UNPKG

webrtc-adapter-test

Version:

Hide browser differences in WebRTC APIs (test package name)

727 lines (667 loc) 25.2 kB
(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. */ 'use strict'; // 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. */ 'use strict'; 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. */ 'use strict'; 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. */ 'use strict'; 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) });