webrtc-adapter-test
Version:
Hide browser differences in WebRTC APIs (test package name)
727 lines (667 loc) • 25.2 kB
JavaScript
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.adapter = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
},{}],2:[function(require,module,exports){
/*
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree.
*/
;
// Shimming starts here.
(function() {
// Utils.
var logging = require('./utils').log;
var browserDetails = require('./utils').browserDetails;
// Export to the adapter global object visible in the browser.
module.exports.browserDetails = browserDetails;
module.exports.extractVersion = require('./utils').extractVersion;
module.exports.disableLog = require('./utils').disableLog;
// Uncomment if you do not want any logging at all including the switch
// statement below. Can also be turned off in the browser via
// adapter.disableLog(true) but then logging from the switch statement below
// will still appear.
//require('./utils').disableLog(true);
// Bail if version is not supported regardless of browser.
if (browserDetails.version < browserDetails.minVersion) {
logging('Browser: ' + browserDetails.browser + ' Version: ' +
browserDetails.version + ' <' + ' minimum supported version: ' +
browserDetails.minVersion + '\n aborting!');
return;
}
// Browser shims.
var chromeShim = require('./chrome/chrome_shim') || null;
var edgeShim = require('./edge/edge_shim') || null;
var firefoxShim = require('./firefox/firefox_shim') || null;
// Shim browser if found.
switch(browserDetails.browser) {
case 'chrome':
if (!chromeShim) {
logging('Chrome shim is not included in this adapter release.');
return;
}
logging('Adapter.js shimming chrome!');
// Export to the adapter global object visible in the browser.
module.exports.browserShim = chromeShim;
chromeShim.shimSourceObject();
chromeShim.shimPeerConnection();
chromeShim.shimGetUserMedia();
break;
case 'edge':
if (!edgeShim) {
logging('MS edge shim is not included in this adapter release.');
return;
}
logging('Adapter.js shimming edge!');
// Export to the adapter global object visible in the browser.
module.exports.browserShim = edgeShim;
edgeShim.shimPeerConnection();
break;
case 'firefox':
if (!firefoxShim) {
logging('Firefox shim is not included in this adapter release.');
return;
}
logging('Adapter.js shimming firefox!');
// Export to the adapter global object visible in the browser.
module.exports.browserShim = firefoxShim;
firefoxShim.shimSourceObject();
firefoxShim.shimPeerConnection();
firefoxShim.shimGetUserMedia();
break;
default:
logging('Unsupported browser!');
}
})();
},{"./chrome/chrome_shim":3,"./edge/edge_shim":1,"./firefox/firefox_shim":4,"./utils":5}],3:[function(require,module,exports){
/*
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree.
*/
;
var logging = require('../utils.js').log;
var browserDetails = require('../utils.js').browserDetails;
var chromeShim = {
shimSourceObject: function() {
if (typeof window === 'object') {
if (window.HTMLMediaElement &&
!('srcObject' in window.HTMLMediaElement.prototype)) {
// Shim the srcObject property, once, when HTMLMediaElement is found.
Object.defineProperty(window.HTMLMediaElement.prototype, 'srcObject', {
get: function() {
return this._srcObject;
},
set: function(stream) {
// Use _srcObject as a private property for this shim
this._srcObject = stream;
// TODO: revokeObjectUrl(this.src) when !stream to release resources?
this.src = URL.createObjectURL(stream);
}
});
}
}
},
shimPeerConnection: function() {
// The RTCPeerConnection object.
window.RTCPeerConnection = function(pcConfig, pcConstraints) {
// Translate iceTransportPolicy to iceTransports,
// see https://code.google.com/p/webrtc/issues/detail?id=4869
logging('PeerConnection');
if (pcConfig && pcConfig.iceTransportPolicy) {
pcConfig.iceTransports = pcConfig.iceTransportPolicy;
}
var pc = new webkitRTCPeerConnection(pcConfig, pcConstraints); // jscs:ignore requireCapitalizedConstructors
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);
}
var fixChromeStats_ = function(response) {
var standardReport = {};
var reports = response.result();
reports.forEach(function(report) {
var standardStats = {
id: report.id,
timestamp: report.timestamp,
type: report.type
};
report.names().forEach(function(name) {
standardStats[name] = report.stat(name);
});
standardReport[standardStats.id] = standardStats;
});
return standardReport;
};
if (arguments.length >= 2) {
var successCallbackWrapper_ = function(response) {
args[1](fixChromeStats_(response));
};
return origGetStats.apply(this, [successCallbackWrapper_, arguments[0]]);
}
// promise-support
return new Promise(function(resolve, reject) {
if (args.length === 1 && selector === null) {
origGetStats.apply(self, [
function(response) {
resolve.apply(null, [fixChromeStats_(response)]);
}, reject]);
} else {
origGetStats.apply(self, [resolve, reject]);
}
});
};
return pc;
};
// wrap static methods. Currently just generateCertificate.
if (webkitRTCPeerConnection.generateCertificate) {
Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', {
get: function() {
if (arguments.length) {
return webkitRTCPeerConnection.generateCertificate.apply(null,
arguments);
} else {
return webkitRTCPeerConnection.generateCertificate;
}
}
});
}
// add promise support
['createOffer', 'createAnswer'].forEach(function(method) {
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]);
}
}]
);
});
};
});
},
shimGetUserMedia: function() {
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;
};
var getUserMedia_ = function(constraints, onSuccess, onError) {
if (constraints.audio) {
constraints.audio = constraintsToChrome_(constraints.audio);
}
if (constraints.video) {
constraints.video = constraintsToChrome_(constraints.video);
}
logging('chrome: ' + JSON.stringify(constraints));
return navigator.webkitGetUserMedia(constraints, onSuccess, onError);
};
navigator.getUserMedia = getUserMedia_;
// Returns the result of getUserMedia as a Promise.
var getUserMediaPromise_ = function(constraints) {
return new Promise(function(resolve, reject) {
navigator.getUserMedia(constraints, resolve, reject);
});
}
if (!navigator.mediaDevices) {
navigator.mediaDevices = {getUserMedia: getUserMediaPromise_,
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 getUserMediaPromise_(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) {
if (c) {
logging('spec: ' + JSON.stringify(c)); // whitespace for alignment
c.audio = constraintsToChrome_(c.audio);
c.video = constraintsToChrome_(c.video);
logging('chrome: ' + JSON.stringify(c));
}
return origGetUserMedia(c);
}.bind(this);
}
// Dummy devicechange event methods.
// TODO(KaptenJansson) remove once implemented in Chrome stable.
if (typeof navigator.mediaDevices.addEventListener === 'undefined') {
navigator.mediaDevices.addEventListener = function() {
logging('Dummy mediaDevices.addEventListener called.');
};
}
if (typeof navigator.mediaDevices.removeEventListener === 'undefined') {
navigator.mediaDevices.removeEventListener = function() {
logging('Dummy mediaDevices.removeEventListener called.');
};
}
},
// Attach a media stream to an element.
attachMediaStream: function(element, stream) {
logging('DEPRECATED, attachMediaStream will soon be removed.');
if (browserDetails.version >= 43) {
element.srcObject = stream;
} else if (typeof element.src !== 'undefined') {
element.src = URL.createObjectURL(stream);
} else {
logging('Error attaching stream to element.');
}
},
reattachMediaStream: function(to, from) {
logging('DEPRECATED, reattachMediaStream will soon be removed.');
if (browserDetails.version >= 43) {
to.srcObject = from.srcObject;
} else {
to.src = from.src;
}
}
}
// Expose public methods.
module.exports = {
shimSourceObject: chromeShim.shimSourceObject,
shimPeerConnection: chromeShim.shimPeerConnection,
shimGetUserMedia: chromeShim.shimGetUserMedia,
attachMediaStream: chromeShim.attachMediaStream,
reattachMediaStream: chromeShim.reattachMediaStream
};
},{"../utils.js":5}],4:[function(require,module,exports){
/*
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree.
*/
;
var logging = require('../utils').log;
var browserDetails = require('../utils').browserDetails;
var firefoxShim = {
shimSourceObject: function() {
if (typeof window === 'object') {
if (window.HTMLMediaElement &&
!('srcObject' in window.HTMLMediaElement.prototype)) {
// Shim the srcObject property, once, when HTMLMediaElement is found.
Object.defineProperty(window.HTMLMediaElement.prototype, 'srcObject', {
get: function() {
// If prefixed srcObject property exists, return it.
// Otherwise use the shimmed property, _srcObject
return 'mozSrcObject' in this ? this.mozSrcObject : this._srcObject;
},
set: function(stream) {
if ('mozSrcObject' in this) {
this.mozSrcObject = stream;
} else {
// Use _srcObject as a private property for this shim
this._srcObject = stream;
// TODO: revokeObjectUrl(this.src) when !stream to release resources?
this.src = URL.createObjectURL(stream);
}
}
});
}
}
},
shimPeerConnection: function() {
// The RTCPeerConnection object.
window.RTCPeerConnection = function(pcConfig, pcConstraints) {
if (browserDetails.version < 38) {
// .urls is not supported in FF < 38.
// create RTCIceServers with a single url.
if (pcConfig && pcConfig.iceServers) {
var newIceServers = [];
for (var i = 0; i < pcConfig.iceServers.length; i++) {
var server = pcConfig.iceServers[i];
if (server.hasOwnProperty('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); // jscs:ignore requireCapitalizedConstructors
};
// wrap static methods. Currently just generateCertificate.
if (mozRTCPeerConnection.generateCertificate) {
Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', {
get: function() {
if (arguments.length) {
return mozRTCPeerConnection.generateCertificate.apply(null,
arguments);
} else {
return mozRTCPeerConnection.generateCertificate;
}
}
});
}
// The RTCSessionDescription object.
if (!window.RTCSessionDescription) {
window.RTCSessionDescription = mozRTCSessionDescription;
}
// The RTCIceCandidate object.
if (!window.RTCIceCandidate) {
window.RTCIceCandidate = mozRTCIceCandidate;
}
},
shimGetUserMedia: function() {
// getUserMedia constraints shim.
var getUserMedia_ = function(constraints, onSuccess, onError) {
var constraintsToFF37_ = function(c) {
if (typeof c !== 'object' || c.require) {
return c;
}
var require = [];
Object.keys(c).forEach(function(key) {
if (key === 'require' || key === 'advanced' || key === 'mediaSource') {
return;
}
var r = c[key] = (typeof c[key] === 'object') ?
c[key] : {ideal: c[key]};
if (r.min !== undefined ||
r.max !== undefined || r.exact !== undefined) {
require.push(key);
}
if (r.exact !== undefined) {
if (typeof r.exact === 'number') {
r. min = r.max = r.exact;
} else {
c[key] = r.exact;
}
delete r.exact;
}
if (r.ideal !== undefined) {
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 (browserDetails.version < 38) {
logging('spec: ' + JSON.stringify(constraints));
if (constraints.audio) {
constraints.audio = constraintsToFF37_(constraints.audio);
}
if (constraints.video) {
constraints.video = constraintsToFF37_(constraints.video);
}
logging('ff37: ' + JSON.stringify(constraints));
}
return navigator.mozGetUserMedia(constraints, onSuccess, onError);
};
navigator.getUserMedia = getUserMedia_;
// Returns the result of getUserMedia as a Promise.
var getUserMediaPromise_ = function(constraints) {
return new Promise(function(resolve, reject) {
navigator.getUserMedia(constraints, resolve, reject);
});
}
// Shim for mediaDevices on older versions.
if (!navigator.mediaDevices) {
navigator.mediaDevices = {getUserMedia: getUserMediaPromise_,
addEventListener: function() { },
removeEventListener: function() { }
};
}
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 (browserDetails.version < 41) {
// Work around http://bugzil.la/1169665
var orgEnumerateDevices =
navigator.mediaDevices.enumerateDevices.bind(navigator.mediaDevices);
navigator.mediaDevices.enumerateDevices = function() {
return orgEnumerateDevices().then(undefined, function(e) {
if (e.name === 'NotFoundError') {
return [];
}
throw e;
});
};
}
},
// Attach a media stream to an element.
attachMediaStream: function(element, stream) {
logging('DEPRECATED, attachMediaStream will soon be removed.');
if (browserDetails.version >= 43) {
element.srcObject = stream;
} else if (typeof element.src !== 'undefined') {
element.src = URL.createObjectURL(stream);
} else {
logging('Error attaching stream to element.');
}
},
reattachMediaStream: function(to, from) {
logging('DEPRECATED, reattachMediaStream will soon be removed.');
if (browserDetails.version >= 43) {
to.srcObject = from.srcObject;
} else {
to.src = from.src;
}
}
}
// Expose public methods.
module.exports = {
shimSourceObject: firefoxShim.shimSourceObject,
shimPeerConnection: firefoxShim.shimPeerConnection,
shimGetUserMedia: firefoxShim.shimGetUserMedia,
attachMediaStream: firefoxShim.attachMediaStream,
reattachMediaStream: firefoxShim.reattachMediaStream
}
},{"../utils":5}],5:[function(require,module,exports){
/*
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree.
*/
;
var logDisabled_ = false;
// Utility methods.
var utils = {
disableLog: function(bool) {
if (typeof bool !== 'boolean') {
return new Error('Argument type: ' + typeof bool +
'. Please use a boolean.');
}
logDisabled_ = bool;
return (bool) ? 'adapter.js logging disabled' :
'adapter.js logging enabled';
},
log: function() {
if (typeof window === 'object') {
if (logDisabled_) {
return;
}
console.log.apply(console, arguments);
}
},
/**
* Extract browser version out of the provided user agent string.
* @param {!string} uastring userAgent string.
* @param {!string} expr Regular expression used as match criteria.
* @param {!number} pos position in the version string to be returned.
* @return {!number} browser version.
*/
extractVersion: function(uastring, expr, pos) {
var match = uastring.match(expr);
return match && match.length >= pos && parseInt(match[pos], 10);
},
/**
* Browser detector.
* @return {object} result containing browser, version and minVersion
* properties.
*/
detectBrowser: function() {
// Returned result object.
var result = {};
result.browser = null;
result.version = null
result.minVersion = null;
// Non supported browser.
if (typeof window === 'undefined' || !window.navigator) {
result.browser = 'Not a supported browser.';
return result;
}
// Firefox.
if (navigator.mozGetUserMedia && window.mozRTCPeerConnection) {
result.browser = 'firefox';
result.version = this.extractVersion(navigator.userAgent,
/Firefox\/([0-9]+)\./, 1);
result.minVersion = 31;
return result;
}
// Chrome/Chromium/Webview.
if (navigator.webkitGetUserMedia && window.webkitRTCPeerConnection) {
result.browser = 'chrome';
result.version = this.extractVersion(navigator.userAgent,
/Chrom(e|ium)\/([0-9]+)\./, 2);
result.minVersion = 38;
return result;
}
// Edge.
if (navigator.mediaDevices &&
navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)) {
result.browser = 'edge';
result.version = this.extractVersion(navigator.userAgent,
/Edge\/(\d+).(\d+)$/, 2);
result.minVersion = 10547;
return result;
}
}
};
// Export.
module.exports = {
log: utils.log,
disableLog: utils.disableLog,
browserDetails: utils.detectBrowser(),
extractVersion: utils.extractVersion
};
},{}]},{},[2])(2)
});