'use strict'
// Adapter's interface.
var AdapterJS = AdapterJS || window.AdapterJS || {};
AdapterJS.options = AdapterJS.options || {};
// uncomment to get virtual webcams
// AdapterJS.options.getAllCams = true;
AdapterJS.options.getAllCams = !!AdapterJS.options.getAllCams;
// uncomment to prevent the install prompt when the plugin in not yet installed
// AdapterJS.options.hidePluginInstallPrompt = true;
AdapterJS.options.hidePluginInstallPrompt = !!AdapterJS.options.hidePluginInstallPrompt;
// uncomment to force the use of the plugin on Safari
// AdapterJS.options.forceSafariPlugin = true;
AdapterJS.options.forceSafariPlugin = !!AdapterJS.options.forceSafariPlugin;
// AdapterJS version
AdapterJS.VERSION = '@@version';
// This function will be called when the WebRTC API is ready to be used
// Whether it is the native implementation (Chrome, Firefox, Opera) or
// the plugin
// You may Override this function to synchronise the start of your application
// with the WebRTC API being ready.
// If you decide not to override use this synchronisation, it may result in
// an extensive CPU usage on the plugin start (once per tab loaded)
// Params:
// - isUsingPlugin: true is the WebRTC plugin is being used, false otherwise
//
AdapterJS.onwebrtcready = AdapterJS.onwebrtcready || function(isUsingPlugin) {
// The WebRTC API is ready.
// Override me and do whatever you want here
};
// New interface to store multiple callbacks, private
AdapterJS._onwebrtcreadies = [];
// Sets a callback function to be called when the WebRTC interface is ready.
// The first argument is the function to callback.\
// Throws an error if the first argument is not a function
AdapterJS.webRTCReady = function (baseCallback) {
if (typeof baseCallback !== 'function') {
throw new Error('Callback provided is not a function');
}
var callback = function () {
// Make users having requirejs to use the webRTCReady function to define first
// When you set a setTimeout(definePolyfill, 0), it overrides the WebRTC function
// This is be more than 0s
if (typeof window.require === 'function' &&
typeof AdapterJS._defineMediaSourcePolyfill === 'function') {
AdapterJS._defineMediaSourcePolyfill();
}
// All WebRTC interfaces are ready, just call the callback
baseCallback(null !== AdapterJS.WebRTCPlugin.plugin);
};
if (true === AdapterJS.onwebrtcreadyDone) {
callback();
} else {
// will be triggered automatically when your browser/plugin is ready.
AdapterJS._onwebrtcreadies.push(callback);
}
};
// Plugin namespace
AdapterJS.WebRTCPlugin = AdapterJS.WebRTCPlugin || {};
// The object to store plugin information
/* jshint ignore:start */
@Tem@include('pluginInfo.js', {})
/* jshint ignore:end */
AdapterJS.WebRTCPlugin.TAGS = {
NONE : 'none',
AUDIO : 'audio',
VIDEO : 'video'
};
// Unique identifier of each opened page
AdapterJS.WebRTCPlugin.pageId = Math.random().toString(36).slice(2);
// Use this whenever you want to call the plugin.
AdapterJS.WebRTCPlugin.plugin = null;
// Set log level for the plugin once it is ready.
// The different values are
// This is an asynchronous function that will run when the plugin is ready
AdapterJS.WebRTCPlugin.setLogLevel = null;
// Defines webrtc's JS interface according to the plugin's implementation.
// Define plugin Browsers as WebRTC Interface.
AdapterJS.WebRTCPlugin.defineWebRTCInterface = null;
// This function detects whether or not a plugin is installed.
// Checks if Not IE (firefox, for example), else if it's IE,
// we're running IE and do something. If not it is not supported.
AdapterJS.WebRTCPlugin.isPluginInstalled = null;
// Lets adapter.js wait until the the document is ready before injecting the plugin
AdapterJS.WebRTCPlugin.pluginInjectionInterval = null;
// Inject the HTML DOM object element into the page.
AdapterJS.WebRTCPlugin.injectPlugin = null;
// States of readiness that the plugin goes through when
// being injected and stated
AdapterJS.WebRTCPlugin.PLUGIN_STATES = {
NONE : 0, // no plugin use
INITIALIZING : 1, // Detected need for plugin
INJECTING : 2, // Injecting plugin
INJECTED: 3, // Plugin element injected but not usable yet
READY: 4 // Plugin ready to be used
};
// Current state of the plugin. You cannot use the plugin before this is
// equal to AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY
AdapterJS.WebRTCPlugin.pluginState = AdapterJS.WebRTCPlugin.PLUGIN_STATES.NONE;
// True is AdapterJS.onwebrtcready was already called, false otherwise
// Used to make sure AdapterJS.onwebrtcready is only called once
AdapterJS.onwebrtcreadyDone = false;
// Log levels for the plugin.
// To be set by calling AdapterJS.WebRTCPlugin.setLogLevel
/*
Log outputs are prefixed in some cases.
INFO: Information reported by the plugin.
ERROR: Errors originating from within the plugin.
WEBRTC: Error originating from within the libWebRTC library
*/
// From the least verbose to the most verbose
AdapterJS.WebRTCPlugin.PLUGIN_LOG_LEVELS = {
NONE : 'NONE',
ERROR : 'ERROR',
WARNING : 'WARNING',
INFO: 'INFO',
VERBOSE: 'VERBOSE',
SENSITIVE: 'SENSITIVE'
};
// Does a waiting check before proceeding to load the plugin.
AdapterJS.WebRTCPlugin.WaitForPluginReady = null;
// This methid will use an interval to wait for the plugin to be ready.
AdapterJS.WebRTCPlugin.callWhenPluginReady = null;
AdapterJS.documentReady = function () {
return (document.readyState === 'interactive' && !!document.body) || document.readyState === 'complete';
}
// !!!! WARNING: DO NOT OVERRIDE THIS FUNCTION. !!!
// This function will be called when plugin is ready. It sends necessary
// details to the plugin.
// The function will wait for the document to be ready and the set the
// plugin state to AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY,
// indicating that it can start being requested.
// This function is not in the IE/Safari condition brackets so that
// TemPluginLoaded function might be called on Chrome/Firefox.
// This function is the only private function that is not encapsulated to
// allow the plugin method to be called.
window.__TemWebRTCReady0 = function () {
if (AdapterJS.documentReady()) {
AdapterJS.WebRTCPlugin.pluginState = AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY;
AdapterJS.maybeThroughWebRTCReady();
} else {
// Try again in 100ms
setTimeout(__TemWebRTCReady0, 100);
}
};
AdapterJS.maybeThroughWebRTCReady = function() {
if (!AdapterJS.onwebrtcreadyDone) {
AdapterJS.onwebrtcreadyDone = true;
// If new interface for multiple callbacks used
if (AdapterJS._onwebrtcreadies.length) {
AdapterJS._onwebrtcreadies.forEach(function (callback) {
if (typeof(callback) === 'function') {
callback(AdapterJS.WebRTCPlugin.plugin !== null);
}
});
// Else if no callbacks on new interface assuming user used old(deprecated) way to set callback through AdapterJS.onwebrtcready = ...
} else if (typeof(AdapterJS.onwebrtcready) === 'function') {
AdapterJS.onwebrtcready(AdapterJS.WebRTCPlugin.plugin !== null);
}
}
};
// Text namespace
AdapterJS.TEXT = {
PLUGIN: {
REQUIRE_INSTALLATION: 'This website requires you to install a WebRTC-enabling plugin ' +
'to work on this browser.',
REQUIRE_RESTART: 'Your plugin is being downloaded. Please run the installer, and restart your browser to begin using it.',
NOT_SUPPORTED: 'Your browser does not support WebRTC.',
BUTTON: 'Install Now'
},
REFRESH: {
REQUIRE_REFRESH: 'Please refresh page',
BUTTON: 'Refresh Page'
}
};
// The result of ice connection states.
// - starting: Ice connection is starting.
// - checking: Ice connection is checking.
// - connected Ice connection is connected.
// - completed Ice connection is connected.
// - done Ice connection has been completed.
// - disconnected Ice connection has been disconnected.
// - failed Ice connection has failed.
// - closed Ice connection is closed.
AdapterJS._iceConnectionStates = {
starting : 'starting',
checking : 'checking',
connected : 'connected',
completed : 'connected',
done : 'completed',
disconnected : 'disconnected',
failed : 'failed',
closed : 'closed'
};
//The IceConnection states that has been fired for each peer.
AdapterJS._iceConnectionFiredStates = [];
// Check if WebRTC Interface is defined.
AdapterJS.isDefined = null;
// -----------------------------------------------------------
// Detected webrtc implementation. Types are:
// - 'moz': Mozilla implementation of webRTC.
// - 'webkit': WebKit implementation of webRTC.
// - 'plugin': Using the plugin implementation.
window.webrtcDetectedType = null;
//Creates MediaStream object.
window.MediaStream = (typeof MediaStream === 'function') ? MediaStream : null;
//Creates MediaStreamTrack object.
window.MediaStreamTrack = (typeof MediaStreamTrack === 'function') ? MediaStreamTrack : null;
//The RTCPeerConnection object.
window.RTCPeerConnection = (typeof RTCPeerConnection === 'function') ?
RTCPeerConnection : null;
// Creates RTCSessionDescription object for Plugin Browsers
window.RTCSessionDescription = (typeof RTCSessionDescription === 'function') ?
RTCSessionDescription : null;
// Creates RTCIceCandidate object for Plugin Browsers
window.RTCIceCandidate = (typeof RTCIceCandidate === 'function') ?
RTCIceCandidate : null;
// Get UserMedia (only difference is the prefix).
// Code from Adam Barth.
window.getUserMedia = (typeof getUserMedia === 'function') ?
getUserMedia : null;
// Attach a media stream to an element.
window.attachMediaStream = null;
// Re-attach a media stream to an element.
window.reattachMediaStream = null;
// Detected browser agent name. Types are:
// - 'firefox': Firefox browser.
// - 'chrome': Chrome browser.
// - 'opera': Opera browser.
// - 'safari': Safari browser.
// - 'IE' - Internet Explorer browser.
window.webrtcDetectedBrowser = null;
// Detected browser version.
window.webrtcDetectedVersion = null;
// The minimum browser version still supported by AJS.
window.webrtcMinimumVersion = null;
// The type of DC supported by the browser
window.webrtcDetectedDCSupport = null;
// This function helps to retrieve the webrtc detected browser information.
// This sets:
// - webrtcDetectedBrowser: The browser agent name.
// - webrtcDetectedVersion: The browser version.
// - webrtcMinimumVersion: The minimum browser version still supported by AJS.
// - webrtcDetectedType: The types of webRTC support.
// - 'moz': Mozilla implementation of webRTC.
// - 'webkit': WebKit implementation of webRTC.
// - 'plugin': Using the plugin implementation.
AdapterJS.parseWebrtcDetectedBrowser = function () {
var hasMatch = null;
// Detect Opera (8.0+)
if ((!!window.opr && !!opr.addons) || !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0) {
hasMatch = navigator.userAgent.match(/OPR\/(\d+)/i) || [];
window.webrtcDetectedBrowser = 'opera';
window.webrtcDetectedVersion = parseInt(hasMatch[1] || '0', 10);
window.webrtcMinimumVersion = 26;
window.webrtcDetectedType = 'webkit';
window.webrtcDetectedDCSupport = 'SCTP'; // Opera 20+ uses Chrome 33
// Detect Bowser on iOS
} else if (navigator.userAgent.match(/Bowser\/[0-9.]*/g)) {
hasMatch = navigator.userAgent.match(/Bowser\/[0-9.]*/g) || [];
var chromiumVersion = parseInt((navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./i) || [])[2] || '0', 10);
window.webrtcDetectedBrowser = 'bowser';
window.webrtcDetectedVersion = parseFloat((hasMatch[0] || '0/0').split('/')[1], 10);
window.webrtcMinimumVersion = 0;
window.webrtcDetectedType = 'webkit';
window.webrtcDetectedDCSupport = chromiumVersion > 30 ? 'SCTP' : 'RTP';
// Detect Opera on iOS (does not support WebRTC yet)
} else if (navigator.userAgent.indexOf('OPiOS') > 0) {
hasMatch = navigator.userAgent.match(/OPiOS\/([0-9]+)\./);
// Browser which do not support webrtc yet
window.webrtcDetectedBrowser = 'opera';
window.webrtcDetectedVersion = parseInt(hasMatch[1] || '0', 10);
window.webrtcMinimumVersion = 0;
window.webrtcDetectedType = null;
window.webrtcDetectedDCSupport = null;
// Detect Chrome on iOS (does not support WebRTC yet)
} else if (navigator.userAgent.indexOf('CriOS') > 0) {
hasMatch = navigator.userAgent.match(/CriOS\/([0-9]+)\./) || [];
window.webrtcDetectedVersion = parseInt(hasMatch[1] || '0', 10);
window.webrtcMinimumVersion = 0;
window.webrtcDetectedType = null;
window.webrtcDetectedBrowser = 'chrome';
window.webrtcDetectedDCSupport = null;
// Detect Firefox on iOS (does not support WebRTC yet)
} else if (navigator.userAgent.indexOf('FxiOS') > 0) {
hasMatch = navigator.userAgent.match(/FxiOS\/([0-9]+)\./) || [];
// Browser which do not support webrtc yet
window.webrtcDetectedBrowser = 'firefox';
window.webrtcDetectedVersion = parseInt(hasMatch[1] || '0', 10);
window.webrtcMinimumVersion = 0;
window.webrtcDetectedType = null;
window.webrtcDetectedDCSupport = null;
// Detect IE (6-11)
} else if (/*@cc_on!@*/false || !!document.documentMode) {
hasMatch = /\brv[ :]+(\d+)/g.exec(navigator.userAgent) || [];
window.webrtcDetectedBrowser = 'IE';
window.webrtcDetectedVersion = parseInt(hasMatch[1], 10);
window.webrtcMinimumVersion = 9;
window.webrtcDetectedType = 'plugin';
window.webrtcDetectedDCSupport = 'SCTP';
if (!webrtcDetectedVersion) {
hasMatch = /\bMSIE[ :]+(\d+)/g.exec(navigator.userAgent) || [];
window.webrtcDetectedVersion = parseInt(hasMatch[1] || '0', 10);
}
// Detect Edge (20+)
} else if (!!window.StyleMedia || navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)) {
hasMatch = navigator.userAgent.match(/Edge\/(\d+).(\d+)$/) || [];
// Previous webrtc/adapter uses minimum version as 10547 but checking in the Edge release history,
// It's close to 13.10547 and ObjectRTC API is fully supported in that version
window.webrtcDetectedBrowser = 'edge';
window.webrtcDetectedVersion = parseFloat((hasMatch[0] || '0/0').split('/')[1], 10);
window.webrtcMinimumVersion = 13.10547;
window.webrtcDetectedType = 'ms';
window.webrtcDetectedDCSupport = null;
// Detect Firefox (1.0+)
// Placed before Safari check to ensure Firefox on Android is detected
} else if (typeof InstallTrigger !== 'undefined' || navigator.userAgent.indexOf('irefox') > 0) {
hasMatch = navigator.userAgent.match(/Firefox\/([0-9]+)\./) || [];
window.webrtcDetectedBrowser = 'firefox';
window.webrtcDetectedVersion = parseInt(hasMatch[1] || '0', 10);
window.webrtcMinimumVersion = 33;
window.webrtcDetectedType = 'moz';
window.webrtcDetectedDCSupport = 'SCTP';
// Detect Chrome (1+ and mobile)
// Placed before Safari check to ensure Chrome on Android is detected
} else if ((!!window.chrome && !!window.chrome.webstore) || navigator.userAgent.indexOf('Chrom') > 0) {
hasMatch = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./i) || [];
window.webrtcDetectedBrowser = 'chrome';
window.webrtcDetectedVersion = parseInt(hasMatch[2] || '0', 10);
window.webrtcMinimumVersion = 38;
window.webrtcDetectedType = 'webkit';
window.webrtcDetectedDCSupport = window.webrtcDetectedVersion > 30 ? 'SCTP' : 'RTP'; // Chrome 31+ supports SCTP without flags
// Detect Safari
} else if (/constructor/i.test(window.HTMLElement) || (function (p) { return p.toString() === "[object SafariRemoteNotification]"; })(!window['safari'] || safari.pushNotification) || navigator.userAgent.match(/AppleWebKit\/(\d+)\./) || navigator.userAgent.match(/Version\/(\d+).(\d+)/)) {
hasMatch = navigator.userAgent.match(/version\/(\d+)\.(\d+)/i) || [];
var AppleWebKitBuild = navigator.userAgent.match(/AppleWebKit\/(\d+)/i) || [];
var isMobile = navigator.userAgent.match(/(iPhone|iPad)/gi);
var hasNativeImpl = AppleWebKitBuild.length >= 1 && AppleWebKitBuild[1] >= 604;
window.webrtcDetectedBrowser = 'safari';
window.webrtcDetectedVersion = parseInt(hasMatch[1] || '0', 10);
window.webrtcMinimumVersion = 7;
if (isMobile) {
window.webrtcDetectedType = hasNativeImpl ? 'AppleWebKit' : null;
} else { // desktop
var majorVersion = window.webrtcDetectedVersion;
var minorVersion = parseInt(hasMatch[2] || '0', 10);
var nativeImplIsOverridable = majorVersion == 11 && minorVersion < 2;
window.webrtcDetectedType = hasNativeImpl && !(AdapterJS.options.forceSafariPlugin && nativeImplIsOverridable) ? 'AppleWebKit' : 'plugin';
}
window.webrtcDetectedDCSupport = 'SCTP';
}
// Scope it to AdapterJS and window for better consistency
AdapterJS.webrtcDetectedBrowser = window.webrtcDetectedBrowser;
AdapterJS.webrtcDetectedVersion = window.webrtcDetectedVersion;
AdapterJS.webrtcMinimumVersion = window.webrtcMinimumVersion;
AdapterJS.webrtcDetectedType = window.webrtcDetectedType;
AdapterJS.webrtcDetectedDCSupport = window.webrtcDetectedDCSupport;
};
AdapterJS.addEvent = function(elem, evnt, func) {
if (elem.addEventListener) { // W3C DOM
elem.addEventListener(evnt, func, false);
} else if (elem.attachEvent) {// OLD IE DOM
elem.attachEvent('on'+evnt, func);
} else { // No much to do
elem[evnt] = func;
}
};
AdapterJS.renderNotificationBar = function (message, buttonText, buttonCallback) {
// only inject once the page is ready
if (!AdapterJS.documentReady()) {
return;
}
var w = window;
var i = document.createElement('iframe');
i.name = 'adapterjs-alert';
i.style.position = 'fixed';
i.style.top = '-41px';
i.style.left = 0;
i.style.right = 0;
i.style.width = '100%';
i.style.height = '40px';
i.style.backgroundColor = '#ffffe1';
i.style.border = 'none';
i.style.borderBottom = '1px solid #888888';
i.style.zIndex = '9999999';
if(typeof i.style.webkitTransition === 'string') {
i.style.webkitTransition = 'all .5s ease-out';
} else if(typeof i.style.transition === 'string') {
i.style.transition = 'all .5s ease-out';
}
document.body.appendChild(i);
var c = (i.contentWindow) ? i.contentWindow :
(i.contentDocument.document) ? i.contentDocument.document : i.contentDocument;
c.document.open();
c.document.write('' + message + '');
if(buttonText && typeof buttonCallback === 'function') {
c.document.write('');
c.document.close();
// On click on okay
AdapterJS.addEvent(c.document.getElementById('okay'), 'click', function (e) {
e.preventDefault();
try {
e.cancelBubble = true;
} catch(error) { }
buttonCallback(e);
});
// On click on Cancel - all bars has same logic so keeping it that way for now
AdapterJS.addEvent(c.document.getElementById('cancel'), 'click', function(e) {
w.document.body.removeChild(i);
});
} else {
c.document.close();
}
setTimeout(function() {
if(typeof i.style.webkitTransform === 'string') {
i.style.webkitTransform = 'translateY(40px)';
} else if(typeof i.style.transform === 'string') {
i.style.transform = 'translateY(40px)';
} else {
i.style.top = '0px';
}
}, 300);
};
// The requestUserMedia used by plugin gUM
window.requestUserMedia = (typeof requestUserMedia === 'function') ?
requestUserMedia : null;
// Check for browser types and react accordingly
AdapterJS.parseWebrtcDetectedBrowser();
if (['webkit', 'moz', 'ms', 'AppleWebKit'].indexOf(AdapterJS.webrtcDetectedType) > -1) {
///////////////////////////////////////////////////////////////////
// INJECTION OF GOOGLE'S ADAPTER.JS CONTENT
// Store the original native RTCPC in msRTCPeerConnection object
if (navigator.userAgent.match(/Edge\/(\d+).(\d+)$/) && window.RTCPeerConnection) {
window.msRTCPeerConnection = window.RTCPeerConnection;
}
/* jshint ignore:start */
@Goo@include('node_modules/webrtc-adapter/out/adapter.js', {})
/* jshint ignore:end */
// END OF INJECTION OF GOOGLE'S ADAPTER.JS CONTENT
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
// EXTENSION FOR CHROME, FIREFOX AND EDGE
// Includes legacy functions
// -- MediaStreamTrack.getSources
//
// and additional shims
// -- attachMediaStream
// -- reattachMediaStream
// -- requestUserMedia
// -- a call to AdapterJS.maybeThroughWebRTCReady (notifies WebRTC is ready)
// Add support for legacy functions
if ( navigator.mozGetUserMedia ) {
// Shim for MediaStreamTrack.getSources.
MediaStreamTrack.getSources = function(successCb) {
setTimeout(function() {
var infos = [
{ kind: 'audio', id: 'default', label:'', facing:'' },
{ kind: 'video', id: 'default', label:'', facing:'' }
];
successCb(infos);
}, 0);
};
// Attach a media stream to an element.
attachMediaStream = function(element, stream) {
element.srcObject = stream;
return element;
};
reattachMediaStream = function(to, from) {
to.srcObject = from.srcObject;
return to;
};
} else if ( navigator.webkitGetUserMedia ) {
// Attach a media stream to an element.
attachMediaStream = function(element, stream) {
if (AdapterJS.webrtcDetectedVersion >= 43) {
element.srcObject = stream;
} else if (typeof element.src !== 'undefined') {
element.src = URL.createObjectURL(stream);
} else {
console.error('Error attaching stream to element.');
// logging('Error attaching stream to element.');
}
return element;
};
reattachMediaStream = function(to, from) {
if (AdapterJS.webrtcDetectedVersion >= 43) {
to.srcObject = from.srcObject;
} else {
to.src = from.src;
}
return to;
};
} else if (AdapterJS.webrtcDetectedType === 'AppleWebKit') {
attachMediaStream = function(element, stream) {
element.srcObject = stream;
return element;
};
reattachMediaStream = function(to, from) {
to.srcObject = from.srcObject;
return to;
};
// Polyfill getUserMedia()
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
navigator.getUserMedia = getUserMedia = function (constraints, successCb, errorCb) {
navigator.mediaDevices.getUserMedia(constraints).then(successCb).catch(errorCb);
};
}
} else if (navigator.mediaDevices && navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)) {
// Attach a media stream to an element.
attachMediaStream = function(element, stream) {
element.srcObject = stream;
return element;
};
reattachMediaStream = function(to, from) {
to.srcObject = from.srcObject;
return to;
};
}
// Need to override attachMediaStream and reattachMediaStream
// to support the plugin's logic
var attachMediaStream_base = attachMediaStream;
if (AdapterJS.webrtcDetectedBrowser === 'opera') {
attachMediaStream_base = function (element, stream) {
if (AdapterJS.webrtcDetectedVersion > 38) {
element.srcObject = stream;
} else if (typeof element.src !== 'undefined') {
element.src = URL.createObjectURL(stream);
}
// Else it doesn't work
};
}
attachMediaStream = function (element, stream) {
if ((AdapterJS.webrtcDetectedBrowser === 'chrome' ||
AdapterJS.webrtcDetectedBrowser === 'opera') &&
!stream) {
// Chrome does not support "src = null"
element.src = '';
} else {
attachMediaStream_base(element, stream);
}
return element;
};
var reattachMediaStream_base = reattachMediaStream;
reattachMediaStream = function (to, from) {
reattachMediaStream_base(to, from);
return to;
};
// Propagate attachMediaStream and gUM in window and AdapterJS
window.attachMediaStream = attachMediaStream;
window.reattachMediaStream = reattachMediaStream;
window.getUserMedia = function(constraints, onSuccess, onFailure) {
navigator.getUserMedia(constraints, onSuccess, onFailure);
};
AdapterJS.attachMediaStream = attachMediaStream;
AdapterJS.reattachMediaStream = reattachMediaStream;
AdapterJS.getUserMedia = getUserMedia;
// Removed Google defined promises when promise is not defined
if (typeof Promise === 'undefined') {
requestUserMedia = null;
}
AdapterJS.maybeThroughWebRTCReady();
// END OF EXTENSION OF CHROME, FIREFOX AND EDGE
///////////////////////////////////////////////////////////////////
} else { // TRY TO USE PLUGIN
///////////////////////////////////////////////////////////////////
// WEBRTC PLUGIN SHIM
// Will automatically check if the plugin is available and inject it
// into the DOM if it is.
// When the plugin is not available, will prompt a banner to suggest installing it
// Use AdapterJS.options.hidePluginInstallPrompt to prevent this banner from popping
//
// Shims the follwing:
// -- getUserMedia
// -- MediaStream
// -- MediaStreamTrack
// -- MediaStreamTrack.getSources
// -- RTCPeerConnection
// -- RTCSessionDescription
// -- RTCIceCandidate
// -- attachMediaStream
// -- reattachMediaStream
// -- webrtcDetectedBrowser
// -- webrtcDetectedVersion
// IE 9 is not offering an implementation of console.log until you open a console
if (typeof console !== 'object' || typeof console.log !== 'function') {
/* jshint -W020 */
console = {} || console;
// Implemented based on console specs from MDN
// You may override these functions
console.log = function (arg) {};
console.info = function (arg) {};
console.error = function (arg) {};
console.dir = function (arg) {};
console.exception = function (arg) {};
console.trace = function (arg) {};
console.warn = function (arg) {};
console.count = function (arg) {};
console.debug = function (arg) {};
console.count = function (arg) {};
console.time = function (arg) {};
console.timeEnd = function (arg) {};
console.group = function (arg) {};
console.groupCollapsed = function (arg) {};
console.groupEnd = function (arg) {};
/* jshint +W020 */
}
/* jshint -W035 */
AdapterJS.WebRTCPlugin.WaitForPluginReady = function() {
while (AdapterJS.WebRTCPlugin.pluginState !== AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY) {
/* empty because it needs to prevent the function from running. */
}
};
/* jshint +W035 */
AdapterJS.WebRTCPlugin.callWhenPluginReady = function (callback) {
if (AdapterJS.WebRTCPlugin.pluginState === AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY) {
// Call immediately if possible
// Once the plugin is set, the code will always take this path
callback();
} else {
// otherwise start a 100ms interval
var checkPluginReadyState = setInterval(function () {
if (AdapterJS.WebRTCPlugin.pluginState === AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY) {
clearInterval(checkPluginReadyState);
callback();
}
}, 100);
}
};
AdapterJS.WebRTCPlugin.setLogLevel = function(logLevel) {
AdapterJS.WebRTCPlugin.callWhenPluginReady(function() {
AdapterJS.WebRTCPlugin.plugin.setLogLevel(logLevel);
});
};
AdapterJS.WebRTCPlugin.injectPlugin = function () {
// only inject once the page is ready
if (!AdapterJS.documentReady()) {
return;
}
// Prevent multiple injections
if (AdapterJS.WebRTCPlugin.pluginState !== AdapterJS.WebRTCPlugin.PLUGIN_STATES.INITIALIZING) {
return;
}
AdapterJS.WebRTCPlugin.pluginState = AdapterJS.WebRTCPlugin.PLUGIN_STATES.INJECTING;
var existing = document.getElementById(AdapterJS.WebRTCPlugin.pluginInfo.pluginId);
if (!!existing) {
// There is already a plugin injected in the DOM.
// Probably from multiple calls to node's require(AJS);
// Take the existing one, and make it this AJS's plugin
AdapterJS.WebRTCPlugin.plugin = existing;
AdapterJS.WebRTCPlugin.pluginState = AdapterJS.WebRTCPlugin.PLUGIN_STATES.INJECTED;
if (AdapterJS.WebRTCPlugin.plugin.valid) {
window[AdapterJS.WebRTCPlugin.pluginInfo.onload](); // call onload function to unlock AJS
} else {
// wait for plugin.valid with an interval
var pluginValidInterval = setInterval(function () {
if (AdapterJS.WebRTCPlugin.plugin.valid) {
clearInterval(pluginValidInterval);
window[AdapterJS.WebRTCPlugin.pluginInfo.onload](); // call onload function to unlock AJS
}
}, 100);
}
return;
}
if (AdapterJS.webrtcDetectedBrowser === 'IE' && AdapterJS.webrtcDetectedVersion <= 10) {
var frag = document.createDocumentFragment();
AdapterJS.WebRTCPlugin.plugin = document.createElement('div');
AdapterJS.WebRTCPlugin.plugin.innerHTML = '';
while (AdapterJS.WebRTCPlugin.plugin.firstChild) {
frag.appendChild(AdapterJS.WebRTCPlugin.plugin.firstChild);
}
document.body.appendChild(frag);
// Need to re-fetch the plugin
AdapterJS.WebRTCPlugin.plugin =
document.getElementById(AdapterJS.WebRTCPlugin.pluginInfo.pluginId);
} else {
// Load Plugin
AdapterJS.WebRTCPlugin.plugin = document.createElement('object');
AdapterJS.WebRTCPlugin.plugin.id =
AdapterJS.WebRTCPlugin.pluginInfo.pluginId;
// IE will only start the plugin if it's ACTUALLY visible
if (AdapterJS.webrtcDetectedBrowser === 'IE') {
AdapterJS.WebRTCPlugin.plugin.width = '1px';
AdapterJS.WebRTCPlugin.plugin.height = '1px';
} else { // The size of the plugin on Safari should be 0x0px
// so that the autorisation prompt is at the top
AdapterJS.WebRTCPlugin.plugin.width = '0px';
AdapterJS.WebRTCPlugin.plugin.height = '0px';
}
AdapterJS.WebRTCPlugin.plugin.type = AdapterJS.WebRTCPlugin.pluginInfo.type;
AdapterJS.WebRTCPlugin.plugin.innerHTML = '' +
'' +
' ' +
(AdapterJS.options.getAllCams ? '':'') +
'' +
'';
document.body.appendChild(AdapterJS.WebRTCPlugin.plugin);
}
AdapterJS.WebRTCPlugin.pluginState = AdapterJS.WebRTCPlugin.PLUGIN_STATES.INJECTED;
};
AdapterJS.WebRTCPlugin.isPluginInstalled =
function (comName, plugName, plugType, installedCb, notInstalledCb) {
if (AdapterJS.webrtcDetectedBrowser !== 'IE') {
var pluginArray = navigator.mimeTypes;
if (typeof pluginArray !== 'undefined') {
for (var i = 0; i < pluginArray.length; i++) {
if (pluginArray[i].type.indexOf(plugType) >= 0) {
installedCb();
return;
}
}
notInstalledCb();
} else {
AdapterJS.renderNotificationBar(AdapterJS.TEXT.PLUGIN.NOT_SUPPORTED);
}
} else {
try {
var axo = new ActiveXObject(comName + '.' + plugName);
} catch (e) {
notInstalledCb();
return;
}
installedCb();
}
};
AdapterJS.WebRTCPlugin.defineWebRTCInterface = function () {
if (AdapterJS.WebRTCPlugin.pluginState ===
AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY) {
console.error('AdapterJS - WebRTC interface has already been defined');
return;
}
AdapterJS.WebRTCPlugin.pluginState = AdapterJS.WebRTCPlugin.PLUGIN_STATES.INITIALIZING;
AdapterJS.isDefined = function (variable) {
return variable !== null && variable !== undefined;
};
////////////////////////////////////////////////////////////////////////////
/// RTCSessionDescription
////////////////////////////////////////////////////////////////////////////
RTCSessionDescription = function (info) {
AdapterJS.WebRTCPlugin.WaitForPluginReady();
return AdapterJS.WebRTCPlugin.plugin.
ConstructSessionDescription(info.type, info.sdp);
};
////////////////////////////////////////////////////////////////////////////
/// MediaStream
////////////////////////////////////////////////////////////////////////////
MediaStream = function (mediaStreamOrTracks) {
AdapterJS.WebRTCPlugin.WaitForPluginReady();
return AdapterJS.WebRTCPlugin.plugin.MediaStream(mediaStreamOrTracks);
}
////////////////////////////////////////////////////////////////////////////
/// RTCPeerConnection
////////////////////////////////////////////////////////////////////////////
RTCPeerConnection = function (servers, constraints) {
// Validate server argumenr
if (!(servers === undefined ||
servers === null ||
Array.isArray(servers.iceServers))) {
throw new Error('Failed to construct \'RTCPeerConnection\': Malformed RTCConfiguration');
}
// Validate constraints argument
if (typeof constraints !== 'undefined' && constraints !== null) {
var invalidConstraits = false;
invalidConstraits |= typeof constraints !== 'object';
invalidConstraits |= constraints.hasOwnProperty('mandatory') &&
constraints.mandatory !== undefined &&
constraints.mandatory !== null &&
constraints.mandatory.constructor !== Object;
invalidConstraits |= constraints.hasOwnProperty('optional') &&
constraints.optional !== undefined &&
constraints.optional !== null &&
!Array.isArray(constraints.optional);
if (invalidConstraits) {
throw new Error('Failed to construct \'RTCPeerConnection\': Malformed constraints object');
}
}
// Call relevant PeerConnection constructor according to plugin version
AdapterJS.WebRTCPlugin.WaitForPluginReady();
// RTCPeerConnection prototype from the old spec
var iceServers = null;
if (servers && Array.isArray(servers.iceServers)) {
iceServers = servers.iceServers;
for (var i = 0; i < iceServers.length; i++) {
// Legacy plugin versions compatibility
if (iceServers[i].urls && !iceServers[i].url) {
iceServers[i].url = iceServers[i].urls;
}
iceServers[i].hasCredentials = AdapterJS.
isDefined(iceServers[i].username) &&
AdapterJS.isDefined(iceServers[i].credential);
}
}
if (AdapterJS.WebRTCPlugin.plugin.PEER_CONNECTION_VERSION &&
AdapterJS.WebRTCPlugin.plugin.PEER_CONNECTION_VERSION > 1) {
// RTCPeerConnection prototype from the new spec
if (iceServers) {
servers.iceServers = iceServers;
}
return AdapterJS.WebRTCPlugin.plugin.PeerConnection(servers);
} else {
var mandatory = (constraints && constraints.mandatory) ?
constraints.mandatory : null;
var optional = (constraints && constraints.optional) ?
constraints.optional : null;
return AdapterJS.WebRTCPlugin.plugin.
PeerConnection(AdapterJS.WebRTCPlugin.pageId,
iceServers, mandatory, optional);
}
};
////////////////////////////////////////////////////////////////////////////
/// MediaStreamTrack
////////////////////////////////////////////////////////////////////////////
MediaStreamTrack = function(){};
MediaStreamTrack.getSources = function (callback) {
AdapterJS.WebRTCPlugin.callWhenPluginReady(function() {
AdapterJS.WebRTCPlugin.plugin.GetSources(callback);
});
};
// getUserMedia constraints shim.
// Copied from Chrome
var constraintsToPlugin = 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') {
return;
}
if (typeof c[key] === 'string') {
cc[key] = c[key];
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;
};
// HACK : Specially handling: if deviceId is an object with exact property,
// change it such that deviceId value is not in exact property
// Reason : AJS-286 (deviceId in WebRTC samples not in the format specified as specifications)
if ( oldname('', key) === 'sourceId' && r.exact !== undefined ) {
r.ideal = r.exact;
r.exact = undefined;
}
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;
};
////////////////////////////////////////////////////////////////////////////
/// getUserMedia
////////////////////////////////////////////////////////////////////////////
getUserMedia = function (constraints, successCallback, failureCallback) {
var cc = {};
cc.audio = constraints.audio ?
constraintsToPlugin(constraints.audio) : false;
cc.video = constraints.video ?
constraintsToPlugin(constraints.video) : false;
AdapterJS.WebRTCPlugin.callWhenPluginReady(function() {
AdapterJS.WebRTCPlugin.plugin.
getUserMedia(cc, successCallback, failureCallback);
});
};
window.navigator.getUserMedia = getUserMedia;
////////////////////////////////////////////////////////////////////////////
/// mediaDevices
////////////////////////////////////////////////////////////////////////////
if (typeof Promise !== 'undefined') {
requestUserMedia = function(constraints) {
return new Promise(function(resolve, reject) {
try {
getUserMedia(constraints, resolve, reject);
} catch (error) {
reject(error);
}
});
};
if (typeof(navigator.mediaDevices) === 'undefined')
navigator.mediaDevices = {};
navigator.mediaDevices.getUserMedia = requestUserMedia;
navigator.mediaDevices.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],
id: device.id,
deviceId: device.id,
groupId: ''};
}));
});
});
};
}
////////////////////////////////////////////////////////////////////////////
/// attachMediaStream
////////////////////////////////////////////////////////////////////////////
attachMediaStream = function (element, stream) {
if (!element || !element.parentNode) {
return;
}
var streamId;
if (stream === null) {
streamId = '';
} else {
if (typeof stream.enableSoundTracks !== 'undefined') {
stream.enableSoundTracks(true);
}
streamId = stream.id;
}
var elementId = element.id.length === 0 ? Math.random().toString(36).slice(2) : element.id;
var nodeName = element.nodeName.toLowerCase();
if (nodeName !== 'object') { // not a plugin