palava-client 2.2.0 → 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 +10 -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 -1607
- package/palava.min.js +0 -24
- package/uglifier_options.json +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 3.0.0
|
|
4
|
+
|
|
5
|
+
* Use modern coffee/js modules
|
|
6
|
+
* Add support for WebRTC renegotiation
|
|
7
|
+
* Add support for request local audio/video after the connection is established
|
|
8
|
+
|
|
9
|
+
## 2.2.1
|
|
10
|
+
|
|
11
|
+
* Only catch parsing-related errors with "invalid_format" error
|
|
12
|
+
|
|
3
13
|
## 2.2.0
|
|
4
14
|
|
|
5
15
|
* Add support for TURN relays via signaltower
|
package/README.md
CHANGED
|
@@ -39,7 +39,7 @@ Use the [yarn link](https://classic.yarnpkg.com/en/docs/cli/link/) feature:
|
|
|
39
39
|
### Compile latest source
|
|
40
40
|
|
|
41
41
|
- Make sure you have Ruby and Bundler installed (and have run `$ bundle install` once)
|
|
42
|
-
- `$ rake
|
|
42
|
+
- `$ rake bundle`
|
|
43
43
|
- Rebuild palava-web, for example, by restarting the yarn dev server
|
|
44
44
|
|
|
45
45
|
## Credits
|
package/dist/browser.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// Generated by CoffeeScript 2.7.0
|
|
2
|
+
import adapter from 'webrtc-adapter';
|
|
3
|
+
|
|
4
|
+
// Checks whether the browser is a Firefox
|
|
5
|
+
|
|
6
|
+
// @return [Boolean] `true` if Firefox
|
|
7
|
+
|
|
8
|
+
export var isMozilla = function() {
|
|
9
|
+
return adapter.browserDetails.browser === 'firefox';
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// Checks whether the browser is a Chrome/Chromium
|
|
13
|
+
|
|
14
|
+
// @return [Boolean] `true` if Chrome
|
|
15
|
+
|
|
16
|
+
export var isChrome = function() {
|
|
17
|
+
return adapter.browserDetails.browser === 'chrome';
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// Checks which browser is used
|
|
21
|
+
|
|
22
|
+
// @return [String] A well defined id of the browser (firefox, chrome, safari, or unknown)
|
|
23
|
+
|
|
24
|
+
export var getUserAgent = function() {
|
|
25
|
+
return adapter.browserDetails.browser;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Checks which browser is used
|
|
29
|
+
|
|
30
|
+
// @return [Integer] The user agent version
|
|
31
|
+
|
|
32
|
+
export var getUserAgentVersion = function() {
|
|
33
|
+
return adapter.browserDetails.version;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// Checks whether the WebRTC support of the browser should be compatible with palava
|
|
37
|
+
|
|
38
|
+
// Please note: The test requires network connectivity
|
|
39
|
+
|
|
40
|
+
// @return [Boolean] `true` if the browser is supported by palava
|
|
41
|
+
|
|
42
|
+
export var checkForWebrtcError = function() {
|
|
43
|
+
var e;
|
|
44
|
+
try {
|
|
45
|
+
new window.RTCPeerConnection({
|
|
46
|
+
iceServers: []
|
|
47
|
+
});
|
|
48
|
+
} catch (error) {
|
|
49
|
+
e = error;
|
|
50
|
+
return e;
|
|
51
|
+
}
|
|
52
|
+
return !(window.RTCPeerConnection && window.RTCIceCandidate && window.RTCSessionDescription && navigator.mediaDevices && navigator.mediaDevices.getUserMedia);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// Get WebRTC constraints argument
|
|
56
|
+
|
|
57
|
+
// @return [Object] Appropriate constraints for WebRTC
|
|
58
|
+
|
|
59
|
+
export var getConstraints = function() {
|
|
60
|
+
return {
|
|
61
|
+
optional: [],
|
|
62
|
+
mandatory: {
|
|
63
|
+
OfferToReceiveAudio: true,
|
|
64
|
+
OfferToReceiveVideo: true
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// Get WebRTC PeerConnection options
|
|
70
|
+
|
|
71
|
+
// @return [Object] Appropriate options for the PeerConnection
|
|
72
|
+
|
|
73
|
+
export var getPeerConnectionOptions = function() {
|
|
74
|
+
if (isChrome()) {
|
|
75
|
+
return {
|
|
76
|
+
optional: [
|
|
77
|
+
{
|
|
78
|
+
DtlsSrtpKeyAgreement: true
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
};
|
|
82
|
+
} else {
|
|
83
|
+
return {};
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// Attaches a media stream to a DOM element
|
|
88
|
+
|
|
89
|
+
// @param element [DOM Element] The element to attach the stream to
|
|
90
|
+
// @param stream [MediaStream] The stream to attach
|
|
91
|
+
|
|
92
|
+
export var attachMediaStream = function(element, stream) {
|
|
93
|
+
if (stream) {
|
|
94
|
+
return element.srcObject = stream;
|
|
95
|
+
} else {
|
|
96
|
+
element.pause();
|
|
97
|
+
return element.srcObject = null;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// Attaches a peer's stream to a DOM element
|
|
102
|
+
|
|
103
|
+
// @param element [DOM Element] The element to attach the stream to
|
|
104
|
+
// @param peer [Peer] The peer whose stream to attach
|
|
105
|
+
|
|
106
|
+
export var attachPeer = function(element, peer) {
|
|
107
|
+
var attach;
|
|
108
|
+
attach = function() {
|
|
109
|
+
attachMediaStream(element, peer.getStream());
|
|
110
|
+
if (peer.isLocal()) {
|
|
111
|
+
element.setAttribute('muted', true);
|
|
112
|
+
}
|
|
113
|
+
return element.play();
|
|
114
|
+
};
|
|
115
|
+
if (peer.getStream()) {
|
|
116
|
+
return attach();
|
|
117
|
+
} else {
|
|
118
|
+
return peer.on('stream_ready', function() {
|
|
119
|
+
return attach();
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// Generated by CoffeeScript 2.7.0
|
|
2
|
+
import EventEmitter from 'wolfy87-eventemitter';
|
|
3
|
+
|
|
4
|
+
export var DataChannel = (function() {
|
|
5
|
+
class DataChannel extends EventEmitter {
|
|
6
|
+
constructor(channel) {
|
|
7
|
+
super();
|
|
8
|
+
this.channel = channel;
|
|
9
|
+
this.channel.onmessage = (event) => {
|
|
10
|
+
return this.emit('message', event.data);
|
|
11
|
+
};
|
|
12
|
+
this.channel.onclose = () => {
|
|
13
|
+
return this.emit('close');
|
|
14
|
+
};
|
|
15
|
+
this.channel.onerror = (e) => {
|
|
16
|
+
return this.emit('error', e);
|
|
17
|
+
};
|
|
18
|
+
this.sendBuffer = [];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
send(data, cb) {
|
|
22
|
+
this.sendBuffer.push([data, cb]);
|
|
23
|
+
if (this.sendBuffer.length === 1) {
|
|
24
|
+
return this.actualSend();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
actualSend() {
|
|
29
|
+
var cb, data, e;
|
|
30
|
+
if (this.channel.readyState !== 'open') {
|
|
31
|
+
console.log("Not sending when not open!");
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
while (this.sendBuffer.length) {
|
|
35
|
+
if (this.channel.bufferedAmount > this.MAX_BUFFER) {
|
|
36
|
+
setTimeout(this.actualSend.bind(this), 1);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
[data, cb] = this.sendBuffer[0];
|
|
40
|
+
try {
|
|
41
|
+
this.channel.send(data);
|
|
42
|
+
} catch (error) {
|
|
43
|
+
e = error;
|
|
44
|
+
setTimeout(this.actualSend.bind(this), 1);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
if (typeof cb === "function") {
|
|
49
|
+
cb();
|
|
50
|
+
}
|
|
51
|
+
} catch (error) {
|
|
52
|
+
e = error;
|
|
53
|
+
// TODO: find a better way to tell the user ...
|
|
54
|
+
console.log('Exception in write callback:', e);
|
|
55
|
+
}
|
|
56
|
+
this.sendBuffer.shift();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
DataChannel.prototype.MAX_BUFFER = 1024 * 1024;
|
|
63
|
+
|
|
64
|
+
return DataChannel;
|
|
65
|
+
|
|
66
|
+
}).call(this);
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// Generated by CoffeeScript 2.7.0
|
|
2
|
+
// Distributor supports exchanging direct messages with peers through a channel.
|
|
3
|
+
// The incoming messages are filtered and outgoing messages are are sent within
|
|
4
|
+
// appropriate `send_to_peer` messages.
|
|
5
|
+
|
|
6
|
+
export var Distributor = class Distributor {
|
|
7
|
+
// @param channel [palava.Channel] The channel to connect through
|
|
8
|
+
// @param peerId [String] The id of the peer to connect to or `null` for global messages
|
|
9
|
+
|
|
10
|
+
constructor(channel, peerId = null) {
|
|
11
|
+
// Adds a handler to the Distributor
|
|
12
|
+
|
|
13
|
+
// @example
|
|
14
|
+
// distributor.on 'peer_left', (msg) => console.log "peer left!"
|
|
15
|
+
|
|
16
|
+
// @param event [String] Event id on which the handler is called
|
|
17
|
+
// @param handler [function] This function is called when the event is received
|
|
18
|
+
|
|
19
|
+
this.on = this.on.bind(this);
|
|
20
|
+
// Sends a message through the Distributor
|
|
21
|
+
|
|
22
|
+
// @param msg [Object] The message to send through the distributor
|
|
23
|
+
|
|
24
|
+
this.send = this.send.bind(this);
|
|
25
|
+
this.channel = channel;
|
|
26
|
+
this.peerId = peerId;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
on(event, handler) {
|
|
30
|
+
return this.channel.on('message', (msg) => {
|
|
31
|
+
if (this.peerId) {
|
|
32
|
+
if (msg.sender_id === this.peerId && event === msg.event) {
|
|
33
|
+
return handler(msg);
|
|
34
|
+
}
|
|
35
|
+
} else {
|
|
36
|
+
if (!msg.sender_id && event === msg.event) {
|
|
37
|
+
return handler(msg);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
send(msg) {
|
|
44
|
+
var payload;
|
|
45
|
+
if (this.peerId) {
|
|
46
|
+
payload = {
|
|
47
|
+
event: 'send_to_peer',
|
|
48
|
+
peer_id: this.peerId,
|
|
49
|
+
data: msg
|
|
50
|
+
};
|
|
51
|
+
} else {
|
|
52
|
+
payload = msg;
|
|
53
|
+
}
|
|
54
|
+
return this.channel.send(payload);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
};
|
package/dist/gum.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
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
|
+
export var Gum = class Gum extends EventEmitter {
|
|
7
|
+
constructor(config) {
|
|
8
|
+
super();
|
|
9
|
+
this.changeConfig = this.changeConfig.bind(this);
|
|
10
|
+
this.requestStream = this.requestStream.bind(this);
|
|
11
|
+
this.getStream = this.getStream.bind(this);
|
|
12
|
+
this.releaseStream = this.releaseStream.bind(this);
|
|
13
|
+
this.config = config || {
|
|
14
|
+
video: true,
|
|
15
|
+
audio: true
|
|
16
|
+
};
|
|
17
|
+
this.stream = null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
changeConfig(config) {
|
|
21
|
+
boundMethodCheck(this, Gum);
|
|
22
|
+
this.config = config;
|
|
23
|
+
this.releaseStream();
|
|
24
|
+
return this.requestStream();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
requestStream() {
|
|
28
|
+
boundMethodCheck(this, Gum);
|
|
29
|
+
return navigator.mediaDevices.getUserMedia(this.config).then((stream) => {
|
|
30
|
+
this.stream = stream;
|
|
31
|
+
return this.emit('stream_ready', stream);
|
|
32
|
+
}).catch((error) => {
|
|
33
|
+
return this.emit('stream_error', error);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
getStream() {
|
|
38
|
+
boundMethodCheck(this, Gum);
|
|
39
|
+
return this.stream;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
releaseStream() {
|
|
43
|
+
boundMethodCheck(this, Gum);
|
|
44
|
+
if (this.stream) {
|
|
45
|
+
this.stream.getAudioTracks().forEach((track) => {
|
|
46
|
+
return track.stop();
|
|
47
|
+
});
|
|
48
|
+
this.stream.getVideoTracks().forEach((track) => {
|
|
49
|
+
return track.stop();
|
|
50
|
+
});
|
|
51
|
+
this.stream = null;
|
|
52
|
+
this.emit('stream_released', this);
|
|
53
|
+
return true;
|
|
54
|
+
} else {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
};
|
package/dist/identity.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Generated by CoffeeScript 2.7.0
|
|
2
|
+
import {
|
|
3
|
+
Gum
|
|
4
|
+
} from './gum.js';
|
|
5
|
+
|
|
6
|
+
export var Identity = class Identity {
|
|
7
|
+
constructor(o) {
|
|
8
|
+
this.getName = this.getName.bind(this);
|
|
9
|
+
this.getStatus = this.getStatus.bind(this);
|
|
10
|
+
this.userMediaConfig = o.userMediaConfig;
|
|
11
|
+
this.status = o.status || {};
|
|
12
|
+
this.status.name = o.name;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
newUserMedia() {
|
|
16
|
+
return new Gum(this.userMediaConfig);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
getName() {
|
|
20
|
+
return this.name;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
getStatus() {
|
|
24
|
+
return this.status;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// Generated by CoffeeScript 2.7.0
|
|
2
|
+
import * as browser from './browser.js';
|
|
3
|
+
|
|
4
|
+
export {
|
|
5
|
+
browser
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export {
|
|
9
|
+
Gum
|
|
10
|
+
} from './gum.js';
|
|
11
|
+
|
|
12
|
+
export {
|
|
13
|
+
Identity
|
|
14
|
+
} from './identity.js';
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
Peer
|
|
18
|
+
} from './peer.js';
|
|
19
|
+
|
|
20
|
+
export {
|
|
21
|
+
LocalPeer
|
|
22
|
+
} from './local_peer.js';
|
|
23
|
+
|
|
24
|
+
export {
|
|
25
|
+
RemotePeer
|
|
26
|
+
} from './remote_peer.js';
|
|
27
|
+
|
|
28
|
+
export {
|
|
29
|
+
Room
|
|
30
|
+
} from './room.js';
|
|
31
|
+
|
|
32
|
+
export {
|
|
33
|
+
Session
|
|
34
|
+
} from './session.js';
|
|
35
|
+
|
|
36
|
+
export {
|
|
37
|
+
WebSocketChannel
|
|
38
|
+
} from './web_socket_channel.js';
|
|
39
|
+
|
|
40
|
+
export {
|
|
41
|
+
Distributor
|
|
42
|
+
} from './distributor.js';
|
|
43
|
+
|
|
44
|
+
export {
|
|
45
|
+
DataChannel
|
|
46
|
+
} from './data_channel.js';
|
|
47
|
+
|
|
48
|
+
// Version info
|
|
49
|
+
export var PROTOCOL_NAME = 'palava';
|
|
50
|
+
|
|
51
|
+
export var PROTOCOL_VERSION = '1.0.0';
|
|
52
|
+
|
|
53
|
+
export var LIB_VERSION = '3.0.0';
|
|
@@ -0,0 +1,220 @@
|
|
|
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 * as browser from './browser.js';
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
Peer
|
|
8
|
+
} from './peer.js';
|
|
9
|
+
|
|
10
|
+
// A specialized peer representing the local user in the conference
|
|
11
|
+
export var LocalPeer = class LocalPeer extends Peer {
|
|
12
|
+
// @param id [String] Unique ID of the local peer in the conference
|
|
13
|
+
// @param status [Object] An object containing state which is exchanged through the palava machine (see `palava.Peer` for more informations)
|
|
14
|
+
// @param room [palava.Room] The room in which the peer is present
|
|
15
|
+
constructor(id, status, room) {
|
|
16
|
+
super(id, status);
|
|
17
|
+
// Initializes the events based on the userMedia
|
|
18
|
+
|
|
19
|
+
// @nodoc
|
|
20
|
+
|
|
21
|
+
this.setupUserMedia = this.setupUserMedia.bind(this);
|
|
22
|
+
// Initializes the events based on the room
|
|
23
|
+
|
|
24
|
+
// @nodoc
|
|
25
|
+
|
|
26
|
+
this.setupRoom = this.setupRoom.bind(this);
|
|
27
|
+
// Returns the local stream
|
|
28
|
+
|
|
29
|
+
// @return [MediaStream] The local stream as defined by the WebRTC API
|
|
30
|
+
|
|
31
|
+
this.getStream = this.getStream.bind(this);
|
|
32
|
+
// Updates the status of the local peer. The status is extended or updated with the given items.
|
|
33
|
+
|
|
34
|
+
// @param status [Object] Object containing the new items
|
|
35
|
+
|
|
36
|
+
this.updateStatus = this.updateStatus.bind(this);
|
|
37
|
+
// Remove video track and emit event for renegotiation
|
|
38
|
+
|
|
39
|
+
this.disableVideo = this.disableVideo.bind(this);
|
|
40
|
+
// Remove audio track and emit event for renegotiation
|
|
41
|
+
|
|
42
|
+
this.disableAudio = this.disableAudio.bind(this);
|
|
43
|
+
// Request video from getUserMedia and add it to the local stream
|
|
44
|
+
// Emits 'video_added' event which remote peers listen to for adding the track to their connections
|
|
45
|
+
|
|
46
|
+
// @param constraints [Object] Video constraints for getUserMedia (optional, defaults to true)
|
|
47
|
+
// @return [Promise] Resolves with the video track when added, rejects on error
|
|
48
|
+
|
|
49
|
+
this.requestVideo = this.requestVideo.bind(this);
|
|
50
|
+
// Request audio from getUserMedia and add it to the local stream
|
|
51
|
+
// Emits 'audio_added' event which remote peers listen to for adding the track to their connections
|
|
52
|
+
|
|
53
|
+
// @param constraints [Object] Audio constraints for getUserMedia (optional, defaults to true)
|
|
54
|
+
// @return [Promise] Resolves with the audio track when added, rejects on error
|
|
55
|
+
|
|
56
|
+
this.requestAudio = this.requestAudio.bind(this);
|
|
57
|
+
// Leave the room
|
|
58
|
+
this.leave = this.leave.bind(this);
|
|
59
|
+
this.muted = true;
|
|
60
|
+
this.local = true;
|
|
61
|
+
this.room = room;
|
|
62
|
+
this.userMedia = room.userMedia;
|
|
63
|
+
this.setupRoom();
|
|
64
|
+
this.setupUserMedia();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
setupUserMedia() {
|
|
68
|
+
boundMethodCheck(this, LocalPeer);
|
|
69
|
+
this.userMedia.on('stream_released', () => {
|
|
70
|
+
this.ready = false;
|
|
71
|
+
return this.emit('stream_removed');
|
|
72
|
+
});
|
|
73
|
+
this.userMedia.on('stream_ready', (e) => {
|
|
74
|
+
this.ready = true;
|
|
75
|
+
return this.emit('stream_ready', e);
|
|
76
|
+
});
|
|
77
|
+
this.userMedia.on('stream_error', (e) => {
|
|
78
|
+
return this.emit('stream_error', e);
|
|
79
|
+
});
|
|
80
|
+
if (this.getStream()) {
|
|
81
|
+
this.ready = true;
|
|
82
|
+
return this.emit('stream_ready');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
setupRoom() {
|
|
87
|
+
boundMethodCheck(this, LocalPeer);
|
|
88
|
+
this.room.peers[this.id] = this.room.localPeer = this;
|
|
89
|
+
this.on('update', () => {
|
|
90
|
+
return this.room.emit('peer_update', this);
|
|
91
|
+
});
|
|
92
|
+
this.on('stream_ready', () => {
|
|
93
|
+
return this.room.emit('peer_stream_ready', this);
|
|
94
|
+
});
|
|
95
|
+
return this.on('stream_removed', () => {
|
|
96
|
+
return this.room.emit('peer_stream_removed', this);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
getStream() {
|
|
101
|
+
boundMethodCheck(this, LocalPeer);
|
|
102
|
+
return this.userMedia.getStream();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
updateStatus(status) {
|
|
106
|
+
var base, key;
|
|
107
|
+
boundMethodCheck(this, LocalPeer);
|
|
108
|
+
if (!status || !(status instanceof Object) || Object.keys(status).length === 0) {
|
|
109
|
+
return status;
|
|
110
|
+
}
|
|
111
|
+
for (key in status) {
|
|
112
|
+
this.status[key] = status[key];
|
|
113
|
+
}
|
|
114
|
+
(base = this.status).user_agent || (base.user_agent = browser.getUserAgent());
|
|
115
|
+
this.room.channel.send({
|
|
116
|
+
event: 'update_status',
|
|
117
|
+
status: this.status
|
|
118
|
+
});
|
|
119
|
+
return this.status;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
disableVideo() {
|
|
123
|
+
var i, len, ref, results, stream, track;
|
|
124
|
+
boundMethodCheck(this, LocalPeer);
|
|
125
|
+
stream = this.getStream();
|
|
126
|
+
if (!stream) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
ref = stream.getVideoTracks();
|
|
130
|
+
results = [];
|
|
131
|
+
for (i = 0, len = ref.length; i < len; i++) {
|
|
132
|
+
track = ref[i];
|
|
133
|
+
track.stop();
|
|
134
|
+
stream.removeTrack(track);
|
|
135
|
+
results.push(this.emit('video_removed', track, stream));
|
|
136
|
+
}
|
|
137
|
+
return results;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
disableAudio() {
|
|
141
|
+
var i, len, ref, results, stream, track;
|
|
142
|
+
boundMethodCheck(this, LocalPeer);
|
|
143
|
+
stream = this.getStream();
|
|
144
|
+
if (!stream) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
ref = stream.getAudioTracks();
|
|
148
|
+
results = [];
|
|
149
|
+
for (i = 0, len = ref.length; i < len; i++) {
|
|
150
|
+
track = ref[i];
|
|
151
|
+
track.stop();
|
|
152
|
+
stream.removeTrack(track);
|
|
153
|
+
results.push(this.emit('audio_removed', track, stream));
|
|
154
|
+
}
|
|
155
|
+
return results;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
requestVideo(constraints = true) {
|
|
159
|
+
boundMethodCheck(this, LocalPeer);
|
|
160
|
+
if (!this.getStream()) {
|
|
161
|
+
return Promise.reject(new Error('No stream available'));
|
|
162
|
+
}
|
|
163
|
+
if (this.hasVideo()) {
|
|
164
|
+
return Promise.resolve(this.getStream().getVideoTracks()[0]);
|
|
165
|
+
}
|
|
166
|
+
return navigator.mediaDevices.getUserMedia({
|
|
167
|
+
video: constraints,
|
|
168
|
+
audio: false
|
|
169
|
+
}).then((stream) => {
|
|
170
|
+
var videoTrack;
|
|
171
|
+
videoTrack = stream.getVideoTracks()[0];
|
|
172
|
+
if (!videoTrack) {
|
|
173
|
+
return Promise.reject(new Error('No video track received'));
|
|
174
|
+
}
|
|
175
|
+
// Add track to our local stream
|
|
176
|
+
this.getStream().addTrack(videoTrack);
|
|
177
|
+
// Emit event - remote peers will listen and add the track to their connections
|
|
178
|
+
this.emit('video_added', videoTrack, this.getStream());
|
|
179
|
+
return videoTrack;
|
|
180
|
+
}).catch((error) => {
|
|
181
|
+
this.emit('video_error', error);
|
|
182
|
+
return Promise.reject(error);
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
requestAudio(constraints = true) {
|
|
187
|
+
boundMethodCheck(this, LocalPeer);
|
|
188
|
+
if (!this.getStream()) {
|
|
189
|
+
return Promise.reject(new Error('No stream available'));
|
|
190
|
+
}
|
|
191
|
+
if (this.hasAudio()) {
|
|
192
|
+
return Promise.resolve(this.getStream().getAudioTracks()[0]);
|
|
193
|
+
}
|
|
194
|
+
return navigator.mediaDevices.getUserMedia({
|
|
195
|
+
video: false,
|
|
196
|
+
audio: constraints
|
|
197
|
+
}).then((stream) => {
|
|
198
|
+
var audioTrack;
|
|
199
|
+
audioTrack = stream.getAudioTracks()[0];
|
|
200
|
+
if (!audioTrack) {
|
|
201
|
+
return Promise.reject(new Error('No audio track received'));
|
|
202
|
+
}
|
|
203
|
+
// Add track to our local stream
|
|
204
|
+
this.getStream().addTrack(audioTrack);
|
|
205
|
+
// Emit event - remote peers will listen and add the track to their connections
|
|
206
|
+
this.emit('audio_added', audioTrack, this.getStream());
|
|
207
|
+
return audioTrack;
|
|
208
|
+
}).catch((error) => {
|
|
209
|
+
this.emit('audio_error', error);
|
|
210
|
+
return Promise.reject(error);
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
leave() {
|
|
215
|
+
boundMethodCheck(this, LocalPeer);
|
|
216
|
+
this.ready = false;
|
|
217
|
+
return this.emit('left');
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
};
|