|
|
|
@ -20,15 +20,10 @@
@@ -20,15 +20,10 @@
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
"use strict"; |
|
|
|
|
define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _, AudioContext) { |
|
|
|
|
define(['jquery', 'underscore', 'audiocontext', 'mediastream/dummystream', 'webrtc.adapter'], function($, _, AudioContext, DummyStream) { |
|
|
|
|
|
|
|
|
|
// Create AudioContext singleton, if supported.
|
|
|
|
|
var context = AudioContext ? new AudioContext() : null; |
|
|
|
|
var peerconnections = {}; |
|
|
|
|
|
|
|
|
|
// Disabled for now until browser support matures. If enabled this totally breaks
|
|
|
|
|
// Firefox and Chrome with Firefox interop.
|
|
|
|
|
var enableRenegotiationSupport = false; |
|
|
|
|
|
|
|
|
|
// Converter helpers to convert media constraints to new API.
|
|
|
|
|
var mergeConstraints = function(constraints, k, v, mandatory) { |
|
|
|
@ -124,6 +119,7 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
@@ -124,6 +119,7 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
|
|
|
|
|
} |
|
|
|
|
})(); |
|
|
|
|
|
|
|
|
|
// UserMedia.
|
|
|
|
|
var UserMedia = function(options) { |
|
|
|
|
|
|
|
|
|
this.options = $.extend({}, options); |
|
|
|
@ -131,15 +127,23 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
@@ -131,15 +127,23 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
|
|
|
|
|
|
|
|
|
|
this.localStream = null; |
|
|
|
|
this.started = false; |
|
|
|
|
this.delay = 0; |
|
|
|
|
|
|
|
|
|
this.audioMute = false; |
|
|
|
|
this.videoMute = false; |
|
|
|
|
this.peerconnections = {}; |
|
|
|
|
|
|
|
|
|
// If true, mute/unmute of audio/video creates a new stream which
|
|
|
|
|
// will trigger renegotiation on the peer connection.
|
|
|
|
|
this.renegotiation = options.renegotiation && true; |
|
|
|
|
if (this.renegotiation) { |
|
|
|
|
console.info("User media with renegotiation created ..."); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.audioMute = options.audioMute && true; |
|
|
|
|
this.videoMute = options.videoMute && true; |
|
|
|
|
this.mediaConstraints = null; |
|
|
|
|
|
|
|
|
|
// Audio level.
|
|
|
|
|
this.audioLevel = 0; |
|
|
|
|
if (!this.options.noaudio && context && context.createScriptProcessor) { |
|
|
|
|
if (!this.options.noAudio && context && context.createScriptProcessor) { |
|
|
|
|
|
|
|
|
|
this.audioSource = null; |
|
|
|
|
this.audioProcessor = context.createScriptProcessor(2048, 1, 1); |
|
|
|
@ -167,6 +171,11 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
@@ -167,6 +171,11 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
|
|
|
|
|
if (this.audioSource) { |
|
|
|
|
this.audioSource.disconnect(); |
|
|
|
|
} |
|
|
|
|
var audioTracks = stream.getAudioTracks(); |
|
|
|
|
if (audioTracks.length < 1) { |
|
|
|
|
this.audioSource = null; |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
// Connect to audioProcessor.
|
|
|
|
|
this.audioSource = context.createMediaStreamSource(stream); |
|
|
|
|
//console.log("got source", this.audioSource);
|
|
|
|
@ -180,9 +189,13 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
@@ -180,9 +189,13 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
|
|
|
|
|
this.e.on("localstream", _.bind(function(event, stream, oldstream) { |
|
|
|
|
// Update stream support.
|
|
|
|
|
if (oldstream) { |
|
|
|
|
_.each(peerconnections, function(pc) { |
|
|
|
|
_.each(this.peerconnections, function(pc) { |
|
|
|
|
if (DummyStream.not(oldstream)) { |
|
|
|
|
pc.removeStream(oldstream); |
|
|
|
|
} |
|
|
|
|
if (DummyStream.not(stream)) { |
|
|
|
|
pc.addStream(stream); |
|
|
|
|
} |
|
|
|
|
console.log("Updated usermedia stream at peer connection", pc, stream); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
@ -244,7 +257,6 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
@@ -244,7 +257,6 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
|
|
|
|
|
if (!mediaConstraints) { |
|
|
|
|
mediaConstraints = currentcall.mediaConstraints; |
|
|
|
|
} |
|
|
|
|
this.mediaConstraints = mediaConstraints; |
|
|
|
|
|
|
|
|
|
return this.doGetUserMediaWithConstraints(mediaConstraints); |
|
|
|
|
|
|
|
|
@ -254,6 +266,21 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
@@ -254,6 +266,21 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
|
|
|
|
|
|
|
|
|
|
if (!mediaConstraints) { |
|
|
|
|
mediaConstraints = this.mediaConstraints; |
|
|
|
|
} else { |
|
|
|
|
this.mediaConstraints = mediaConstraints; |
|
|
|
|
if (this.localStream) { |
|
|
|
|
// Release stream early if any to be able to apply new constraints.
|
|
|
|
|
this.replaceStream(null); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (this.renegotiation && this.audioMute && this.videoMute) { |
|
|
|
|
// Fast path as nothing should be shared.
|
|
|
|
|
_.defer(_.bind(function() { |
|
|
|
|
this.onUserMediaSuccess(new DummyStream()); |
|
|
|
|
}, this)); |
|
|
|
|
this.started = true; |
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var constraints = $.extend(true, {}, mediaConstraints); |
|
|
|
@ -301,22 +328,18 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
@@ -301,22 +328,18 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
|
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
UserMedia.prototype.onLocalStream = function(stream) { |
|
|
|
|
UserMedia.prototype.replaceStream = function(stream) { |
|
|
|
|
|
|
|
|
|
var oldStream = this.localStream; |
|
|
|
|
if (oldStream) { |
|
|
|
|
oldStream.onended = function() {}; |
|
|
|
|
if (oldStream && oldStream.active) { |
|
|
|
|
// Let old stream silently end.
|
|
|
|
|
oldStream.onended = function() { |
|
|
|
|
console.log("Silently ended replaced user media stream."); |
|
|
|
|
}; |
|
|
|
|
oldStream.stop(); |
|
|
|
|
setTimeout(_.bind(function() { |
|
|
|
|
this.e.triggerHandler("mediachanged", [this]); |
|
|
|
|
}, this), 0); |
|
|
|
|
} else { |
|
|
|
|
// Let webrtc handle the rest.
|
|
|
|
|
setTimeout(_.bind(function() { |
|
|
|
|
this.e.triggerHandler("mediasuccess", [this]); |
|
|
|
|
}, this), this.delay); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (stream) { |
|
|
|
|
// Get notified of end events.
|
|
|
|
|
stream.onended = _.bind(function(event) { |
|
|
|
|
console.log("User media stream ended."); |
|
|
|
@ -324,10 +347,28 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
@@ -324,10 +347,28 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
|
|
|
|
|
this.stop(); |
|
|
|
|
} |
|
|
|
|
}, this); |
|
|
|
|
|
|
|
|
|
// Set new stream.
|
|
|
|
|
this.localStream = stream; |
|
|
|
|
this.e.triggerHandler("localstream", [stream, oldStream, this]); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return oldStream && stream; |
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
UserMedia.prototype.onLocalStream = function(stream) { |
|
|
|
|
|
|
|
|
|
if (this.replaceStream(stream)) { |
|
|
|
|
// We replaced a stream.
|
|
|
|
|
setTimeout(_.bind(function() { |
|
|
|
|
this.e.triggerHandler("mediachanged", [this]); |
|
|
|
|
}, this), 0); |
|
|
|
|
} else { |
|
|
|
|
// We are new.
|
|
|
|
|
setTimeout(_.bind(function() { |
|
|
|
|
this.e.triggerHandler("mediasuccess", [this]); |
|
|
|
|
}, this), 0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
@ -352,11 +393,7 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
@@ -352,11 +393,7 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
|
|
|
|
|
this.mediaConstraints = null; |
|
|
|
|
console.log("Stopped user media."); |
|
|
|
|
this.e.triggerHandler("stopped", [this]); |
|
|
|
|
|
|
|
|
|
this.delay = 1500; |
|
|
|
|
setTimeout(_.bind(function() { |
|
|
|
|
this.delay = 0; |
|
|
|
|
}, this), 2000); |
|
|
|
|
this.e.off(); |
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
@ -364,7 +401,7 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
@@ -364,7 +401,7 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
|
|
|
|
|
|
|
|
|
|
var m = !!mute; |
|
|
|
|
|
|
|
|
|
if (!enableRenegotiationSupport) { |
|
|
|
|
if (!this.renegotiation) { |
|
|
|
|
|
|
|
|
|
// Disable streams only - does not require renegotiation but keeps mic
|
|
|
|
|
// active and the stream will transmit silence.
|
|
|
|
@ -394,7 +431,7 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
@@ -394,7 +431,7 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
|
|
|
|
|
// Remove audio stream, by creating a new stream and doing renegotiation. This
|
|
|
|
|
// is the way to go to disable the mic when audio is muted.
|
|
|
|
|
|
|
|
|
|
if (this.localStream) { |
|
|
|
|
if (this.started) { |
|
|
|
|
if (this.audioMute !== m) { |
|
|
|
|
this.audioMute = m; |
|
|
|
|
this.doGetUserMediaWithConstraints(); |
|
|
|
@ -413,7 +450,7 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
@@ -413,7 +450,7 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
|
|
|
|
|
|
|
|
|
|
var m = !!mute; |
|
|
|
|
|
|
|
|
|
if (!enableRenegotiationSupport) { |
|
|
|
|
if (!this.renegotiation) { |
|
|
|
|
|
|
|
|
|
// Disable streams only - does not require renegotiation but keeps camera
|
|
|
|
|
// active and the stream will transmit black.
|
|
|
|
@ -441,7 +478,7 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
@@ -441,7 +478,7 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
|
|
|
|
|
// Remove video stream, by creating a new stream and doing renegotiation. This
|
|
|
|
|
// is the way to go to disable the camera when video is muted.
|
|
|
|
|
|
|
|
|
|
if (this.localStream) { |
|
|
|
|
if (this.started) { |
|
|
|
|
if (this.videoMute !== m) { |
|
|
|
|
this.videoMute = m; |
|
|
|
|
this.doGetUserMediaWithConstraints(); |
|
|
|
@ -460,13 +497,15 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
@@ -460,13 +497,15 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
|
|
|
|
|
|
|
|
|
|
console.log("Add usermedia stream to peer connection", pc, this.localStream); |
|
|
|
|
if (this.localStream) { |
|
|
|
|
if (DummyStream.not(this.localStream)) { |
|
|
|
|
pc.addStream(this.localStream); |
|
|
|
|
} |
|
|
|
|
var id = pc.id; |
|
|
|
|
if (!peerconnections.hasOwnProperty(id)) { |
|
|
|
|
peerconnections[id] = pc; |
|
|
|
|
pc.currentcall.e.one("closed", function() { |
|
|
|
|
delete peerconnections[id]; |
|
|
|
|
}); |
|
|
|
|
if (!this.peerconnections.hasOwnProperty(id)) { |
|
|
|
|
this.peerconnections[id] = pc; |
|
|
|
|
pc.currentcall.e.one("closed", _.bind(function() { |
|
|
|
|
delete this.peerconnections[id]; |
|
|
|
|
}, this)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -476,9 +515,11 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
@@ -476,9 +515,11 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
|
|
|
|
|
|
|
|
|
|
console.log("Remove usermedia stream from peer connection", pc, this.localStream); |
|
|
|
|
if (this.localStream) { |
|
|
|
|
if (DummyStream.not(this.localStream)) { |
|
|
|
|
pc.removeStream(this.localStream); |
|
|
|
|
if (peerconnections.hasOwnProperty(pc.id)) { |
|
|
|
|
delete peerconnections[pc.id]; |
|
|
|
|
} |
|
|
|
|
if (this.peerconnections.hasOwnProperty(pc.id)) { |
|
|
|
|
delete this.peerconnections[pc.id]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -486,7 +527,9 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
@@ -486,7 +527,9 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
|
|
|
|
|
|
|
|
|
|
UserMedia.prototype.attachMediaStream = function(video) { |
|
|
|
|
|
|
|
|
|
if (this.localStream && DummyStream.not(this.localStream)) { |
|
|
|
|
window.attachMediaStream(video, this.localStream); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|