|
|
|
@ -30,31 +30,63 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
|
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
|
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
var RTCPeerConnection = null; |
|
|
|
|
|
|
|
var getUserMedia = null; |
|
|
|
var getUserMedia = null; |
|
|
|
var attachMediaStream = null; |
|
|
|
var attachMediaStream = null; |
|
|
|
var reattachMediaStream = null; |
|
|
|
var reattachMediaStream = null; |
|
|
|
var webrtcDetectedBrowser = null; |
|
|
|
var webrtcDetectedBrowser = null; |
|
|
|
var webrtcDetectedVersion = null; |
|
|
|
var webrtcDetectedVersion = null; |
|
|
|
|
|
|
|
var webrtcMinimumVersion = null; |
|
|
|
|
|
|
|
var webrtcUtils = { |
|
|
|
|
|
|
|
log: function() { |
|
|
|
|
|
|
|
// suppress console.log output when being included as a module.
|
|
|
|
|
|
|
|
if (!(typeof module !== 'undefined' || |
|
|
|
|
|
|
|
typeof require === 'function') && (typeof define === 'function')) { |
|
|
|
|
|
|
|
console.log.apply(console, arguments); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
if (navigator.mozGetUserMedia) { |
|
|
|
if (typeof window === 'undefined' || !window.navigator) { |
|
|
|
console.log('This appears to be Firefox'); |
|
|
|
webrtcUtils.log('This does not appear to be a browser'); |
|
|
|
|
|
|
|
webrtcDetectedBrowser = 'not a browser'; |
|
|
|
|
|
|
|
} else if (navigator.mozGetUserMedia) { |
|
|
|
|
|
|
|
webrtcUtils.log('This appears to be Firefox'); |
|
|
|
|
|
|
|
|
|
|
|
webrtcDetectedBrowser = 'firefox'; |
|
|
|
webrtcDetectedBrowser = 'firefox'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// the detected firefox version.
|
|
|
|
webrtcDetectedVersion = |
|
|
|
webrtcDetectedVersion = |
|
|
|
parseInt(navigator.userAgent.match(/Firefox\/([0-9]+)\./)[1], 10); |
|
|
|
parseInt(navigator.userAgent.match(/Firefox\/([0-9]+)\./)[1], 10); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// the minimum firefox version still supported by adapter.
|
|
|
|
|
|
|
|
webrtcMinimumVersion = 31; |
|
|
|
|
|
|
|
|
|
|
|
// The RTCPeerConnection object.
|
|
|
|
// The RTCPeerConnection object.
|
|
|
|
window.RTCPeerConnection = function(pcConfig, pcConstraints) { |
|
|
|
window.RTCPeerConnection = function(pcConfig, pcConstraints) { |
|
|
|
// .urls is not supported in FF yet.
|
|
|
|
if (webrtcDetectedVersion < 38) { |
|
|
|
|
|
|
|
// .urls is not supported in FF < 38.
|
|
|
|
|
|
|
|
// create RTCIceServers with a single url.
|
|
|
|
if (pcConfig && pcConfig.iceServers) { |
|
|
|
if (pcConfig && pcConfig.iceServers) { |
|
|
|
|
|
|
|
var newIceServers = []; |
|
|
|
for (var i = 0; i < pcConfig.iceServers.length; i++) { |
|
|
|
for (var i = 0; i < pcConfig.iceServers.length; i++) { |
|
|
|
if (pcConfig.iceServers[i].hasOwnProperty('urls')) { |
|
|
|
var server = pcConfig.iceServers[i]; |
|
|
|
pcConfig.iceServers[i].url = pcConfig.iceServers[i].urls; |
|
|
|
if (server.hasOwnProperty('urls')) { |
|
|
|
delete pcConfig.iceServers[i].urls; |
|
|
|
for (var j = 0; j < server.urls.length; j++) { |
|
|
|
|
|
|
|
var newServer = { |
|
|
|
|
|
|
|
url: server.urls[j] |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
if (server.urls[j].indexOf('turn') === 0) { |
|
|
|
|
|
|
|
newServer.username = server.username; |
|
|
|
|
|
|
|
newServer.credential = server.credential; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
newIceServers.push(newServer); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
newIceServers.push(pcConfig.iceServers[i]); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
pcConfig.iceServers = newIceServers; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return new mozRTCPeerConnection(pcConfig, pcConstraints); |
|
|
|
return new mozRTCPeerConnection(pcConfig, pcConstraints); |
|
|
|
}; |
|
|
|
}; |
|
|
|
@ -65,139 +97,407 @@ if (navigator.mozGetUserMedia) { |
|
|
|
// The RTCIceCandidate object.
|
|
|
|
// The RTCIceCandidate object.
|
|
|
|
window.RTCIceCandidate = mozRTCIceCandidate; |
|
|
|
window.RTCIceCandidate = mozRTCIceCandidate; |
|
|
|
|
|
|
|
|
|
|
|
// getUserMedia shim (only difference is the prefix).
|
|
|
|
// getUserMedia constraints shim.
|
|
|
|
// Code from Adam Barth.
|
|
|
|
getUserMedia = function(constraints, onSuccess, onError) { |
|
|
|
getUserMedia = navigator.mozGetUserMedia.bind(navigator); |
|
|
|
var constraintsToFF37 = function(c) { |
|
|
|
navigator.getUserMedia = getUserMedia; |
|
|
|
if (typeof c !== 'object' || c.require) { |
|
|
|
|
|
|
|
return c; |
|
|
|
// Creates ICE server from the URL for FF.
|
|
|
|
} |
|
|
|
window.createIceServer = function(url, username, password) { |
|
|
|
var require = []; |
|
|
|
var iceServer = null; |
|
|
|
Object.keys(c).forEach(function(key) { |
|
|
|
var urlParts = url.split(':'); |
|
|
|
if (key === 'require' || key === 'advanced' || key === 'mediaSource') { |
|
|
|
if (urlParts[0].indexOf('stun') === 0) { |
|
|
|
return; |
|
|
|
// Create ICE server with STUN URL.
|
|
|
|
} |
|
|
|
iceServer = { |
|
|
|
var r = c[key] = (typeof c[key] === 'object') ? |
|
|
|
'url': url |
|
|
|
c[key] : {ideal: c[key]}; |
|
|
|
}; |
|
|
|
if (r.min !== undefined || |
|
|
|
} else if (urlParts[0].indexOf('turn') === 0) { |
|
|
|
r.max !== undefined || r.exact !== undefined) { |
|
|
|
if (webrtcDetectedVersion < 27) { |
|
|
|
require.push(key); |
|
|
|
// Create iceServer with turn url.
|
|
|
|
|
|
|
|
// Ignore the transport parameter from TURN url for FF version <=27.
|
|
|
|
|
|
|
|
var turnUrlParts = url.split('?'); |
|
|
|
|
|
|
|
// Return null for createIceServer if transport=tcp.
|
|
|
|
|
|
|
|
if (turnUrlParts.length === 1 || |
|
|
|
|
|
|
|
turnUrlParts[1].indexOf('transport=udp') === 0) { |
|
|
|
|
|
|
|
iceServer = { |
|
|
|
|
|
|
|
'url': turnUrlParts[0], |
|
|
|
|
|
|
|
'credential': password, |
|
|
|
|
|
|
|
'username': username |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (r.exact !== undefined) { |
|
|
|
|
|
|
|
if (typeof r.exact === 'number') { |
|
|
|
|
|
|
|
r.min = r.max = r.exact; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
// FF 27 and above supports transport parameters in TURN url,
|
|
|
|
c[key] = r.exact; |
|
|
|
// So passing in the full url to create iceServer.
|
|
|
|
} |
|
|
|
iceServer = { |
|
|
|
delete r.exact; |
|
|
|
'url': url, |
|
|
|
} |
|
|
|
'credential': password, |
|
|
|
if (r.ideal !== undefined) { |
|
|
|
'username': username |
|
|
|
c.advanced = c.advanced || []; |
|
|
|
|
|
|
|
var oc = {}; |
|
|
|
|
|
|
|
if (typeof r.ideal === 'number') { |
|
|
|
|
|
|
|
oc[key] = {min: r.ideal, max: r.ideal}; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
oc[key] = r.ideal; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
c.advanced.push(oc); |
|
|
|
|
|
|
|
delete r.ideal; |
|
|
|
|
|
|
|
if (!Object.keys(r).length) { |
|
|
|
|
|
|
|
delete c[key]; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
if (require.length) { |
|
|
|
|
|
|
|
c.require = require; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return c; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
if (webrtcDetectedVersion < 38) { |
|
|
|
|
|
|
|
webrtcUtils.log('spec: ' + JSON.stringify(constraints)); |
|
|
|
|
|
|
|
if (constraints.audio) { |
|
|
|
|
|
|
|
constraints.audio = constraintsToFF37(constraints.audio); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (constraints.video) { |
|
|
|
|
|
|
|
constraints.video = constraintsToFF37(constraints.video); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
webrtcUtils.log('ff37: ' + JSON.stringify(constraints)); |
|
|
|
} |
|
|
|
} |
|
|
|
return iceServer; |
|
|
|
return navigator.mozGetUserMedia(constraints, onSuccess, onError); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
window.createIceServers = function(urls, username, password) { |
|
|
|
navigator.getUserMedia = getUserMedia; |
|
|
|
var iceServers = []; |
|
|
|
|
|
|
|
// Use .url for FireFox.
|
|
|
|
// Shim for mediaDevices on older versions.
|
|
|
|
for (var i = 0; i < urls.length; i++) { |
|
|
|
if (!navigator.mediaDevices) { |
|
|
|
var iceServer = |
|
|
|
navigator.mediaDevices = {getUserMedia: requestUserMedia, |
|
|
|
window.createIceServer(urls[i], username, password); |
|
|
|
addEventListener: function() { }, |
|
|
|
if (iceServer !== null) { |
|
|
|
removeEventListener: function() { } |
|
|
|
iceServers.push(iceServer); |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
return iceServers; |
|
|
|
navigator.mediaDevices.enumerateDevices = |
|
|
|
|
|
|
|
navigator.mediaDevices.enumerateDevices || function() { |
|
|
|
|
|
|
|
return new Promise(function(resolve) { |
|
|
|
|
|
|
|
var infos = [ |
|
|
|
|
|
|
|
{kind: 'audioinput', deviceId: 'default', label:'', groupId:''}, |
|
|
|
|
|
|
|
{kind: 'videoinput', deviceId: 'default', label:'', groupId:''} |
|
|
|
|
|
|
|
]; |
|
|
|
|
|
|
|
resolve(infos); |
|
|
|
|
|
|
|
}); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (webrtcDetectedVersion < 41) { |
|
|
|
|
|
|
|
// Work around http://bugzil.la/1169665
|
|
|
|
|
|
|
|
var orgEnumerateDevices = |
|
|
|
|
|
|
|
navigator.mediaDevices.enumerateDevices.bind(navigator.mediaDevices); |
|
|
|
|
|
|
|
navigator.mediaDevices.enumerateDevices = function() { |
|
|
|
|
|
|
|
return orgEnumerateDevices().catch(function(e) { |
|
|
|
|
|
|
|
if (e.name === 'NotFoundError') { |
|
|
|
|
|
|
|
return []; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
throw e; |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
} |
|
|
|
// Attach a media stream to an element.
|
|
|
|
// Attach a media stream to an element.
|
|
|
|
attachMediaStream = function(element, stream) { |
|
|
|
attachMediaStream = function(element, stream) { |
|
|
|
console.log('Attaching media stream'); |
|
|
|
|
|
|
|
element.mozSrcObject = stream; |
|
|
|
element.mozSrcObject = stream; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
reattachMediaStream = function(to, from) { |
|
|
|
reattachMediaStream = function(to, from) { |
|
|
|
console.log('Reattaching media stream'); |
|
|
|
|
|
|
|
to.mozSrcObject = from.mozSrcObject; |
|
|
|
to.mozSrcObject = from.mozSrcObject; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
} else if (navigator.webkitGetUserMedia) { |
|
|
|
} else if (navigator.webkitGetUserMedia) { |
|
|
|
console.log('This appears to be Chrome'); |
|
|
|
webrtcUtils.log('This appears to be Chrome'); |
|
|
|
|
|
|
|
|
|
|
|
webrtcDetectedBrowser = 'chrome'; |
|
|
|
webrtcDetectedBrowser = 'chrome'; |
|
|
|
// Temporary fix until crbug/374263 is fixed.
|
|
|
|
|
|
|
|
// Setting Chrome version to 999, if version is unavailable.
|
|
|
|
// the detected chrome version.
|
|
|
|
var result = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./); |
|
|
|
webrtcDetectedVersion = |
|
|
|
if (result !== null) { |
|
|
|
parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2], 10); |
|
|
|
webrtcDetectedVersion = parseInt(result[2], 10); |
|
|
|
|
|
|
|
} else { |
|
|
|
// the minimum chrome version still supported by adapter.
|
|
|
|
webrtcDetectedVersion = 999; |
|
|
|
webrtcMinimumVersion = 38; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// The RTCPeerConnection object.
|
|
|
|
|
|
|
|
window.RTCPeerConnection = function(pcConfig, pcConstraints) { |
|
|
|
|
|
|
|
var pc = new webkitRTCPeerConnection(pcConfig, pcConstraints); |
|
|
|
|
|
|
|
var origGetStats = pc.getStats.bind(pc); |
|
|
|
|
|
|
|
pc.getStats = function(selector, successCallback, errorCallback) { // jshint ignore: line
|
|
|
|
|
|
|
|
var self = this; |
|
|
|
|
|
|
|
var args = arguments; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If selector is a function then we are in the old style stats so just
|
|
|
|
|
|
|
|
// pass back the original getStats format to avoid breaking old users.
|
|
|
|
|
|
|
|
if (arguments.length > 0 && typeof selector === 'function') { |
|
|
|
|
|
|
|
return origGetStats(selector, successCallback); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Creates iceServer from the url for Chrome M33 and earlier.
|
|
|
|
var fixChromeStats = function(response) { |
|
|
|
window.createIceServer = function(url, username, password) { |
|
|
|
var standardReport = {}; |
|
|
|
var iceServer = null; |
|
|
|
var reports = response.result(); |
|
|
|
var urlParts = url.split(':'); |
|
|
|
reports.forEach(function(report) { |
|
|
|
if (urlParts[0].indexOf('stun') === 0) { |
|
|
|
var standardStats = { |
|
|
|
// Create iceServer with stun url.
|
|
|
|
id: report.id, |
|
|
|
iceServer = { |
|
|
|
timestamp: report.timestamp, |
|
|
|
'url': url |
|
|
|
type: report.type |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
report.names().forEach(function(name) { |
|
|
|
|
|
|
|
standardStats[name] = report.stat(name); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
standardReport[standardStats.id] = standardStats; |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return standardReport; |
|
|
|
}; |
|
|
|
}; |
|
|
|
} else if (urlParts[0].indexOf('turn') === 0) { |
|
|
|
|
|
|
|
// Chrome M28 & above uses below TURN format.
|
|
|
|
if (arguments.length >= 2) { |
|
|
|
iceServer = { |
|
|
|
var successCallbackWrapper = function(response) { |
|
|
|
'url': url, |
|
|
|
args[1](fixChromeStats(response)); |
|
|
|
'credential': password, |
|
|
|
|
|
|
|
'username': username |
|
|
|
|
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return origGetStats.apply(this, [successCallbackWrapper, arguments[0]]); |
|
|
|
} |
|
|
|
} |
|
|
|
return iceServer; |
|
|
|
|
|
|
|
|
|
|
|
// promise-support
|
|
|
|
|
|
|
|
return new Promise(function(resolve, reject) { |
|
|
|
|
|
|
|
origGetStats.apply(self, [resolve, reject]); |
|
|
|
|
|
|
|
}); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// Creates an ICEServer object from multiple URLs.
|
|
|
|
return pc; |
|
|
|
window.createIceServers = function(urls, username, password) { |
|
|
|
|
|
|
|
return [{ |
|
|
|
|
|
|
|
'urls': urls, |
|
|
|
|
|
|
|
'credential': password, |
|
|
|
|
|
|
|
'username': username |
|
|
|
|
|
|
|
}]; |
|
|
|
|
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// The RTCPeerConnection object.
|
|
|
|
// add promise support
|
|
|
|
RTCPeerConnection = function(pcConfig, pcConstraints) { |
|
|
|
['createOffer', 'createAnswer'].forEach(function(method) { |
|
|
|
return new webkitRTCPeerConnection(pcConfig, pcConstraints); |
|
|
|
var nativeMethod = webkitRTCPeerConnection.prototype[method]; |
|
|
|
|
|
|
|
webkitRTCPeerConnection.prototype[method] = function() { |
|
|
|
|
|
|
|
var self = this; |
|
|
|
|
|
|
|
if (arguments.length < 1 || (arguments.length === 1 && |
|
|
|
|
|
|
|
typeof(arguments[0]) === 'object')) { |
|
|
|
|
|
|
|
var opts = arguments.length === 1 ? arguments[0] : undefined; |
|
|
|
|
|
|
|
return new Promise(function(resolve, reject) { |
|
|
|
|
|
|
|
nativeMethod.apply(self, [resolve, reject, opts]); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
return nativeMethod.apply(this, arguments); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
['setLocalDescription', 'setRemoteDescription', |
|
|
|
|
|
|
|
'addIceCandidate'].forEach(function(method) { |
|
|
|
|
|
|
|
var nativeMethod = webkitRTCPeerConnection.prototype[method]; |
|
|
|
|
|
|
|
webkitRTCPeerConnection.prototype[method] = function() { |
|
|
|
|
|
|
|
var args = arguments; |
|
|
|
|
|
|
|
var self = this; |
|
|
|
|
|
|
|
return new Promise(function(resolve, reject) { |
|
|
|
|
|
|
|
nativeMethod.apply(self, [args[0], |
|
|
|
|
|
|
|
function() { |
|
|
|
|
|
|
|
resolve(); |
|
|
|
|
|
|
|
if (args.length >= 2) { |
|
|
|
|
|
|
|
args[1].apply(null, []); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
function(err) { |
|
|
|
|
|
|
|
reject(err); |
|
|
|
|
|
|
|
if (args.length >= 3) { |
|
|
|
|
|
|
|
args[2].apply(null, [err]); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}] |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// getUserMedia constraints shim.
|
|
|
|
|
|
|
|
var constraintsToChrome = function(c) { |
|
|
|
|
|
|
|
if (typeof c !== 'object' || c.mandatory || c.optional) { |
|
|
|
|
|
|
|
return c; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
var cc = {}; |
|
|
|
|
|
|
|
Object.keys(c).forEach(function(key) { |
|
|
|
|
|
|
|
if (key === 'require' || key === 'advanced' || key === 'mediaSource') { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
var r = (typeof c[key] === 'object') ? c[key] : {ideal: c[key]}; |
|
|
|
|
|
|
|
if (r.exact !== undefined && typeof r.exact === 'number') { |
|
|
|
|
|
|
|
r.min = r.max = r.exact; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
var oldname = function(prefix, name) { |
|
|
|
|
|
|
|
if (prefix) { |
|
|
|
|
|
|
|
return prefix + name.charAt(0).toUpperCase() + name.slice(1); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return (name === 'deviceId') ? 'sourceId' : name; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
if (r.ideal !== undefined) { |
|
|
|
|
|
|
|
cc.optional = cc.optional || []; |
|
|
|
|
|
|
|
var oc = {}; |
|
|
|
|
|
|
|
if (typeof r.ideal === 'number') { |
|
|
|
|
|
|
|
oc[oldname('min', key)] = r.ideal; |
|
|
|
|
|
|
|
cc.optional.push(oc); |
|
|
|
|
|
|
|
oc = {}; |
|
|
|
|
|
|
|
oc[oldname('max', key)] = r.ideal; |
|
|
|
|
|
|
|
cc.optional.push(oc); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
oc[oldname('', key)] = r.ideal; |
|
|
|
|
|
|
|
cc.optional.push(oc); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (r.exact !== undefined && typeof r.exact !== 'number') { |
|
|
|
|
|
|
|
cc.mandatory = cc.mandatory || {}; |
|
|
|
|
|
|
|
cc.mandatory[oldname('', key)] = r.exact; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
['min', 'max'].forEach(function(mix) { |
|
|
|
|
|
|
|
if (r[mix] !== undefined) { |
|
|
|
|
|
|
|
cc.mandatory = cc.mandatory || {}; |
|
|
|
|
|
|
|
cc.mandatory[oldname(mix, key)] = r[mix]; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
if (c.advanced) { |
|
|
|
|
|
|
|
cc.optional = (cc.optional || []).concat(c.advanced); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return cc; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// Get UserMedia (only difference is the prefix).
|
|
|
|
getUserMedia = function(constraints, onSuccess, onError) { |
|
|
|
// Code from Adam Barth.
|
|
|
|
if (constraints.audio) { |
|
|
|
getUserMedia = navigator.webkitGetUserMedia.bind(navigator); |
|
|
|
constraints.audio = constraintsToChrome(constraints.audio); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (constraints.video) { |
|
|
|
|
|
|
|
constraints.video = constraintsToChrome(constraints.video); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
webrtcUtils.log('chrome: ' + JSON.stringify(constraints)); |
|
|
|
|
|
|
|
return navigator.webkitGetUserMedia(constraints, onSuccess, onError); |
|
|
|
|
|
|
|
}; |
|
|
|
navigator.getUserMedia = getUserMedia; |
|
|
|
navigator.getUserMedia = getUserMedia; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!navigator.mediaDevices) { |
|
|
|
|
|
|
|
navigator.mediaDevices = {getUserMedia: requestUserMedia, |
|
|
|
|
|
|
|
enumerateDevices: function() { |
|
|
|
|
|
|
|
return new Promise(function(resolve) { |
|
|
|
|
|
|
|
var kinds = {audio: 'audioinput', video: 'videoinput'}; |
|
|
|
|
|
|
|
return MediaStreamTrack.getSources(function(devices) { |
|
|
|
|
|
|
|
resolve(devices.map(function(device) { |
|
|
|
|
|
|
|
return {label: device.label, |
|
|
|
|
|
|
|
kind: kinds[device.kind], |
|
|
|
|
|
|
|
deviceId: device.id, |
|
|
|
|
|
|
|
groupId: ''}; |
|
|
|
|
|
|
|
})); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
}}; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// A shim for getUserMedia method on the mediaDevices object.
|
|
|
|
|
|
|
|
// TODO(KaptenJansson) remove once implemented in Chrome stable.
|
|
|
|
|
|
|
|
if (!navigator.mediaDevices.getUserMedia) { |
|
|
|
|
|
|
|
navigator.mediaDevices.getUserMedia = function(constraints) { |
|
|
|
|
|
|
|
return requestUserMedia(constraints); |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// Even though Chrome 45 has navigator.mediaDevices and a getUserMedia
|
|
|
|
|
|
|
|
// function which returns a Promise, it does not accept spec-style
|
|
|
|
|
|
|
|
// constraints.
|
|
|
|
|
|
|
|
var origGetUserMedia = navigator.mediaDevices.getUserMedia. |
|
|
|
|
|
|
|
bind(navigator.mediaDevices); |
|
|
|
|
|
|
|
navigator.mediaDevices.getUserMedia = function(c) { |
|
|
|
|
|
|
|
webrtcUtils.log('spec: ' + JSON.stringify(c)); // whitespace for alignment
|
|
|
|
|
|
|
|
c.audio = constraintsToChrome(c.audio); |
|
|
|
|
|
|
|
c.video = constraintsToChrome(c.video); |
|
|
|
|
|
|
|
webrtcUtils.log('chrome: ' + JSON.stringify(c)); |
|
|
|
|
|
|
|
return origGetUserMedia(c); |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Dummy devicechange event methods.
|
|
|
|
|
|
|
|
// TODO(KaptenJansson) remove once implemented in Chrome stable.
|
|
|
|
|
|
|
|
if (typeof navigator.mediaDevices.addEventListener === 'undefined') { |
|
|
|
|
|
|
|
navigator.mediaDevices.addEventListener = function() { |
|
|
|
|
|
|
|
webrtcUtils.log('Dummy mediaDevices.addEventListener called.'); |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (typeof navigator.mediaDevices.removeEventListener === 'undefined') { |
|
|
|
|
|
|
|
navigator.mediaDevices.removeEventListener = function() { |
|
|
|
|
|
|
|
webrtcUtils.log('Dummy mediaDevices.removeEventListener called.'); |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Attach a media stream to an element.
|
|
|
|
// Attach a media stream to an element.
|
|
|
|
attachMediaStream = function(element, stream) { |
|
|
|
attachMediaStream = function(element, stream) { |
|
|
|
if (typeof element.srcObject !== 'undefined') { |
|
|
|
if (typeof element.srcObject !== 'undefined') { |
|
|
|
element.srcObject = stream; |
|
|
|
element.srcObject = stream; |
|
|
|
} else if (typeof element.mozSrcObject !== 'undefined') { |
|
|
|
|
|
|
|
element.mozSrcObject = stream; |
|
|
|
|
|
|
|
} else if (typeof element.src !== 'undefined') { |
|
|
|
} else if (typeof element.src !== 'undefined') { |
|
|
|
element.src = URL.createObjectURL(stream); |
|
|
|
element.src = URL.createObjectURL(stream); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
console.log('Error attaching stream to element.'); |
|
|
|
webrtcUtils.log('Error attaching stream to element.'); |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
reattachMediaStream = function(to, from) { |
|
|
|
reattachMediaStream = function(to, from) { |
|
|
|
to.src = from.src; |
|
|
|
to.src = from.src; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else if (navigator.mediaDevices && navigator.userAgent.match( |
|
|
|
|
|
|
|
/Edge\/(\d+).(\d+)$/)) { |
|
|
|
|
|
|
|
webrtcUtils.log('This appears to be Edge'); |
|
|
|
|
|
|
|
webrtcDetectedBrowser = 'edge'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
webrtcDetectedVersion = |
|
|
|
|
|
|
|
parseInt(navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)[2], 10); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// the minimum version still supported by adapter.
|
|
|
|
|
|
|
|
webrtcMinimumVersion = 12; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
getUserMedia = navigator.getUserMedia; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
attachMediaStream = function(element, stream) { |
|
|
|
|
|
|
|
element.srcObject = stream; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
reattachMediaStream = function(to, from) { |
|
|
|
|
|
|
|
to.srcObject = from.srcObject; |
|
|
|
|
|
|
|
}; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
console.log('Browser does not appear to be WebRTC-capable'); |
|
|
|
webrtcUtils.log('Browser does not appear to be WebRTC-capable'); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Returns the result of getUserMedia as a Promise.
|
|
|
|
|
|
|
|
function requestUserMedia(constraints) { |
|
|
|
|
|
|
|
return new Promise(function(resolve, reject) { |
|
|
|
|
|
|
|
getUserMedia(constraints, resolve, reject); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var webrtcTesting = {}; |
|
|
|
|
|
|
|
Object.defineProperty(webrtcTesting, 'version', { |
|
|
|
|
|
|
|
set: function(version) { |
|
|
|
|
|
|
|
webrtcDetectedVersion = version; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (typeof module !== 'undefined') { |
|
|
|
|
|
|
|
var RTCPeerConnection; |
|
|
|
|
|
|
|
if (typeof window !== 'undefined') { |
|
|
|
|
|
|
|
RTCPeerConnection = window.RTCPeerConnection; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
module.exports = { |
|
|
|
|
|
|
|
RTCPeerConnection: RTCPeerConnection, |
|
|
|
|
|
|
|
getUserMedia: getUserMedia, |
|
|
|
|
|
|
|
attachMediaStream: attachMediaStream, |
|
|
|
|
|
|
|
reattachMediaStream: reattachMediaStream, |
|
|
|
|
|
|
|
webrtcDetectedBrowser: webrtcDetectedBrowser, |
|
|
|
|
|
|
|
webrtcDetectedVersion: webrtcDetectedVersion, |
|
|
|
|
|
|
|
webrtcMinimumVersion: webrtcMinimumVersion, |
|
|
|
|
|
|
|
webrtcTesting: webrtcTesting |
|
|
|
|
|
|
|
//requestUserMedia: not exposed on purpose.
|
|
|
|
|
|
|
|
//trace: not exposed on purpose.
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
} else if ((typeof require === 'function') && (typeof define === 'function')) { |
|
|
|
|
|
|
|
// Expose objects and functions when RequireJS is doing the loading.
|
|
|
|
|
|
|
|
define([], function() { |
|
|
|
|
|
|
|
return { |
|
|
|
|
|
|
|
RTCPeerConnection: window.RTCPeerConnection, |
|
|
|
|
|
|
|
getUserMedia: getUserMedia, |
|
|
|
|
|
|
|
attachMediaStream: attachMediaStream, |
|
|
|
|
|
|
|
reattachMediaStream: reattachMediaStream, |
|
|
|
|
|
|
|
webrtcDetectedBrowser: webrtcDetectedBrowser, |
|
|
|
|
|
|
|
webrtcDetectedVersion: webrtcDetectedVersion, |
|
|
|
|
|
|
|
webrtcMinimumVersion: webrtcMinimumVersion, |
|
|
|
|
|
|
|
webrtcTesting: webrtcTesting |
|
|
|
|
|
|
|
//requestUserMedia: not exposed on purpose.
|
|
|
|
|
|
|
|
//trace: not exposed on purpose.
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
}); |
|
|
|
} |
|
|
|
} |