palava-client 2.2.1 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/README.md +1 -1
- package/dist/browser.js +122 -0
- package/dist/data_channel.js +66 -0
- package/dist/distributor.js +57 -0
- package/dist/gum.js +59 -0
- package/dist/identity.js +27 -0
- package/dist/index.js +53 -0
- package/dist/local_peer.js +220 -0
- package/dist/peer.js +150 -0
- package/dist/remote_peer.js +484 -0
- package/dist/room.js +213 -0
- package/dist/session.js +319 -0
- package/dist/web_socket_channel.js +132 -0
- package/package.json +12 -4
- package/Gemfile +0 -8
- package/Gemfile.lock +0 -32
- package/Rakefile +0 -47
- package/bower.json +0 -25
- package/palava.bundle.js +0 -3550
- package/palava.js +0 -1608
- package/palava.min.js +0 -24
- package/uglifier_options.json +0 -1
package/dist/room.js
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
// Generated by CoffeeScript 2.7.0
|
|
2
|
+
var boundMethodCheck = function(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new Error('Bound instance method accessed before binding'); } };
|
|
3
|
+
|
|
4
|
+
import EventEmitter from 'wolfy87-eventemitter';
|
|
5
|
+
|
|
6
|
+
import * as browser from './browser.js';
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
Distributor
|
|
10
|
+
} from './distributor.js';
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
LocalPeer
|
|
14
|
+
} from './local_peer.js';
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
RemotePeer
|
|
18
|
+
} from './remote_peer.js';
|
|
19
|
+
|
|
20
|
+
// A room connecting multiple participants
|
|
21
|
+
|
|
22
|
+
export var Room = class Room extends EventEmitter {
|
|
23
|
+
// @param roomId [String] ID of the room
|
|
24
|
+
// @param channel [Channel] Channel used for communication
|
|
25
|
+
// @param userMedia [UserMedia] UserMedia used for local user
|
|
26
|
+
// @param options [Object] Further objects for the room
|
|
27
|
+
// @option options joinTimeout [Integer] Timeout for joining
|
|
28
|
+
// @option options ownStatus [Object] The status of the local user
|
|
29
|
+
|
|
30
|
+
constructor(roomId, channel, userMedia, options = {}) {
|
|
31
|
+
super();
|
|
32
|
+
// Bind UserMedia events to room events
|
|
33
|
+
|
|
34
|
+
// @nodoc
|
|
35
|
+
|
|
36
|
+
this.setupUserMedia = this.setupUserMedia.bind(this);
|
|
37
|
+
// Set default options
|
|
38
|
+
|
|
39
|
+
// @nodoc
|
|
40
|
+
|
|
41
|
+
this.setupOptions = this.setupOptions.bind(this);
|
|
42
|
+
// Initialize global distributor and messaging
|
|
43
|
+
|
|
44
|
+
// @nodoc
|
|
45
|
+
|
|
46
|
+
this.setupDistributor = this.setupDistributor.bind(this);
|
|
47
|
+
// Join the room
|
|
48
|
+
|
|
49
|
+
// @param status [Object] Status of the local user
|
|
50
|
+
|
|
51
|
+
this.join = this.join.bind(this);
|
|
52
|
+
// Send leave room event to server
|
|
53
|
+
|
|
54
|
+
this.leave = this.leave.bind(this);
|
|
55
|
+
// Makes sure room is closed by disconnecting all peer connections and clearing all timeouts
|
|
56
|
+
|
|
57
|
+
this.destroy = this.destroy.bind(this);
|
|
58
|
+
// Find peer with the given id
|
|
59
|
+
|
|
60
|
+
// @param id [String] id of the searched peer
|
|
61
|
+
|
|
62
|
+
// @return [Peer] The peer with the given id or `undefined`
|
|
63
|
+
|
|
64
|
+
this.getPeerById = this.getPeerById.bind(this);
|
|
65
|
+
// Get local peer
|
|
66
|
+
|
|
67
|
+
// @return [Peer] The local peer
|
|
68
|
+
|
|
69
|
+
this.getLocalPeer = this.getLocalPeer.bind(this);
|
|
70
|
+
// Get remote peers
|
|
71
|
+
|
|
72
|
+
// @return [Array] All peers except the local peer
|
|
73
|
+
|
|
74
|
+
this.getRemotePeers = this.getRemotePeers.bind(this);
|
|
75
|
+
// Get all peers
|
|
76
|
+
|
|
77
|
+
// @return [Array] All peers including the local peer
|
|
78
|
+
|
|
79
|
+
this.getAllPeers = this.getAllPeers.bind(this);
|
|
80
|
+
this.id = roomId;
|
|
81
|
+
this.userMedia = userMedia;
|
|
82
|
+
this.channel = channel;
|
|
83
|
+
this.peers = {};
|
|
84
|
+
this.options = options;
|
|
85
|
+
this.setupUserMedia();
|
|
86
|
+
this.setupDistributor();
|
|
87
|
+
this.setupOptions();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
setupUserMedia() {
|
|
91
|
+
boundMethodCheck(this, Room);
|
|
92
|
+
this.userMedia.on('stream_ready', (stream) => {
|
|
93
|
+
return this.emit('local_stream_ready', stream);
|
|
94
|
+
});
|
|
95
|
+
this.userMedia.on('stream_error', (error) => {
|
|
96
|
+
return this.emit('local_stream_error', error);
|
|
97
|
+
});
|
|
98
|
+
return this.userMedia.on('stream_released', () => {
|
|
99
|
+
return this.emit('local_stream_removed');
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
setupOptions() {
|
|
104
|
+
var base, base1, base2;
|
|
105
|
+
boundMethodCheck(this, Room);
|
|
106
|
+
(base = this.options).joinTimeout || (base.joinTimeout = 1000);
|
|
107
|
+
(base1 = this.options).ownStatus || (base1.ownStatus = {});
|
|
108
|
+
return (base2 = this.options).filterIceCandidateTypes || (base2.filterIceCandidateTypes = []);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
setupDistributor() {
|
|
112
|
+
boundMethodCheck(this, Room);
|
|
113
|
+
this.distributor = new Distributor(this.channel);
|
|
114
|
+
this.distributor.on('joined_room', (msg) => {
|
|
115
|
+
var i, len, newPeer, offers, peer, ref, turnCredentials;
|
|
116
|
+
clearTimeout(this.joinCheckTimeout);
|
|
117
|
+
if (msg.turn_user) {
|
|
118
|
+
turnCredentials = {
|
|
119
|
+
user: msg.turn_user,
|
|
120
|
+
password: msg.turn_password
|
|
121
|
+
};
|
|
122
|
+
} else {
|
|
123
|
+
turnCredentials = null;
|
|
124
|
+
}
|
|
125
|
+
new LocalPeer(msg.own_id, this.options.ownStatus, this);
|
|
126
|
+
ref = msg.peers;
|
|
127
|
+
for (i = 0, len = ref.length; i < len; i++) {
|
|
128
|
+
peer = ref[i];
|
|
129
|
+
offers = !browser.isChrome();
|
|
130
|
+
newPeer = new RemotePeer(peer.peer_id, peer.status, this, offers, turnCredentials);
|
|
131
|
+
}
|
|
132
|
+
return this.emit("joined");
|
|
133
|
+
});
|
|
134
|
+
this.distributor.on('new_peer', (msg) => {
|
|
135
|
+
var newPeer, offers;
|
|
136
|
+
offers = msg.status.user_agent === 'chrome';
|
|
137
|
+
newPeer = new RemotePeer(msg.peer_id, msg.status, this, offers);
|
|
138
|
+
return this.emit('peer_joined', newPeer);
|
|
139
|
+
});
|
|
140
|
+
this.distributor.on('error', (msg) => {
|
|
141
|
+
return this.emit('signaling_error', 'server', msg.description);
|
|
142
|
+
});
|
|
143
|
+
return this.distributor.on('shutdown', (msg) => {
|
|
144
|
+
return this.emit('signaling_shutdown', msg.seconds);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
join(status = {}) {
|
|
149
|
+
var base, i, key, len;
|
|
150
|
+
boundMethodCheck(this, Room);
|
|
151
|
+
this.joinCheckTimeout = setTimeout((() => {
|
|
152
|
+
return this.emit('join_error');
|
|
153
|
+
}), this.options.joinTimeout);
|
|
154
|
+
for (i = 0, len = status.length; i < len; i++) {
|
|
155
|
+
key = status[i];
|
|
156
|
+
this.options.ownStatus[key] = status[key];
|
|
157
|
+
}
|
|
158
|
+
(base = this.options.ownStatus).user_agent || (base.user_agent = browser.getUserAgent());
|
|
159
|
+
return this.distributor.send({
|
|
160
|
+
event: 'join_room',
|
|
161
|
+
room_id: this.id,
|
|
162
|
+
status: this.options.ownStatus
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
leave() {
|
|
167
|
+
boundMethodCheck(this, Room);
|
|
168
|
+
if (this.channel) {
|
|
169
|
+
this.distributor.send({
|
|
170
|
+
event: 'leave_room'
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
return this.emit('left');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
destroy() {
|
|
177
|
+
boundMethodCheck(this, Room);
|
|
178
|
+
this.getRemotePeers().forEach((peer) => {
|
|
179
|
+
return peer.closePeerConnection();
|
|
180
|
+
});
|
|
181
|
+
return clearTimeout(this.joinCheckTimeout);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
getPeerById(id) {
|
|
185
|
+
boundMethodCheck(this, Room);
|
|
186
|
+
return this.peers[id];
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
getLocalPeer() {
|
|
190
|
+
boundMethodCheck(this, Room);
|
|
191
|
+
return this.localPeer;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
getRemotePeers() {
|
|
195
|
+
boundMethodCheck(this, Room);
|
|
196
|
+
return this.getAllPeers(false);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
getAllPeers(allowLocal = true) {
|
|
200
|
+
var id, peer, peers, ref;
|
|
201
|
+
boundMethodCheck(this, Room);
|
|
202
|
+
peers = [];
|
|
203
|
+
ref = this.peers;
|
|
204
|
+
for (id in ref) {
|
|
205
|
+
peer = ref[id];
|
|
206
|
+
if (allowLocal || !peer.local) {
|
|
207
|
+
peers.push(peer);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return peers;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
};
|
package/dist/session.js
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
// Generated by CoffeeScript 2.7.0
|
|
2
|
+
var boundMethodCheck = function(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new Error('Bound instance method accessed before binding'); } };
|
|
3
|
+
|
|
4
|
+
import EventEmitter from 'wolfy87-eventemitter';
|
|
5
|
+
|
|
6
|
+
import * as browser from './browser.js';
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
Gum
|
|
10
|
+
} from './gum.js';
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
Room
|
|
14
|
+
} from './room.js';
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
WebSocketChannel
|
|
18
|
+
} from './web_socket_channel.js';
|
|
19
|
+
|
|
20
|
+
// Session is a wrapper around a concrete room, channel and userMedia
|
|
21
|
+
export var Session = class Session extends EventEmitter {
|
|
22
|
+
// Creates the session object
|
|
23
|
+
|
|
24
|
+
// @param o [Object] See Session#connect for available options
|
|
25
|
+
|
|
26
|
+
constructor(o = {}) {
|
|
27
|
+
super();
|
|
28
|
+
// Initializes the websocket channel, retrieves user media and joins room when stream ready
|
|
29
|
+
|
|
30
|
+
// @param o [Object] Options for the session
|
|
31
|
+
// @option o webSocketAddress [WebSocket] The websocket endpoint to connect to
|
|
32
|
+
// @option o userMediaConfig [Object] getUserMedia constraints
|
|
33
|
+
// @option o stun [String] Address of stun server
|
|
34
|
+
// @option o turn [String] Turn address and credentials
|
|
35
|
+
// @option o joinTimeout [Integer] Milliseconds till joining is canceled by throwing
|
|
36
|
+
// the "join_error" event
|
|
37
|
+
|
|
38
|
+
this.connect = this.connect.bind(this);
|
|
39
|
+
// Reconnect the session
|
|
40
|
+
|
|
41
|
+
this.reconnect = this.reconnect.bind(this);
|
|
42
|
+
// Reset channel and room
|
|
43
|
+
|
|
44
|
+
// @param o [Object] Also release user media
|
|
45
|
+
|
|
46
|
+
this.tearDown = this.tearDown.bind(this);
|
|
47
|
+
// Moves options into inner state
|
|
48
|
+
|
|
49
|
+
// @nodoc
|
|
50
|
+
|
|
51
|
+
this.assignOptions = this.assignOptions.bind(this);
|
|
52
|
+
// Checks whether the inner state of the session is valid. Emits events otherwise
|
|
53
|
+
|
|
54
|
+
// @return [Boolean] `true` if options are correct and webrtc support is given
|
|
55
|
+
|
|
56
|
+
this.checkRequirements = this.checkRequirements.bind(this);
|
|
57
|
+
// Get the channel of the session
|
|
58
|
+
|
|
59
|
+
// @return [Channel] The channel of the session
|
|
60
|
+
|
|
61
|
+
this.getChannel = this.getChannel.bind(this);
|
|
62
|
+
// Get the UserMedia of the session
|
|
63
|
+
|
|
64
|
+
// @return [UserMedia] UserMedia of the session
|
|
65
|
+
|
|
66
|
+
this.getUserMedia = this.getUserMedia.bind(this);
|
|
67
|
+
// Get the room of the session
|
|
68
|
+
|
|
69
|
+
// @return [Room] Room of the session
|
|
70
|
+
|
|
71
|
+
this.getRoom = this.getRoom.bind(this);
|
|
72
|
+
// Build connection to websocket endpont
|
|
73
|
+
|
|
74
|
+
// @return [Room] Room of the session
|
|
75
|
+
|
|
76
|
+
this.createChannel = this.createChannel.bind(this);
|
|
77
|
+
// Maps signals from room to session signals
|
|
78
|
+
|
|
79
|
+
// @nodoc
|
|
80
|
+
|
|
81
|
+
this.createRoom = this.createRoom.bind(this);
|
|
82
|
+
// Destroys the session
|
|
83
|
+
this.destroy = this.destroy.bind(this);
|
|
84
|
+
this.roomOptions = {};
|
|
85
|
+
this.assignOptions(o);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
connect(o) {
|
|
89
|
+
boundMethodCheck(this, Session);
|
|
90
|
+
this.assignOptions(o);
|
|
91
|
+
if (!this.checkRequirements()) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
this.createChannel();
|
|
95
|
+
this.createRoom();
|
|
96
|
+
if (this.userMedia.stream) {
|
|
97
|
+
return this.room.join();
|
|
98
|
+
} else {
|
|
99
|
+
return this.userMedia.requestStream().then(() => {
|
|
100
|
+
return this.room.join();
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
reconnect() {
|
|
106
|
+
boundMethodCheck(this, Session);
|
|
107
|
+
this.emit('session_reconnect');
|
|
108
|
+
this.tearDown();
|
|
109
|
+
this.createChannel();
|
|
110
|
+
this.createRoom();
|
|
111
|
+
return this.room.join();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
tearDown(resetUserMedia = false) {
|
|
115
|
+
var ref, ref1, ref2, ref3, ref4, ref5;
|
|
116
|
+
boundMethodCheck(this, Session);
|
|
117
|
+
if ((ref = this.room) != null) {
|
|
118
|
+
ref.removeAllListeners();
|
|
119
|
+
}
|
|
120
|
+
if ((ref1 = this.channel) != null) {
|
|
121
|
+
ref1.removeAllListeners();
|
|
122
|
+
}
|
|
123
|
+
if ((ref2 = this.channel) != null ? ref2.isConnected() : void 0) {
|
|
124
|
+
if ((ref3 = this.room) != null) {
|
|
125
|
+
ref3.leave();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if ((ref4 = this.channel) != null) {
|
|
129
|
+
ref4.close();
|
|
130
|
+
}
|
|
131
|
+
this.channel = null;
|
|
132
|
+
if ((ref5 = this.room) != null) {
|
|
133
|
+
ref5.destroy();
|
|
134
|
+
}
|
|
135
|
+
this.room = null;
|
|
136
|
+
if (resetUserMedia && this.userMedia) {
|
|
137
|
+
return this.userMedia.releaseStream();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
assignOptions(o) {
|
|
142
|
+
boundMethodCheck(this, Session);
|
|
143
|
+
if (o.roomId) {
|
|
144
|
+
this.roomId = o.roomId;
|
|
145
|
+
}
|
|
146
|
+
if (o.webSocketAddress) {
|
|
147
|
+
this.webSocketAddress = o.webSocketAddress;
|
|
148
|
+
}
|
|
149
|
+
if (o.identity) {
|
|
150
|
+
this.userMedia = o.identity.newUserMedia();
|
|
151
|
+
this.roomOptions.ownStatus = o.identity.getStatus();
|
|
152
|
+
}
|
|
153
|
+
if (o.userMediaConfig) {
|
|
154
|
+
this.userMedia = new Gum(o.userMediaConfig);
|
|
155
|
+
}
|
|
156
|
+
if (o.dataChannels) {
|
|
157
|
+
this.roomOptions.dataChannels = o.dataChannels;
|
|
158
|
+
}
|
|
159
|
+
if (o.stun) {
|
|
160
|
+
this.roomOptions.stun = o.stun;
|
|
161
|
+
}
|
|
162
|
+
if (o.turnUrls) {
|
|
163
|
+
this.roomOptions.turnUrls = o.turnUrls;
|
|
164
|
+
}
|
|
165
|
+
if (o.joinTimeout) {
|
|
166
|
+
this.roomOptions.joinTimeout = o.joinTimeout;
|
|
167
|
+
}
|
|
168
|
+
if (o.filterIceCandidateTypes) {
|
|
169
|
+
return this.roomOptions.filterIceCandidateTypes = o.filterIceCandidateTypes;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
checkRequirements() {
|
|
174
|
+
var e;
|
|
175
|
+
boundMethodCheck(this, Session);
|
|
176
|
+
if (!this.webSocketAddress) {
|
|
177
|
+
this.emit('argument_error', 'no web socket address given');
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
if (!this.userMedia) {
|
|
181
|
+
this.emit('argument_error', 'no user media given');
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
if (!this.roomId) {
|
|
185
|
+
this.emit('argument_error', 'no room id given');
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
if (!this.roomOptions.stun) {
|
|
189
|
+
this.emit('argument_error', 'no stun server given');
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
if (this.roomOptions.turnUrls && !Array.isArray(this.roomOptions.turnUrls)) {
|
|
193
|
+
this.emit('argument_error', 'turnUrls must be an array');
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
if (!navigator.onLine) {
|
|
197
|
+
this.emit('signaling_not_reachable');
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
if (e = browser.checkForWebrtcError()) {
|
|
201
|
+
this.emit('webrtc_no_support', 'WebRTC is not supported by your browser', e);
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
getChannel() {
|
|
208
|
+
boundMethodCheck(this, Session);
|
|
209
|
+
return this.channel;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
getUserMedia() {
|
|
213
|
+
boundMethodCheck(this, Session);
|
|
214
|
+
return this.userMedia;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
getRoom() {
|
|
218
|
+
boundMethodCheck(this, Session);
|
|
219
|
+
return this.room;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
createChannel() {
|
|
223
|
+
boundMethodCheck(this, Session);
|
|
224
|
+
this.channel = new WebSocketChannel(this.webSocketAddress);
|
|
225
|
+
this.channel.on('open', () => {
|
|
226
|
+
return this.emit('signaling_open');
|
|
227
|
+
});
|
|
228
|
+
this.channel.on('error', (t, e) => {
|
|
229
|
+
return this.emit('signaling_error', t, e);
|
|
230
|
+
});
|
|
231
|
+
this.channel.on('close', (e) => {
|
|
232
|
+
return this.emit('signaling_close', e);
|
|
233
|
+
});
|
|
234
|
+
return this.channel.on('not_reachable', () => {
|
|
235
|
+
return this.emit('signaling_not_reachable');
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
createRoom() { // TODO move some more stuff away from the room? eg signaling
|
|
240
|
+
boundMethodCheck(this, Session);
|
|
241
|
+
this.room = new Room(this.roomId, this.channel, this.userMedia, this.roomOptions);
|
|
242
|
+
this.room.on('local_stream_ready', (s) => {
|
|
243
|
+
return this.emit('local_stream_ready', s);
|
|
244
|
+
});
|
|
245
|
+
this.room.on('local_stream_error', (e) => {
|
|
246
|
+
return this.emit('local_stream_error', e);
|
|
247
|
+
});
|
|
248
|
+
this.room.on('local_stream_removed', () => {
|
|
249
|
+
return this.emit('local_stream_removed');
|
|
250
|
+
});
|
|
251
|
+
this.room.on('join_error', () => {
|
|
252
|
+
this.tearDown(true);
|
|
253
|
+
return this.emit('room_join_error', this.room);
|
|
254
|
+
});
|
|
255
|
+
this.room.on('full', () => {
|
|
256
|
+
return this.emit('room_full', this.room);
|
|
257
|
+
});
|
|
258
|
+
this.room.on('joined', () => {
|
|
259
|
+
return this.emit('room_joined', this.room);
|
|
260
|
+
});
|
|
261
|
+
this.room.on('left', () => {
|
|
262
|
+
return this.emit('room_left', this.room);
|
|
263
|
+
});
|
|
264
|
+
this.room.on('peer_joined', (p) => {
|
|
265
|
+
return this.emit('peer_joined', p);
|
|
266
|
+
});
|
|
267
|
+
this.room.on('peer_offer', (p) => {
|
|
268
|
+
return this.emit('peer_offer', p);
|
|
269
|
+
});
|
|
270
|
+
this.room.on('peer_answer', (p) => {
|
|
271
|
+
return this.emit('peer_answer', p);
|
|
272
|
+
});
|
|
273
|
+
this.room.on('peer_update', (p) => {
|
|
274
|
+
return this.emit('peer_update', p);
|
|
275
|
+
});
|
|
276
|
+
this.room.on('peer_stream_ready', (p) => {
|
|
277
|
+
return this.emit('peer_stream_ready', p);
|
|
278
|
+
});
|
|
279
|
+
this.room.on('peer_stream_removed', (p) => {
|
|
280
|
+
return this.emit('peer_stream_removed', p);
|
|
281
|
+
});
|
|
282
|
+
this.room.on('peer_connection_pending', (p) => {
|
|
283
|
+
return this.emit('peer_connection_pending', p);
|
|
284
|
+
});
|
|
285
|
+
this.room.on('peer_connection_established', (p) => {
|
|
286
|
+
return this.emit('peer_connection_established', p);
|
|
287
|
+
});
|
|
288
|
+
this.room.on('peer_connection_failed', (p) => {
|
|
289
|
+
return this.emit('peer_connection_failed', p);
|
|
290
|
+
});
|
|
291
|
+
this.room.on('peer_connection_disconnected', (p) => {
|
|
292
|
+
return this.emit('peer_connection_disconnected', p);
|
|
293
|
+
});
|
|
294
|
+
this.room.on('peer_connection_closed', (p) => {
|
|
295
|
+
return this.emit('peer_connection_closed', p);
|
|
296
|
+
});
|
|
297
|
+
this.room.on('peer_left', (p) => {
|
|
298
|
+
return this.emit('peer_left', p);
|
|
299
|
+
});
|
|
300
|
+
this.room.on('peer_channel_ready', (p, n, c) => {
|
|
301
|
+
return this.emit('peer_channel_ready', p, n, c);
|
|
302
|
+
});
|
|
303
|
+
this.room.on('signaling_shutdown', (p) => {
|
|
304
|
+
return this.emit('signaling_shutdown', p);
|
|
305
|
+
});
|
|
306
|
+
this.room.on('signaling_error', (t, e) => {
|
|
307
|
+
return this.emit('signaling_error', t, e);
|
|
308
|
+
});
|
|
309
|
+
return true;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
destroy() {
|
|
313
|
+
boundMethodCheck(this, Session);
|
|
314
|
+
this.emit('session_before_destroy');
|
|
315
|
+
this.tearDown(true);
|
|
316
|
+
return this.emit('session_after_destroy');
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
// Generated by CoffeeScript 2.7.0
|
|
2
|
+
var boundMethodCheck = function(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new Error('Bound instance method accessed before binding'); } };
|
|
3
|
+
|
|
4
|
+
import EventEmitter from 'wolfy87-eventemitter';
|
|
5
|
+
|
|
6
|
+
// Channel implementation using websockets
|
|
7
|
+
|
|
8
|
+
// Events: open -> (), message -> (msg), error -> (), close -> ()
|
|
9
|
+
|
|
10
|
+
export var WebSocketChannel = class WebSocketChannel extends EventEmitter {
|
|
11
|
+
// @param address [String] Address of the websocket. Should start with `ws://` for web sockets or `wss://` for secure web sockets.
|
|
12
|
+
constructor(address, retries = 2) {
|
|
13
|
+
super();
|
|
14
|
+
// Returns true if socket is in a good state
|
|
15
|
+
this.isConnected = this.isConnected.bind(this);
|
|
16
|
+
this.sendDeliverOnConnectMessages = this.sendDeliverOnConnectMessages.bind(this);
|
|
17
|
+
// Connects websocket events with the events of this object
|
|
18
|
+
|
|
19
|
+
// @nodoc
|
|
20
|
+
|
|
21
|
+
this.setupWebsocket = this.setupWebsocket.bind(this);
|
|
22
|
+
this.startClientPings = this.startClientPings.bind(this);
|
|
23
|
+
// Sends the given data through the websocket
|
|
24
|
+
|
|
25
|
+
// @param data [Object] Object to send through the channel
|
|
26
|
+
|
|
27
|
+
this.send = this.send.bind(this);
|
|
28
|
+
// Closes the websocket
|
|
29
|
+
|
|
30
|
+
this.close = this.close.bind(this);
|
|
31
|
+
this.address = address;
|
|
32
|
+
this.retries = retries;
|
|
33
|
+
this.messagesToDeliverOnConnect = [];
|
|
34
|
+
this.setupWebsocket();
|
|
35
|
+
this.startClientPings();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
isConnected() {
|
|
39
|
+
var ref;
|
|
40
|
+
boundMethodCheck(this, WebSocketChannel);
|
|
41
|
+
return ((ref = this.socket) != null ? ref.readyState : void 0) === 1;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
sendDeliverOnConnectMessages() {
|
|
45
|
+
var i, len, msg, ref;
|
|
46
|
+
boundMethodCheck(this, WebSocketChannel);
|
|
47
|
+
ref = this.messagesToDeliverOnConnect;
|
|
48
|
+
for (i = 0, len = ref.length; i < len; i++) {
|
|
49
|
+
msg = ref[i];
|
|
50
|
+
this.socket.send(msg);
|
|
51
|
+
}
|
|
52
|
+
return this.messagesToDeliverOnConnect = [];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
setupWebsocket() {
|
|
56
|
+
boundMethodCheck(this, WebSocketChannel);
|
|
57
|
+
this.socket = new WebSocket(this.address);
|
|
58
|
+
this.socket.onopen = (handshake) => {
|
|
59
|
+
this.retries = 0;
|
|
60
|
+
this.sendDeliverOnConnectMessages();
|
|
61
|
+
return this.emit('open', handshake);
|
|
62
|
+
};
|
|
63
|
+
this.socket.onmessage = (msg) => {
|
|
64
|
+
var error, parsedMsg;
|
|
65
|
+
try {
|
|
66
|
+
parsedMsg = JSON.parse(msg.data);
|
|
67
|
+
} catch (error1) {
|
|
68
|
+
error = error1;
|
|
69
|
+
this.emit('error', 'invalid_format', {
|
|
70
|
+
error: error,
|
|
71
|
+
data: msg.data
|
|
72
|
+
});
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (parsedMsg.event === "pong") {
|
|
76
|
+
return this.outstandingPongs = 0;
|
|
77
|
+
} else {
|
|
78
|
+
return this.emit('message', parsedMsg);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
this.socket.onerror = (msg) => {
|
|
82
|
+
clearInterval(this.pingInterval);
|
|
83
|
+
if (this.retries > 0) {
|
|
84
|
+
this.retries -= 1;
|
|
85
|
+
this.setupWebsocket();
|
|
86
|
+
return this.startClientPings();
|
|
87
|
+
} else {
|
|
88
|
+
return this.emit('error', 'socket', msg);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
return this.socket.onclose = () => {
|
|
92
|
+
clearInterval(this.pingInterval);
|
|
93
|
+
return this.emit('close');
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
startClientPings() {
|
|
98
|
+
boundMethodCheck(this, WebSocketChannel);
|
|
99
|
+
this.outstandingPongs = 0;
|
|
100
|
+
return this.pingInterval = setInterval(() => {
|
|
101
|
+
if (this.outstandingPongs >= 6) {
|
|
102
|
+
clearInterval(this.pingInterval);
|
|
103
|
+
this.socket.close();
|
|
104
|
+
this.emit('error', "missing_pongs");
|
|
105
|
+
}
|
|
106
|
+
this.socket.send(JSON.stringify({
|
|
107
|
+
event: "ping"
|
|
108
|
+
}));
|
|
109
|
+
return this.outstandingPongs += 1;
|
|
110
|
+
}, 5000);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
send(data) {
|
|
114
|
+
boundMethodCheck(this, WebSocketChannel);
|
|
115
|
+
if (this.socket.readyState === 1) { // successful connection
|
|
116
|
+
if (this.messagesToDeliverOnConnect.length !== 0) {
|
|
117
|
+
this.sendDeliverOnConnectMessages();
|
|
118
|
+
}
|
|
119
|
+
return this.socket.send(JSON.stringify(data));
|
|
120
|
+
} else if (this.socket.readyState > 1) { // connection closing or closed
|
|
121
|
+
return this.emit('not_reachable'); // connection still to be established
|
|
122
|
+
} else {
|
|
123
|
+
return this.messagesToDeliverOnConnect.push(JSON.stringify(data));
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
close() {
|
|
128
|
+
boundMethodCheck(this, WebSocketChannel);
|
|
129
|
+
return this.socket.close();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
};
|
package/package.json
CHANGED
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "palava-client",
|
|
3
3
|
"description": "Signaling client for WebRTC video-/audio conferencing using the palava protocol",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "3.0.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "palava e. V.",
|
|
7
7
|
"email": "contact@palava.tv",
|
|
8
8
|
"homepage": "https://palava.tv"
|
|
9
9
|
},
|
|
10
10
|
"license": "LGPL-3.0",
|
|
11
|
+
"type": "module",
|
|
12
|
+
"exports": "./dist/index.js",
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "coffee -c -o dist/ coffee/",
|
|
15
|
+
"watch": "coffee -c -w -o dist/ coffee/"
|
|
16
|
+
},
|
|
11
17
|
"dependencies": {
|
|
12
18
|
"webrtc-adapter": "^7.7.0",
|
|
13
|
-
"wolfy87-eventemitter": "
|
|
19
|
+
"wolfy87-eventemitter": "^5.2.9"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"coffeescript": "^2.7.0"
|
|
14
23
|
},
|
|
15
|
-
"browser": "./palava.js",
|
|
16
24
|
"keywords": [
|
|
17
25
|
"webrtc",
|
|
18
26
|
"websocket",
|
|
@@ -22,6 +30,6 @@
|
|
|
22
30
|
],
|
|
23
31
|
"repository": {
|
|
24
32
|
"type": "git",
|
|
25
|
-
"url": "https://github.com/palavatv/palava-client.git"
|
|
33
|
+
"url": "git+https://github.com/palavatv/palava-client.git"
|
|
26
34
|
}
|
|
27
35
|
}
|