|
|
|
|
@ -22,6 +22,11 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
@@ -22,6 +22,11 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
|
|
|
|
|
|
|
|
|
|
// 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; |
|
|
|
|
|
|
|
|
|
var UserMedia = function(options) { |
|
|
|
|
|
|
|
|
|
@ -32,9 +37,14 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
@@ -32,9 +37,14 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
|
|
|
|
|
this.started = false; |
|
|
|
|
this.delay = 0; |
|
|
|
|
|
|
|
|
|
this.audioMute = false; |
|
|
|
|
this.videoMute = false; |
|
|
|
|
this.mediaConstraints = null; |
|
|
|
|
|
|
|
|
|
// Audio level.
|
|
|
|
|
this.audioLevel = 0; |
|
|
|
|
if (!this.options.noaudio && context && context.createScriptProcessor) { |
|
|
|
|
|
|
|
|
|
this.audioSource = null; |
|
|
|
|
this.audioProcessor = context.createScriptProcessor(2048, 1, 1); |
|
|
|
|
this.audioProcessor.onaudioprocess = _.bind(function(event) { |
|
|
|
|
@ -54,8 +64,34 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
@@ -54,8 +64,34 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
|
|
|
|
|
this.audioLevel = rms; |
|
|
|
|
//console.log("this.audioLevel", this.audioLevel);
|
|
|
|
|
}, this); |
|
|
|
|
|
|
|
|
|
// Connect stream to audio processor if supported.
|
|
|
|
|
if (context.createMediaStreamSource) { |
|
|
|
|
this.e.on("localstream", _.bind(function(event, stream) { |
|
|
|
|
if (this.audioSource) { |
|
|
|
|
this.audioSource.disconnect(); |
|
|
|
|
} |
|
|
|
|
// Connect to audioProcessor.
|
|
|
|
|
this.audioSource = context.createMediaStreamSource(stream); |
|
|
|
|
//console.log("got source", this.audioSource);
|
|
|
|
|
this.audioSource.connect(this.audioProcessor); |
|
|
|
|
this.audioProcessor.connect(context.destination); |
|
|
|
|
}, this)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.e.on("localstream", _.bind(function(event, stream, oldstream) { |
|
|
|
|
// Update stream support.
|
|
|
|
|
if (oldstream) { |
|
|
|
|
_.each(peerconnections, function(pc) { |
|
|
|
|
pc.removeStream(oldstream); |
|
|
|
|
pc.addStream(stream); |
|
|
|
|
console.log("Updated usermedia stream at peer connection", pc, stream); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
}, this)); |
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// Static.
|
|
|
|
|
@ -112,11 +148,30 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
@@ -112,11 +148,30 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
|
|
|
|
|
if (!mediaConstraints) { |
|
|
|
|
mediaConstraints = currentcall.mediaConstraints; |
|
|
|
|
} |
|
|
|
|
this.mediaConstraints = mediaConstraints; |
|
|
|
|
|
|
|
|
|
return this.doGetUserMediaWithConstraints(mediaConstraints); |
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
UserMedia.prototype.doGetUserMediaWithConstraints = function(mediaConstraints) { |
|
|
|
|
|
|
|
|
|
if (!mediaConstraints) { |
|
|
|
|
mediaConstraints = this.mediaConstraints; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var constraints = $.extend(true, {}, mediaConstraints); |
|
|
|
|
if (this.audioMute) { |
|
|
|
|
constraints.audio = false; |
|
|
|
|
} |
|
|
|
|
if (this.videoMute) { |
|
|
|
|
constraints.video = false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
console.log('Requesting access to local media with mediaConstraints:\n' + |
|
|
|
|
' \'' + JSON.stringify(mediaConstraints) + '\'', mediaConstraints); |
|
|
|
|
getUserMedia(mediaConstraints, _.bind(this.onUserMediaSuccess, this), _.bind(this.onUserMediaError, this)); |
|
|
|
|
' \'' + JSON.stringify(constraints) + '\'', constraints); |
|
|
|
|
getUserMedia(constraints, _.bind(this.onUserMediaSuccess, this), _.bind(this.onUserMediaError, this)); |
|
|
|
|
this.started = true; |
|
|
|
|
return true; |
|
|
|
|
} catch (e) { |
|
|
|
|
@ -134,27 +189,7 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
@@ -134,27 +189,7 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
|
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Get notified of end events.
|
|
|
|
|
stream.onended = _.bind(function(event) { |
|
|
|
|
console.log("User media stream ended."); |
|
|
|
|
if (this.started) { |
|
|
|
|
this.stop(); |
|
|
|
|
} |
|
|
|
|
}, this); |
|
|
|
|
|
|
|
|
|
if (this.audioProcessor && context.createMediaStreamSource) { |
|
|
|
|
// Connect to audioProcessor.
|
|
|
|
|
this.audioSource = context.createMediaStreamSource(stream); |
|
|
|
|
//console.log("got source", this.audioSource);
|
|
|
|
|
this.audioSource.connect(this.audioProcessor); |
|
|
|
|
this.audioProcessor.connect(context.destination); |
|
|
|
|
} |
|
|
|
|
this.localStream = stream; |
|
|
|
|
|
|
|
|
|
// Let webrtc handle the rest.
|
|
|
|
|
setTimeout(_.bind(function() { |
|
|
|
|
this.e.triggerHandler("mediasuccess", [this]); |
|
|
|
|
}, this), this.delay); |
|
|
|
|
this.onLocalStream(stream); |
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
@ -170,6 +205,36 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
@@ -170,6 +205,36 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
|
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
UserMedia.prototype.onLocalStream = function(stream) { |
|
|
|
|
|
|
|
|
|
var oldStream = this.localStream; |
|
|
|
|
if (oldStream) { |
|
|
|
|
oldStream.onended = function() {}; |
|
|
|
|
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); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Get notified of end events.
|
|
|
|
|
stream.onended = _.bind(function(event) { |
|
|
|
|
console.log("User media stream ended."); |
|
|
|
|
if (this.started) { |
|
|
|
|
this.stop(); |
|
|
|
|
} |
|
|
|
|
}, this); |
|
|
|
|
|
|
|
|
|
// Set new stream.
|
|
|
|
|
this.localStream = stream; |
|
|
|
|
this.e.triggerHandler("localstream", [stream, oldStream, this]); |
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
UserMedia.prototype.stop = function() { |
|
|
|
|
|
|
|
|
|
this.started = false; |
|
|
|
|
@ -186,6 +251,9 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
@@ -186,6 +251,9 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
|
|
|
|
|
this.audioProcessor.disconnect() |
|
|
|
|
} |
|
|
|
|
this.audioLevel = 0; |
|
|
|
|
this.audioMute = false; |
|
|
|
|
this.videoMute = false; |
|
|
|
|
this.mediaConstraints = null; |
|
|
|
|
console.log("Stopped user media."); |
|
|
|
|
this.e.triggerHandler("stopped", [this]); |
|
|
|
|
|
|
|
|
|
@ -198,53 +266,97 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
@@ -198,53 +266,97 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
|
|
|
|
|
|
|
|
|
|
UserMedia.prototype.applyAudioMute = function(mute) { |
|
|
|
|
|
|
|
|
|
if (this.localStream) { |
|
|
|
|
var m = !!mute; |
|
|
|
|
|
|
|
|
|
var audioTracks = this.localStream.getAudioTracks(); |
|
|
|
|
if (audioTracks.length === 0) { |
|
|
|
|
//console.log('No local audio available.');
|
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
if (!enableRenegotiationSupport) { |
|
|
|
|
|
|
|
|
|
// Disable streams only - does not require renegotiation but keeps mic
|
|
|
|
|
// active and the stream will transmit silence.
|
|
|
|
|
|
|
|
|
|
if (this.localStream) { |
|
|
|
|
|
|
|
|
|
var audioTracks = this.localStream.getAudioTracks(); |
|
|
|
|
if (audioTracks.length === 0) { |
|
|
|
|
//console.log('No local audio available.');
|
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (var i = 0; i < audioTracks.length; i++) { |
|
|
|
|
audioTracks[i].enabled = !mute; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (mute) { |
|
|
|
|
console.log("Local audio muted by disabling audio tracks."); |
|
|
|
|
} else { |
|
|
|
|
console.log("Local audio unmuted by enabling audio tracks."); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (i = 0; i < audioTracks.length; i++) { |
|
|
|
|
audioTracks[i].enabled = !mute; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (mute) { |
|
|
|
|
console.log("Local audio muted.") |
|
|
|
|
} else { |
|
|
|
|
|
|
|
|
|
// 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.audioMute !== m) { |
|
|
|
|
this.audioMute = m; |
|
|
|
|
this.doGetUserMediaWithConstraints(); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
console.log("Local audio unmuted.") |
|
|
|
|
this.audioMute = m; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return mute; |
|
|
|
|
return m; |
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
UserMedia.prototype.applyVideoMute = function(mute) { |
|
|
|
|
|
|
|
|
|
if (this.localStream) { |
|
|
|
|
var m = !!mute; |
|
|
|
|
|
|
|
|
|
var videoTracks = this.localStream.getVideoTracks(); |
|
|
|
|
if (videoTracks.length === 0) { |
|
|
|
|
//console.log('No local video available.');
|
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
if (!enableRenegotiationSupport) { |
|
|
|
|
|
|
|
|
|
// Disable streams only - does not require renegotiation but keeps camera
|
|
|
|
|
// active and the stream will transmit black.
|
|
|
|
|
|
|
|
|
|
if (this.localStream) { |
|
|
|
|
var videoTracks = this.localStream.getVideoTracks(); |
|
|
|
|
if (videoTracks.length === 0) { |
|
|
|
|
//console.log('No local video available.');
|
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (var i = 0; i < videoTracks.length; i++) { |
|
|
|
|
videoTracks[i].enabled = !mute; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (mute) { |
|
|
|
|
console.log("Local video muted by disabling video tracks."); |
|
|
|
|
} else { |
|
|
|
|
console.log("Local video unmuted by enabling video tracks."); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (i = 0; i < videoTracks.length; i++) { |
|
|
|
|
videoTracks[i].enabled = !mute; |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
|
|
|
|
|
if (mute) { |
|
|
|
|
console.log("Local video muted.") |
|
|
|
|
// Removevideo 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.videoMute !== m) { |
|
|
|
|
this.videoMute = m; |
|
|
|
|
this.doGetUserMediaWithConstraints(); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
console.log("Local video unmuted.") |
|
|
|
|
this.videoMute = m; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return mute; |
|
|
|
|
return m; |
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
@ -253,6 +365,13 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
@@ -253,6 +365,13 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
|
|
|
|
|
console.log("Add usermedia stream to peer connection", pc, this.localStream); |
|
|
|
|
if (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]; |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
@ -262,13 +381,15 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
@@ -262,13 +381,15 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _
|
|
|
|
|
console.log("Remove usermedia stream from peer connection", pc, this.localStream); |
|
|
|
|
if (this.localStream) { |
|
|
|
|
pc.removeStream(this.localStream); |
|
|
|
|
if (peerconnections.hasOwnProperty(pc.id)) { |
|
|
|
|
delete peerconnections[pc.id]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
UserMedia.prototype.attachMediaStream = function(video) { |
|
|
|
|
|
|
|
|
|
//console.log("attach", video, this.localStream);
|
|
|
|
|
attachMediaStream(video, this.localStream); |
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|