Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

adapter.screenshare.js 45KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310
  1. /*! adapterjs - v0.11.0 - 2015-06-08 */
  2. // Adapter's interface.
  3. var AdapterJS = AdapterJS || {};
  4. // Browserify compatibility
  5. if(typeof exports !== 'undefined') {
  6. module.exports = AdapterJS;
  7. }
  8. AdapterJS.options = AdapterJS.options || {};
  9. // uncomment to get virtual webcams
  10. // AdapterJS.options.getAllCams = true;
  11. // uncomment to prevent the install prompt when the plugin in not yet installed
  12. // AdapterJS.options.hidePluginInstallPrompt = true;
  13. // AdapterJS version
  14. AdapterJS.VERSION = '0.11.0';
  15. // This function will be called when the WebRTC API is ready to be used
  16. // Whether it is the native implementation (Chrome, Firefox, Opera) or
  17. // the plugin
  18. // You may Override this function to synchronise the start of your application
  19. // with the WebRTC API being ready.
  20. // If you decide not to override use this synchronisation, it may result in
  21. // an extensive CPU usage on the plugin start (once per tab loaded)
  22. // Params:
  23. // - isUsingPlugin: true is the WebRTC plugin is being used, false otherwise
  24. //
  25. AdapterJS.onwebrtcready = AdapterJS.onwebrtcready || function(isUsingPlugin) {
  26. // The WebRTC API is ready.
  27. // Override me and do whatever you want here
  28. };
  29. // Sets a callback function to be called when the WebRTC interface is ready.
  30. // The first argument is the function to callback.\
  31. // Throws an error if the first argument is not a function
  32. AdapterJS.webRTCReady = function (callback) {
  33. if (typeof callback !== 'function') {
  34. throw new Error('Callback provided is not a function');
  35. }
  36. if (true === AdapterJS.onwebrtcreadyDone) {
  37. // All WebRTC interfaces are ready, just call the callback
  38. callback(null !== AdapterJS.WebRTCPlugin.plugin);
  39. } else {
  40. // will be triggered automatically when your browser/plugin is ready.
  41. AdapterJS.onwebrtcready = callback;
  42. }
  43. };
  44. // Plugin namespace
  45. AdapterJS.WebRTCPlugin = AdapterJS.WebRTCPlugin || {};
  46. // The object to store plugin information
  47. AdapterJS.WebRTCPlugin.pluginInfo = {
  48. prefix : 'Tem',
  49. plugName : 'TemWebRTCPlugin',
  50. pluginId : 'plugin0',
  51. type : 'application/x-temwebrtcplugin',
  52. onload : '__TemWebRTCReady0',
  53. portalLink : 'http://skylink.io/plugin/',
  54. downloadLink : null, //set below
  55. companyName: 'Temasys'
  56. };
  57. if(!!navigator.platform.match(/^Mac/i)) {
  58. AdapterJS.WebRTCPlugin.pluginInfo.downloadLink = 'http://bit.ly/1n77hco';
  59. }
  60. else if(!!navigator.platform.match(/^Win/i)) {
  61. AdapterJS.WebRTCPlugin.pluginInfo.downloadLink = 'http://bit.ly/1kkS4FN';
  62. }
  63. // Unique identifier of each opened page
  64. AdapterJS.WebRTCPlugin.pageId = Math.random().toString(36).slice(2);
  65. // Use this whenever you want to call the plugin.
  66. AdapterJS.WebRTCPlugin.plugin = null;
  67. // Set log level for the plugin once it is ready.
  68. // The different values are
  69. // This is an asynchronous function that will run when the plugin is ready
  70. AdapterJS.WebRTCPlugin.setLogLevel = null;
  71. // Defines webrtc's JS interface according to the plugin's implementation.
  72. // Define plugin Browsers as WebRTC Interface.
  73. AdapterJS.WebRTCPlugin.defineWebRTCInterface = null;
  74. // This function detects whether or not a plugin is installed.
  75. // Checks if Not IE (firefox, for example), else if it's IE,
  76. // we're running IE and do something. If not it is not supported.
  77. AdapterJS.WebRTCPlugin.isPluginInstalled = null;
  78. // Lets adapter.js wait until the the document is ready before injecting the plugin
  79. AdapterJS.WebRTCPlugin.pluginInjectionInterval = null;
  80. // Inject the HTML DOM object element into the page.
  81. AdapterJS.WebRTCPlugin.injectPlugin = null;
  82. // States of readiness that the plugin goes through when
  83. // being injected and stated
  84. AdapterJS.WebRTCPlugin.PLUGIN_STATES = {
  85. NONE : 0, // no plugin use
  86. INITIALIZING : 1, // Detected need for plugin
  87. INJECTING : 2, // Injecting plugin
  88. INJECTED: 3, // Plugin element injected but not usable yet
  89. READY: 4 // Plugin ready to be used
  90. };
  91. // Current state of the plugin. You cannot use the plugin before this is
  92. // equal to AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY
  93. AdapterJS.WebRTCPlugin.pluginState = AdapterJS.WebRTCPlugin.PLUGIN_STATES.NONE;
  94. // True is AdapterJS.onwebrtcready was already called, false otherwise
  95. // Used to make sure AdapterJS.onwebrtcready is only called once
  96. AdapterJS.onwebrtcreadyDone = false;
  97. // Log levels for the plugin.
  98. // To be set by calling AdapterJS.WebRTCPlugin.setLogLevel
  99. /*
  100. Log outputs are prefixed in some cases.
  101. INFO: Information reported by the plugin.
  102. ERROR: Errors originating from within the plugin.
  103. WEBRTC: Error originating from within the libWebRTC library
  104. */
  105. // From the least verbose to the most verbose
  106. AdapterJS.WebRTCPlugin.PLUGIN_LOG_LEVELS = {
  107. NONE : 'NONE',
  108. ERROR : 'ERROR',
  109. WARNING : 'WARNING',
  110. INFO: 'INFO',
  111. VERBOSE: 'VERBOSE',
  112. SENSITIVE: 'SENSITIVE'
  113. };
  114. // Does a waiting check before proceeding to load the plugin.
  115. AdapterJS.WebRTCPlugin.WaitForPluginReady = null;
  116. // This methid will use an interval to wait for the plugin to be ready.
  117. AdapterJS.WebRTCPlugin.callWhenPluginReady = null;
  118. // !!!! WARNING: DO NOT OVERRIDE THIS FUNCTION. !!!
  119. // This function will be called when plugin is ready. It sends necessary
  120. // details to the plugin.
  121. // The function will wait for the document to be ready and the set the
  122. // plugin state to AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY,
  123. // indicating that it can start being requested.
  124. // This function is not in the IE/Safari condition brackets so that
  125. // TemPluginLoaded function might be called on Chrome/Firefox.
  126. // This function is the only private function that is not encapsulated to
  127. // allow the plugin method to be called.
  128. __TemWebRTCReady0 = function () {
  129. if (document.readyState === 'complete') {
  130. AdapterJS.WebRTCPlugin.pluginState = AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY;
  131. AdapterJS.maybeThroughWebRTCReady();
  132. } else {
  133. AdapterJS.WebRTCPlugin.documentReadyInterval = setInterval(function () {
  134. if (document.readyState === 'complete') {
  135. // TODO: update comments, we wait for the document to be ready
  136. clearInterval(AdapterJS.WebRTCPlugin.documentReadyInterval);
  137. AdapterJS.WebRTCPlugin.pluginState = AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY;
  138. AdapterJS.maybeThroughWebRTCReady();
  139. }
  140. }, 100);
  141. }
  142. };
  143. AdapterJS.maybeThroughWebRTCReady = function() {
  144. if (!AdapterJS.onwebrtcreadyDone) {
  145. AdapterJS.onwebrtcreadyDone = true;
  146. if (typeof(AdapterJS.onwebrtcready) === 'function') {
  147. AdapterJS.onwebrtcready(AdapterJS.WebRTCPlugin.plugin !== null);
  148. }
  149. }
  150. };
  151. // Text namespace
  152. AdapterJS.TEXT = {
  153. PLUGIN: {
  154. REQUIRE_INSTALLATION: 'This website requires you to install a WebRTC-enabling plugin ' +
  155. 'to work on this browser.',
  156. NOT_SUPPORTED: 'Your browser does not support WebRTC.',
  157. BUTTON: 'Install Now'
  158. },
  159. REFRESH: {
  160. REQUIRE_REFRESH: 'Please refresh page',
  161. BUTTON: 'Refresh Page'
  162. }
  163. };
  164. // The result of ice connection states.
  165. // - starting: Ice connection is starting.
  166. // - checking: Ice connection is checking.
  167. // - connected Ice connection is connected.
  168. // - completed Ice connection is connected.
  169. // - done Ice connection has been completed.
  170. // - disconnected Ice connection has been disconnected.
  171. // - failed Ice connection has failed.
  172. // - closed Ice connection is closed.
  173. AdapterJS._iceConnectionStates = {
  174. starting : 'starting',
  175. checking : 'checking',
  176. connected : 'connected',
  177. completed : 'connected',
  178. done : 'completed',
  179. disconnected : 'disconnected',
  180. failed : 'failed',
  181. closed : 'closed'
  182. };
  183. //The IceConnection states that has been fired for each peer.
  184. AdapterJS._iceConnectionFiredStates = [];
  185. // Check if WebRTC Interface is defined.
  186. AdapterJS.isDefined = null;
  187. // This function helps to retrieve the webrtc detected browser information.
  188. // This sets:
  189. // - webrtcDetectedBrowser: The browser agent name.
  190. // - webrtcDetectedVersion: The browser version.
  191. // - webrtcDetectedType: The types of webRTC support.
  192. // - 'moz': Mozilla implementation of webRTC.
  193. // - 'webkit': WebKit implementation of webRTC.
  194. // - 'plugin': Using the plugin implementation.
  195. AdapterJS.parseWebrtcDetectedBrowser = function () {
  196. var hasMatch, checkMatch = navigator.userAgent.match(
  197. /(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
  198. if (/trident/i.test(checkMatch[1])) {
  199. hasMatch = /\brv[ :]+(\d+)/g.exec(navigator.userAgent) || [];
  200. webrtcDetectedBrowser = 'IE';
  201. webrtcDetectedVersion = parseInt(hasMatch[1] || '0', 10);
  202. } else if (checkMatch[1] === 'Chrome') {
  203. hasMatch = navigator.userAgent.match(/\bOPR\/(\d+)/);
  204. if (hasMatch !== null) {
  205. webrtcDetectedBrowser = 'opera';
  206. webrtcDetectedVersion = parseInt(hasMatch[1], 10);
  207. }
  208. }
  209. if (navigator.userAgent.indexOf('Safari')) {
  210. if (typeof InstallTrigger !== 'undefined') {
  211. webrtcDetectedBrowser = 'firefox';
  212. } else if (/*@cc_on!@*/ false || !!document.documentMode) {
  213. webrtcDetectedBrowser = 'IE';
  214. } else if (
  215. Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0) {
  216. webrtcDetectedBrowser = 'safari';
  217. } else if (!!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0) {
  218. webrtcDetectedBrowser = 'opera';
  219. } else if (!!window.chrome) {
  220. webrtcDetectedBrowser = 'chrome';
  221. }
  222. }
  223. if (!webrtcDetectedBrowser) {
  224. webrtcDetectedVersion = checkMatch[1];
  225. }
  226. if (!webrtcDetectedVersion) {
  227. try {
  228. checkMatch = (checkMatch[2]) ? [checkMatch[1], checkMatch[2]] :
  229. [navigator.appName, navigator.appVersion, '-?'];
  230. if ((hasMatch = navigator.userAgent.match(/version\/(\d+)/i)) !== null) {
  231. checkMatch.splice(1, 1, hasMatch[1]);
  232. }
  233. webrtcDetectedVersion = parseInt(checkMatch[1], 10);
  234. } catch (error) { }
  235. }
  236. };
  237. // To fix configuration as some browsers does not support
  238. // the 'urls' attribute.
  239. AdapterJS.maybeFixConfiguration = function (pcConfig) {
  240. if (pcConfig === null) {
  241. return;
  242. }
  243. for (var i = 0; i < pcConfig.iceServers.length; i++) {
  244. if (pcConfig.iceServers[i].hasOwnProperty('urls')) {
  245. pcConfig.iceServers[i].url = pcConfig.iceServers[i].urls;
  246. delete pcConfig.iceServers[i].urls;
  247. }
  248. }
  249. };
  250. AdapterJS.addEvent = function(elem, evnt, func) {
  251. if (elem.addEventListener) { // W3C DOM
  252. elem.addEventListener(evnt, func, false);
  253. } else if (elem.attachEvent) {// OLD IE DOM
  254. elem.attachEvent('on'+evnt, func);
  255. } else { // No much to do
  256. elem[evnt] = func;
  257. }
  258. };
  259. AdapterJS.renderNotificationBar = function (text, buttonText, buttonLink, openNewTab, displayRefreshBar) {
  260. // only inject once the page is ready
  261. if (document.readyState !== 'complete') {
  262. return;
  263. }
  264. var w = window;
  265. var i = document.createElement('iframe');
  266. i.style.position = 'fixed';
  267. i.style.top = '-41px';
  268. i.style.left = 0;
  269. i.style.right = 0;
  270. i.style.width = '100%';
  271. i.style.height = '40px';
  272. i.style.backgroundColor = '#ffffe1';
  273. i.style.border = 'none';
  274. i.style.borderBottom = '1px solid #888888';
  275. i.style.zIndex = '9999999';
  276. if(typeof i.style.webkitTransition === 'string') {
  277. i.style.webkitTransition = 'all .5s ease-out';
  278. } else if(typeof i.style.transition === 'string') {
  279. i.style.transition = 'all .5s ease-out';
  280. }
  281. document.body.appendChild(i);
  282. c = (i.contentWindow) ? i.contentWindow :
  283. (i.contentDocument.document) ? i.contentDocument.document : i.contentDocument;
  284. c.document.open();
  285. c.document.write('<span style="display: inline-block; font-family: Helvetica, Arial,' +
  286. 'sans-serif; font-size: .9rem; padding: 4px; vertical-align: ' +
  287. 'middle; cursor: default;">' + text + '</span>');
  288. if(buttonText && buttonLink) {
  289. c.document.write('<button id="okay">' + buttonText + '</button><button>Cancel</button>');
  290. c.document.close();
  291. AdapterJS.addEvent(c.document.getElementById('okay'), 'click', function(e) {
  292. if (!!displayRefreshBar) {
  293. AdapterJS.renderNotificationBar(AdapterJS.TEXT.EXTENSION ?
  294. AdapterJS.TEXT.EXTENSION.REQUIRE_REFRESH : AdapterJS.TEXT.REFRESH.REQUIRE_REFRESH,
  295. AdapterJS.TEXT.REFRESH.BUTTON, 'javascript:location.reload()');
  296. }
  297. window.open(buttonLink, !!openNewTab ? '_blank' : '_top');
  298. e.preventDefault();
  299. try {
  300. event.cancelBubble = true;
  301. } catch(error) { }
  302. });
  303. }
  304. else {
  305. c.document.close();
  306. }
  307. AdapterJS.addEvent(c.document, 'click', function() {
  308. w.document.body.removeChild(i);
  309. });
  310. setTimeout(function() {
  311. if(typeof i.style.webkitTransform === 'string') {
  312. i.style.webkitTransform = 'translateY(40px)';
  313. } else if(typeof i.style.transform === 'string') {
  314. i.style.transform = 'translateY(40px)';
  315. } else {
  316. i.style.top = '0px';
  317. }
  318. }, 300);
  319. };
  320. // -----------------------------------------------------------
  321. // Detected webrtc implementation. Types are:
  322. // - 'moz': Mozilla implementation of webRTC.
  323. // - 'webkit': WebKit implementation of webRTC.
  324. // - 'plugin': Using the plugin implementation.
  325. webrtcDetectedType = null;
  326. // Detected webrtc datachannel support. Types are:
  327. // - 'SCTP': SCTP datachannel support.
  328. // - 'RTP': RTP datachannel support.
  329. webrtcDetectedDCSupport = null;
  330. // Set the settings for creating DataChannels, MediaStream for
  331. // Cross-browser compability.
  332. // - This is only for SCTP based support browsers.
  333. // the 'urls' attribute.
  334. checkMediaDataChannelSettings =
  335. function (peerBrowserAgent, peerBrowserVersion, callback, constraints) {
  336. if (typeof callback !== 'function') {
  337. return;
  338. }
  339. var beOfferer = true;
  340. var isLocalFirefox = webrtcDetectedBrowser === 'firefox';
  341. // Nightly version does not require MozDontOfferDataChannel for interop
  342. var isLocalFirefoxInterop = webrtcDetectedType === 'moz' && webrtcDetectedVersion > 30;
  343. var isPeerFirefox = peerBrowserAgent === 'firefox';
  344. var isPeerFirefoxInterop = peerBrowserAgent === 'firefox' &&
  345. ((peerBrowserVersion) ? (peerBrowserVersion > 30) : false);
  346. // Resends an updated version of constraints for MozDataChannel to work
  347. // If other userAgent is firefox and user is firefox, remove MozDataChannel
  348. if ((isLocalFirefox && isPeerFirefox) || (isLocalFirefoxInterop)) {
  349. try {
  350. delete constraints.mandatory.MozDontOfferDataChannel;
  351. } catch (error) {
  352. console.error('Failed deleting MozDontOfferDataChannel');
  353. console.error(error);
  354. }
  355. } else if ((isLocalFirefox && !isPeerFirefox)) {
  356. constraints.mandatory.MozDontOfferDataChannel = true;
  357. }
  358. if (!isLocalFirefox) {
  359. // temporary measure to remove Moz* constraints in non Firefox browsers
  360. for (var prop in constraints.mandatory) {
  361. if (constraints.mandatory.hasOwnProperty(prop)) {
  362. if (prop.indexOf('Moz') !== -1) {
  363. delete constraints.mandatory[prop];
  364. }
  365. }
  366. }
  367. }
  368. // Firefox (not interopable) cannot offer DataChannel as it will cause problems to the
  369. // interopability of the media stream
  370. if (isLocalFirefox && !isPeerFirefox && !isLocalFirefoxInterop) {
  371. beOfferer = false;
  372. }
  373. callback(beOfferer, constraints);
  374. };
  375. // Handles the differences for all browsers ice connection state output.
  376. // - Tested outcomes are:
  377. // - Chrome (offerer) : 'checking' > 'completed' > 'completed'
  378. // - Chrome (answerer) : 'checking' > 'connected'
  379. // - Firefox (offerer) : 'checking' > 'connected'
  380. // - Firefox (answerer): 'checking' > 'connected'
  381. checkIceConnectionState = function (peerId, iceConnectionState, callback) {
  382. if (typeof callback !== 'function') {
  383. console.warn('No callback specified in checkIceConnectionState. Aborted.');
  384. return;
  385. }
  386. peerId = (peerId) ? peerId : 'peer';
  387. if (!AdapterJS._iceConnectionFiredStates[peerId] ||
  388. iceConnectionState === AdapterJS._iceConnectionStates.disconnected ||
  389. iceConnectionState === AdapterJS._iceConnectionStates.failed ||
  390. iceConnectionState === AdapterJS._iceConnectionStates.closed) {
  391. AdapterJS._iceConnectionFiredStates[peerId] = [];
  392. }
  393. iceConnectionState = AdapterJS._iceConnectionStates[iceConnectionState];
  394. if (AdapterJS._iceConnectionFiredStates[peerId].indexOf(iceConnectionState) < 0) {
  395. AdapterJS._iceConnectionFiredStates[peerId].push(iceConnectionState);
  396. if (iceConnectionState === AdapterJS._iceConnectionStates.connected) {
  397. setTimeout(function () {
  398. AdapterJS._iceConnectionFiredStates[peerId]
  399. .push(AdapterJS._iceConnectionStates.done);
  400. callback(AdapterJS._iceConnectionStates.done);
  401. }, 1000);
  402. }
  403. callback(iceConnectionState);
  404. }
  405. return;
  406. };
  407. // Firefox:
  408. // - Creates iceServer from the url for Firefox.
  409. // - Create iceServer with stun url.
  410. // - Create iceServer with turn url.
  411. // - Ignore the transport parameter from TURN url for FF version <=27.
  412. // - Return null for createIceServer if transport=tcp.
  413. // - FF 27 and above supports transport parameters in TURN url,
  414. // - So passing in the full url to create iceServer.
  415. // Chrome:
  416. // - Creates iceServer from the url for Chrome M33 and earlier.
  417. // - Create iceServer with stun url.
  418. // - Chrome M28 & above uses below TURN format.
  419. // Plugin:
  420. // - Creates Ice Server for Plugin Browsers
  421. // - If Stun - Create iceServer with stun url.
  422. // - Else - Create iceServer with turn url
  423. // - This is a WebRTC Function
  424. createIceServer = null;
  425. // Firefox:
  426. // - Creates IceServers for Firefox
  427. // - Use .url for FireFox.
  428. // - Multiple Urls support
  429. // Chrome:
  430. // - Creates iceServers from the urls for Chrome M34 and above.
  431. // - .urls is supported since Chrome M34.
  432. // - Multiple Urls support
  433. // Plugin:
  434. // - Creates Ice Servers for Plugin Browsers
  435. // - Multiple Urls support
  436. // - This is a WebRTC Function
  437. createIceServers = null;
  438. //------------------------------------------------------------
  439. //The RTCPeerConnection object.
  440. RTCPeerConnection = null;
  441. // Creates RTCSessionDescription object for Plugin Browsers
  442. RTCSessionDescription = (typeof RTCSessionDescription === 'function') ?
  443. RTCSessionDescription : null;
  444. // Creates RTCIceCandidate object for Plugin Browsers
  445. RTCIceCandidate = (typeof RTCIceCandidate === 'function') ?
  446. RTCIceCandidate : null;
  447. // Get UserMedia (only difference is the prefix).
  448. // Code from Adam Barth.
  449. getUserMedia = null;
  450. // Attach a media stream to an element.
  451. attachMediaStream = null;
  452. // Re-attach a media stream to an element.
  453. reattachMediaStream = null;
  454. // Detected browser agent name. Types are:
  455. // - 'firefox': Firefox browser.
  456. // - 'chrome': Chrome browser.
  457. // - 'opera': Opera browser.
  458. // - 'safari': Safari browser.
  459. // - 'IE' - Internet Explorer browser.
  460. webrtcDetectedBrowser = null;
  461. // Detected browser version.
  462. webrtcDetectedVersion = null;
  463. // Check for browser types and react accordingly
  464. if (navigator.mozGetUserMedia) {
  465. webrtcDetectedBrowser = 'firefox';
  466. webrtcDetectedVersion = parseInt(navigator
  467. .userAgent.match(/Firefox\/([0-9]+)\./)[1], 10);
  468. webrtcDetectedType = 'moz';
  469. webrtcDetectedDCSupport = 'SCTP';
  470. RTCPeerConnection = function (pcConfig, pcConstraints) {
  471. AdapterJS.maybeFixConfiguration(pcConfig);
  472. return new mozRTCPeerConnection(pcConfig, pcConstraints);
  473. };
  474. // The RTCSessionDescription object.
  475. RTCSessionDescription = mozRTCSessionDescription;
  476. window.RTCSessionDescription = RTCSessionDescription;
  477. // The RTCIceCandidate object.
  478. RTCIceCandidate = mozRTCIceCandidate;
  479. window.RTCIceCandidate = RTCIceCandidate;
  480. window.getUserMedia = navigator.mozGetUserMedia.bind(navigator);
  481. navigator.getUserMedia = window.getUserMedia;
  482. // Shim for MediaStreamTrack.getSources.
  483. MediaStreamTrack.getSources = function(successCb) {
  484. setTimeout(function() {
  485. var infos = [
  486. { kind: 'audio', id: 'default', label:'', facing:'' },
  487. { kind: 'video', id: 'default', label:'', facing:'' }
  488. ];
  489. successCb(infos);
  490. }, 0);
  491. };
  492. createIceServer = function (url, username, password) {
  493. var iceServer = null;
  494. var url_parts = url.split(':');
  495. if (url_parts[0].indexOf('stun') === 0) {
  496. iceServer = { url : url };
  497. } else if (url_parts[0].indexOf('turn') === 0) {
  498. if (webrtcDetectedVersion < 27) {
  499. var turn_url_parts = url.split('?');
  500. if (turn_url_parts.length === 1 ||
  501. turn_url_parts[1].indexOf('transport=udp') === 0) {
  502. iceServer = {
  503. url : turn_url_parts[0],
  504. credential : password,
  505. username : username
  506. };
  507. }
  508. } else {
  509. iceServer = {
  510. url : url,
  511. credential : password,
  512. username : username
  513. };
  514. }
  515. }
  516. return iceServer;
  517. };
  518. createIceServers = function (urls, username, password) {
  519. var iceServers = [];
  520. for (i = 0; i < urls.length; i++) {
  521. var iceServer = createIceServer(urls[i], username, password);
  522. if (iceServer !== null) {
  523. iceServers.push(iceServer);
  524. }
  525. }
  526. return iceServers;
  527. };
  528. attachMediaStream = function (element, stream) {
  529. element.mozSrcObject = stream;
  530. if (stream !== null)
  531. element.play();
  532. return element;
  533. };
  534. reattachMediaStream = function (to, from) {
  535. to.mozSrcObject = from.mozSrcObject;
  536. to.play();
  537. return to;
  538. };
  539. MediaStreamTrack.getSources = MediaStreamTrack.getSources || function (callback) {
  540. if (!callback) {
  541. throw new TypeError('Failed to execute \'getSources\' on \'MediaStreamTrack\'' +
  542. ': 1 argument required, but only 0 present.');
  543. }
  544. return callback([]);
  545. };
  546. // Fake get{Video,Audio}Tracks
  547. if (!MediaStream.prototype.getVideoTracks) {
  548. MediaStream.prototype.getVideoTracks = function () {
  549. return [];
  550. };
  551. }
  552. if (!MediaStream.prototype.getAudioTracks) {
  553. MediaStream.prototype.getAudioTracks = function () {
  554. return [];
  555. };
  556. }
  557. AdapterJS.maybeThroughWebRTCReady();
  558. } else if (navigator.webkitGetUserMedia) {
  559. webrtcDetectedBrowser = 'chrome';
  560. webrtcDetectedType = 'webkit';
  561. webrtcDetectedVersion = parseInt(navigator
  562. .userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2], 10);
  563. // check if browser is opera 20+
  564. var checkIfOpera = navigator.userAgent.match(/\bOPR\/(\d+)/);
  565. if (checkIfOpera !== null) {
  566. webrtcDetectedBrowser = 'opera';
  567. webrtcDetectedVersion = parseInt(checkIfOpera[1], 10);
  568. }
  569. // check browser datachannel support
  570. if ((webrtcDetectedBrowser === 'chrome' && webrtcDetectedVersion >= 31) ||
  571. (webrtcDetectedBrowser === 'opera' && webrtcDetectedVersion >= 20)) {
  572. webrtcDetectedDCSupport = 'SCTP';
  573. } else if (webrtcDetectedBrowser === 'chrome' && webrtcDetectedVersion < 30 &&
  574. webrtcDetectedVersion > 24) {
  575. webrtcDetectedDCSupport = 'RTP';
  576. } else {
  577. webrtcDetectedDCSupport = '';
  578. }
  579. createIceServer = function (url, username, password) {
  580. var iceServer = null;
  581. var url_parts = url.split(':');
  582. if (url_parts[0].indexOf('stun') === 0) {
  583. iceServer = { 'url' : url };
  584. } else if (url_parts[0].indexOf('turn') === 0) {
  585. iceServer = {
  586. 'url' : url,
  587. 'credential' : password,
  588. 'username' : username
  589. };
  590. }
  591. return iceServer;
  592. };
  593. createIceServers = function (urls, username, password) {
  594. var iceServers = [];
  595. if (webrtcDetectedVersion >= 34) {
  596. iceServers = {
  597. 'urls' : urls,
  598. 'credential' : password,
  599. 'username' : username
  600. };
  601. } else {
  602. for (i = 0; i < urls.length; i++) {
  603. var iceServer = createIceServer(urls[i], username, password);
  604. if (iceServer !== null) {
  605. iceServers.push(iceServer);
  606. }
  607. }
  608. }
  609. return iceServers;
  610. };
  611. RTCPeerConnection = function (pcConfig, pcConstraints) {
  612. if (webrtcDetectedVersion < 34) {
  613. AdapterJS.maybeFixConfiguration(pcConfig);
  614. }
  615. return new webkitRTCPeerConnection(pcConfig, pcConstraints);
  616. };
  617. window.getUserMedia = navigator.webkitGetUserMedia.bind(navigator);
  618. navigator.getUserMedia = window.getUserMedia;
  619. attachMediaStream = function (element, stream) {
  620. if (typeof element.srcObject !== 'undefined') {
  621. element.srcObject = stream;
  622. } else if (typeof element.mozSrcObject !== 'undefined') {
  623. element.mozSrcObject = stream;
  624. } else if (typeof element.src !== 'undefined') {
  625. element.src = (stream === null ? '' : URL.createObjectURL(stream));
  626. } else {
  627. console.log('Error attaching stream to element.');
  628. }
  629. return element;
  630. };
  631. reattachMediaStream = function (to, from) {
  632. to.src = from.src;
  633. return to;
  634. };
  635. AdapterJS.maybeThroughWebRTCReady();
  636. } else { // TRY TO USE PLUGIN
  637. // IE 9 is not offering an implementation of console.log until you open a console
  638. if (typeof console !== 'object' || typeof console.log !== 'function') {
  639. /* jshint -W020 */
  640. console = {} || console;
  641. // Implemented based on console specs from MDN
  642. // You may override these functions
  643. console.log = function (arg) {};
  644. console.info = function (arg) {};
  645. console.error = function (arg) {};
  646. console.dir = function (arg) {};
  647. console.exception = function (arg) {};
  648. console.trace = function (arg) {};
  649. console.warn = function (arg) {};
  650. console.count = function (arg) {};
  651. console.debug = function (arg) {};
  652. console.count = function (arg) {};
  653. console.time = function (arg) {};
  654. console.timeEnd = function (arg) {};
  655. console.group = function (arg) {};
  656. console.groupCollapsed = function (arg) {};
  657. console.groupEnd = function (arg) {};
  658. /* jshint +W020 */
  659. }
  660. webrtcDetectedType = 'plugin';
  661. webrtcDetectedDCSupport = 'plugin';
  662. AdapterJS.parseWebrtcDetectedBrowser();
  663. isIE = webrtcDetectedBrowser === 'IE';
  664. /* jshint -W035 */
  665. AdapterJS.WebRTCPlugin.WaitForPluginReady = function() {
  666. while (AdapterJS.WebRTCPlugin.pluginState !== AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY) {
  667. /* empty because it needs to prevent the function from running. */
  668. }
  669. };
  670. /* jshint +W035 */
  671. AdapterJS.WebRTCPlugin.callWhenPluginReady = function (callback) {
  672. if (AdapterJS.WebRTCPlugin.pluginState === AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY) {
  673. // Call immediately if possible
  674. // Once the plugin is set, the code will always take this path
  675. callback();
  676. } else {
  677. // otherwise start a 100ms interval
  678. var checkPluginReadyState = setInterval(function () {
  679. if (AdapterJS.WebRTCPlugin.pluginState === AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY) {
  680. clearInterval(checkPluginReadyState);
  681. callback();
  682. }
  683. }, 100);
  684. }
  685. };
  686. AdapterJS.WebRTCPlugin.setLogLevel = function(logLevel) {
  687. AdapterJS.WebRTCPlugin.callWhenPluginReady(function() {
  688. AdapterJS.WebRTCPlugin.plugin.setLogLevel(logLevel);
  689. });
  690. };
  691. AdapterJS.WebRTCPlugin.injectPlugin = function () {
  692. // only inject once the page is ready
  693. if (document.readyState !== 'complete') {
  694. return;
  695. }
  696. // Prevent multiple injections
  697. if (AdapterJS.WebRTCPlugin.pluginState !== AdapterJS.WebRTCPlugin.PLUGIN_STATES.INITIALIZING) {
  698. return;
  699. }
  700. AdapterJS.WebRTCPlugin.pluginState = AdapterJS.WebRTCPlugin.PLUGIN_STATES.INJECTING;
  701. if (webrtcDetectedBrowser === 'IE' && webrtcDetectedVersion <= 10) {
  702. var frag = document.createDocumentFragment();
  703. AdapterJS.WebRTCPlugin.plugin = document.createElement('div');
  704. AdapterJS.WebRTCPlugin.plugin.innerHTML = '<object id="' +
  705. AdapterJS.WebRTCPlugin.pluginInfo.pluginId + '" type="' +
  706. AdapterJS.WebRTCPlugin.pluginInfo.type + '" ' + 'width="1" height="1">' +
  707. '<param name="pluginId" value="' +
  708. AdapterJS.WebRTCPlugin.pluginInfo.pluginId + '" /> ' +
  709. '<param name="windowless" value="false" /> ' +
  710. '<param name="pageId" value="' + AdapterJS.WebRTCPlugin.pageId + '" /> ' +
  711. '<param name="onload" value="' + AdapterJS.WebRTCPlugin.pluginInfo.onload +
  712. '" />' +
  713. // uncomment to be able to use virtual cams
  714. (AdapterJS.options.getAllCams ? '<param name="forceGetAllCams" value="True" />':'') +
  715. '</object>';
  716. while (AdapterJS.WebRTCPlugin.plugin.firstChild) {
  717. frag.appendChild(AdapterJS.WebRTCPlugin.plugin.firstChild);
  718. }
  719. document.body.appendChild(frag);
  720. // Need to re-fetch the plugin
  721. AdapterJS.WebRTCPlugin.plugin =
  722. document.getElementById(AdapterJS.WebRTCPlugin.pluginInfo.pluginId);
  723. } else {
  724. // Load Plugin
  725. AdapterJS.WebRTCPlugin.plugin = document.createElement('object');
  726. AdapterJS.WebRTCPlugin.plugin.id =
  727. AdapterJS.WebRTCPlugin.pluginInfo.pluginId;
  728. // IE will only start the plugin if it's ACTUALLY visible
  729. if (isIE) {
  730. AdapterJS.WebRTCPlugin.plugin.width = '1px';
  731. AdapterJS.WebRTCPlugin.plugin.height = '1px';
  732. } else { // The size of the plugin on Safari should be 0x0px
  733. // so that the autorisation prompt is at the top
  734. AdapterJS.WebRTCPlugin.plugin.width = '0px';
  735. AdapterJS.WebRTCPlugin.plugin.height = '0px';
  736. }
  737. AdapterJS.WebRTCPlugin.plugin.type = AdapterJS.WebRTCPlugin.pluginInfo.type;
  738. AdapterJS.WebRTCPlugin.plugin.innerHTML = '<param name="onload" value="' +
  739. AdapterJS.WebRTCPlugin.pluginInfo.onload + '">' +
  740. '<param name="pluginId" value="' +
  741. AdapterJS.WebRTCPlugin.pluginInfo.pluginId + '">' +
  742. '<param name="windowless" value="false" /> ' +
  743. (AdapterJS.options.getAllCams ? '<param name="forceGetAllCams" value="True" />':'') +
  744. '<param name="pageId" value="' + AdapterJS.WebRTCPlugin.pageId + '">';
  745. document.body.appendChild(AdapterJS.WebRTCPlugin.plugin);
  746. }
  747. AdapterJS.WebRTCPlugin.pluginState = AdapterJS.WebRTCPlugin.PLUGIN_STATES.INJECTED;
  748. };
  749. AdapterJS.WebRTCPlugin.isPluginInstalled =
  750. function (comName, plugName, installedCb, notInstalledCb) {
  751. if (!isIE) {
  752. var pluginArray = navigator.plugins;
  753. for (var i = 0; i < pluginArray.length; i++) {
  754. if (pluginArray[i].name.indexOf(plugName) >= 0) {
  755. installedCb();
  756. return;
  757. }
  758. }
  759. notInstalledCb();
  760. } else {
  761. try {
  762. var axo = new ActiveXObject(comName + '.' + plugName);
  763. } catch (e) {
  764. notInstalledCb();
  765. return;
  766. }
  767. installedCb();
  768. }
  769. };
  770. AdapterJS.WebRTCPlugin.defineWebRTCInterface = function () {
  771. AdapterJS.WebRTCPlugin.pluginState = AdapterJS.WebRTCPlugin.PLUGIN_STATES.INITIALIZING;
  772. AdapterJS.isDefined = function (variable) {
  773. return variable !== null && variable !== undefined;
  774. };
  775. createIceServer = function (url, username, password) {
  776. var iceServer = null;
  777. var url_parts = url.split(':');
  778. if (url_parts[0].indexOf('stun') === 0) {
  779. iceServer = {
  780. 'url' : url,
  781. 'hasCredentials' : false
  782. };
  783. } else if (url_parts[0].indexOf('turn') === 0) {
  784. iceServer = {
  785. 'url' : url,
  786. 'hasCredentials' : true,
  787. 'credential' : password,
  788. 'username' : username
  789. };
  790. }
  791. return iceServer;
  792. };
  793. createIceServers = function (urls, username, password) {
  794. var iceServers = [];
  795. for (var i = 0; i < urls.length; ++i) {
  796. iceServers.push(createIceServer(urls[i], username, password));
  797. }
  798. return iceServers;
  799. };
  800. RTCSessionDescription = function (info) {
  801. AdapterJS.WebRTCPlugin.WaitForPluginReady();
  802. return AdapterJS.WebRTCPlugin.plugin.
  803. ConstructSessionDescription(info.type, info.sdp);
  804. };
  805. RTCPeerConnection = function (servers, constraints) {
  806. var iceServers = null;
  807. if (servers) {
  808. iceServers = servers.iceServers;
  809. for (var i = 0; i < iceServers.length; i++) {
  810. if (iceServers[i].urls && !iceServers[i].url) {
  811. iceServers[i].url = iceServers[i].urls;
  812. }
  813. iceServers[i].hasCredentials = AdapterJS.
  814. isDefined(iceServers[i].username) &&
  815. AdapterJS.isDefined(iceServers[i].credential);
  816. }
  817. }
  818. var mandatory = (constraints && constraints.mandatory) ?
  819. constraints.mandatory : null;
  820. var optional = (constraints && constraints.optional) ?
  821. constraints.optional : null;
  822. AdapterJS.WebRTCPlugin.WaitForPluginReady();
  823. return AdapterJS.WebRTCPlugin.plugin.
  824. PeerConnection(AdapterJS.WebRTCPlugin.pageId,
  825. iceServers, mandatory, optional);
  826. };
  827. MediaStreamTrack = {};
  828. MediaStreamTrack.getSources = function (callback) {
  829. AdapterJS.WebRTCPlugin.callWhenPluginReady(function() {
  830. AdapterJS.WebRTCPlugin.plugin.GetSources(callback);
  831. });
  832. };
  833. window.getUserMedia = function (constraints, successCallback, failureCallback) {
  834. constraints.audio = constraints.audio || false;
  835. constraints.video = constraints.video || false;
  836. AdapterJS.WebRTCPlugin.callWhenPluginReady(function() {
  837. AdapterJS.WebRTCPlugin.plugin.
  838. getUserMedia(constraints, successCallback, failureCallback);
  839. });
  840. };
  841. window.navigator.getUserMedia = window.getUserMedia;
  842. attachMediaStream = function (element, stream) {
  843. if (!element || !element.parentNode) {
  844. return;
  845. }
  846. var streamId
  847. if (stream === null) {
  848. streamId = '';
  849. }
  850. else {
  851. stream.enableSoundTracks(true);
  852. streamId = stream.id;
  853. }
  854. if (element.nodeName.toLowerCase() !== 'audio') {
  855. var elementId = element.id.length === 0 ? Math.random().toString(36).slice(2) : element.id;
  856. if (!element.isWebRTCPlugin || !element.isWebRTCPlugin()) {
  857. var frag = document.createDocumentFragment();
  858. var temp = document.createElement('div');
  859. var classHTML = '';
  860. if (element.className) {
  861. classHTML = 'class="' + element.className + '" ';
  862. } else if (element.attributes && element.attributes['class']) {
  863. classHTML = 'class="' + element.attributes['class'].value + '" ';
  864. }
  865. temp.innerHTML = '<object id="' + elementId + '" ' + classHTML +
  866. 'type="' + AdapterJS.WebRTCPlugin.pluginInfo.type + '">' +
  867. '<param name="pluginId" value="' + elementId + '" /> ' +
  868. '<param name="pageId" value="' + AdapterJS.WebRTCPlugin.pageId + '" /> ' +
  869. '<param name="windowless" value="true" /> ' +
  870. '<param name="streamId" value="' + streamId + '" /> ' +
  871. '</object>';
  872. while (temp.firstChild) {
  873. frag.appendChild(temp.firstChild);
  874. }
  875. var height = '';
  876. var width = '';
  877. if (element.getBoundingClientRect) {
  878. var rectObject = element.getBoundingClientRect();
  879. width = rectObject.width + 'px';
  880. height = rectObject.height + 'px';
  881. }
  882. else if (element.width) {
  883. width = element.width;
  884. height = element.height;
  885. } else {
  886. // TODO: What scenario could bring us here?
  887. }
  888. element.parentNode.insertBefore(frag, element);
  889. frag = document.getElementById(elementId);
  890. frag.width = width;
  891. frag.height = height;
  892. element.parentNode.removeChild(element);
  893. } else {
  894. var children = element.children;
  895. for (var i = 0; i !== children.length; ++i) {
  896. if (children[i].name === 'streamId') {
  897. children[i].value = streamId;
  898. break;
  899. }
  900. }
  901. element.setStreamId(streamId);
  902. }
  903. var newElement = document.getElementById(elementId);
  904. newElement.onplaying = (element.onplaying) ? element.onplaying : function (arg) {};
  905. if (isIE) { // on IE the event needs to be plugged manually
  906. newElement.attachEvent('onplaying', newElement.onplaying);
  907. newElement.onclick = (element.onclick) ? element.onclick : function (arg) {};
  908. newElement._TemOnClick = function (id) {
  909. var arg = {
  910. srcElement : document.getElementById(id)
  911. };
  912. newElement.onclick(arg);
  913. };
  914. }
  915. return newElement;
  916. } else {
  917. return element;
  918. }
  919. };
  920. reattachMediaStream = function (to, from) {
  921. var stream = null;
  922. var children = from.children;
  923. for (var i = 0; i !== children.length; ++i) {
  924. if (children[i].name === 'streamId') {
  925. AdapterJS.WebRTCPlugin.WaitForPluginReady();
  926. stream = AdapterJS.WebRTCPlugin.plugin
  927. .getStreamWithId(AdapterJS.WebRTCPlugin.pageId, children[i].value);
  928. break;
  929. }
  930. }
  931. if (stream !== null) {
  932. return attachMediaStream(to, stream);
  933. } else {
  934. console.log('Could not find the stream associated with this element');
  935. }
  936. };
  937. RTCIceCandidate = function (candidate) {
  938. if (!candidate.sdpMid) {
  939. candidate.sdpMid = '';
  940. }
  941. AdapterJS.WebRTCPlugin.WaitForPluginReady();
  942. return AdapterJS.WebRTCPlugin.plugin.ConstructIceCandidate(
  943. candidate.sdpMid, candidate.sdpMLineIndex, candidate.candidate
  944. );
  945. };
  946. // inject plugin
  947. AdapterJS.addEvent(document, 'readystatechange', AdapterJS.WebRTCPlugin.injectPlugin);
  948. AdapterJS.WebRTCPlugin.injectPlugin();
  949. };
  950. // This function will be called if the plugin is needed (browser different
  951. // from Chrome or Firefox), but the plugin is not installed.
  952. AdapterJS.WebRTCPlugin.pluginNeededButNotInstalledCb = AdapterJS.WebRTCPlugin.pluginNeededButNotInstalledCb ||
  953. function() {
  954. AdapterJS.addEvent(document,
  955. 'readystatechange',
  956. AdapterJS.WebRTCPlugin.pluginNeededButNotInstalledCbPriv);
  957. AdapterJS.WebRTCPlugin.pluginNeededButNotInstalledCbPriv();
  958. };
  959. AdapterJS.WebRTCPlugin.pluginNeededButNotInstalledCbPriv = function () {
  960. if (AdapterJS.options.hidePluginInstallPrompt) {
  961. return;
  962. }
  963. var downloadLink = AdapterJS.WebRTCPlugin.pluginInfo.downloadLink;
  964. if(downloadLink) { // if download link
  965. var popupString;
  966. if (AdapterJS.WebRTCPlugin.pluginInfo.portalLink) { // is portal link
  967. popupString = 'This website requires you to install the ' +
  968. ' <a href="' + AdapterJS.WebRTCPlugin.pluginInfo.portalLink +
  969. '" target="_blank">' + AdapterJS.WebRTCPlugin.pluginInfo.companyName +
  970. ' WebRTC Plugin</a>' +
  971. ' to work on this browser.';
  972. } else { // no portal link, just print a generic explanation
  973. popupString = AdapterJS.TEXT.PLUGIN.REQUIRE_INSTALLATION;
  974. }
  975. AdapterJS.renderNotificationBar(popupString, AdapterJS.TEXT.PLUGIN.BUTTON, downloadLink);
  976. } else { // no download link, just print a generic explanation
  977. AdapterJS.renderNotificationBar(AdapterJS.TEXT.PLUGIN.NOT_SUPPORTED);
  978. }
  979. };
  980. // Try to detect the plugin and act accordingly
  981. AdapterJS.WebRTCPlugin.isPluginInstalled(
  982. AdapterJS.WebRTCPlugin.pluginInfo.prefix,
  983. AdapterJS.WebRTCPlugin.pluginInfo.plugName,
  984. AdapterJS.WebRTCPlugin.defineWebRTCInterface,
  985. AdapterJS.WebRTCPlugin.pluginNeededButNotInstalledCb);
  986. }
  987. (function () {
  988. 'use strict';
  989. var baseGetUserMedia = null;
  990. AdapterJS.TEXT.EXTENSION = {
  991. REQUIRE_INSTALLATION_FF: 'To enable screensharing you need to install the Skylink WebRTC tools Firefox Add-on.',
  992. REQUIRE_INSTALLATION_CHROME: 'To enable screensharing you need to install the Skylink WebRTC tools Chrome Extension.',
  993. REQUIRE_REFRESH: 'Please refresh this page after the Skylink WebRTC tools extension has been installed.',
  994. BUTTON_FF: 'Install Now',
  995. BUTTON_CHROME: 'Go to Chrome Web Store'
  996. };
  997. var clone = function(obj) {
  998. if (null == obj || "object" != typeof obj) return obj;
  999. var copy = obj.constructor();
  1000. for (var attr in obj) {
  1001. if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
  1002. }
  1003. return copy;
  1004. };
  1005. if (window.navigator.mozGetUserMedia) {
  1006. baseGetUserMedia = window.navigator.getUserMedia;
  1007. navigator.getUserMedia = function (constraints, successCb, failureCb) {
  1008. if (constraints && constraints.video && !!constraints.video.mediaSource) {
  1009. // intercepting screensharing requests
  1010. if (constraints.video.mediaSource !== 'screen' && constraints.video.mediaSource !== 'window') {
  1011. throw new Error('Only "screen" and "window" option is available as mediaSource');
  1012. }
  1013. var updatedConstraints = clone(constraints);
  1014. //constraints.video.mediaSource = constraints.video.mediaSource;
  1015. updatedConstraints.video.mozMediaSource = updatedConstraints.video.mediaSource;
  1016. // so generally, it requires for document.readyState to be completed before the getUserMedia could be invoked.
  1017. // strange but this works anyway
  1018. var checkIfReady = setInterval(function () {
  1019. if (document.readyState === 'complete') {
  1020. clearInterval(checkIfReady);
  1021. baseGetUserMedia(updatedConstraints, successCb, function (error) {
  1022. if (error.name === 'PermissionDeniedError' && window.parent.location.protocol === 'https:') {
  1023. AdapterJS.renderNotificationBar(AdapterJS.TEXT.EXTENSION.REQUIRE_INSTALLATION_FF,
  1024. AdapterJS.TEXT.EXTENSION.BUTTON_FF,
  1025. 'http://skylink.io/screensharing/ff_addon.php?domain=' + window.location.hostname, false, true);
  1026. //window.location.href = 'http://skylink.io/screensharing/ff_addon.php?domain=' + window.location.hostname;
  1027. } else {
  1028. failureCb(error);
  1029. }
  1030. });
  1031. }
  1032. }, 1);
  1033. } else { // regular GetUserMediaRequest
  1034. baseGetUserMedia(constraints, successCb, failureCb);
  1035. }
  1036. };
  1037. getUserMedia = navigator.getUserMedia;
  1038. } else if (window.navigator.webkitGetUserMedia) {
  1039. baseGetUserMedia = window.navigator.getUserMedia;
  1040. navigator.getUserMedia = function (constraints, successCb, failureCb) {
  1041. if (constraints && constraints.video && !!constraints.video.mediaSource) {
  1042. if (window.webrtcDetectedBrowser !== 'chrome') {
  1043. throw new Error('Current browser does not support screensharing');
  1044. }
  1045. // would be fine since no methods
  1046. var updatedConstraints = clone(constraints);
  1047. var chromeCallback = function(error, sourceId) {
  1048. if(!error) {
  1049. updatedConstraints.video.mandatory = updatedConstraints.video.mandatory || {};
  1050. updatedConstraints.video.mandatory.chromeMediaSource = 'desktop';
  1051. updatedConstraints.video.mandatory.maxWidth = window.screen.width > 1920 ? window.screen.width : 1920;
  1052. updatedConstraints.video.mandatory.maxHeight = window.screen.height > 1080 ? window.screen.height : 1080;
  1053. if (sourceId) {
  1054. updatedConstraints.video.mandatory.chromeMediaSourceId = sourceId;
  1055. }
  1056. delete updatedConstraints.video.mediaSource;
  1057. baseGetUserMedia(updatedConstraints, successCb, failureCb);
  1058. } else {
  1059. if (error === 'permission-denied') {
  1060. throw new Error('Permission denied for screen retrieval');
  1061. } else {
  1062. throw new Error('Failed retrieving selected screen');
  1063. }
  1064. }
  1065. };
  1066. var onIFrameCallback = function (event) {
  1067. if (!event.data) {
  1068. return;
  1069. }
  1070. if (event.data.chromeMediaSourceId) {
  1071. if (event.data.chromeMediaSourceId === 'PermissionDeniedError') {
  1072. chromeCallback('permission-denied');
  1073. } else {
  1074. chromeCallback(null, event.data.chromeMediaSourceId);
  1075. }
  1076. }
  1077. if (event.data.chromeExtensionStatus) {
  1078. if (event.data.chromeExtensionStatus === 'not-installed') {
  1079. AdapterJS.renderNotificationBar(AdapterJS.TEXT.EXTENSION.REQUIRE_INSTALLATION_CHROME,
  1080. AdapterJS.TEXT.EXTENSION.BUTTON_CHROME,
  1081. event.data.data, true, true);
  1082. } else {
  1083. chromeCallback(event.data.chromeExtensionStatus, null);
  1084. }
  1085. }
  1086. // this event listener is no more needed
  1087. window.removeEventListener('message', onIFrameCallback);
  1088. };
  1089. window.addEventListener('message', onIFrameCallback);
  1090. postFrameMessage({
  1091. captureSourceId: true
  1092. });
  1093. } else {
  1094. baseGetUserMedia(constraints, successCb, failureCb);
  1095. }
  1096. };
  1097. getUserMedia = navigator.getUserMedia;
  1098. } else {
  1099. baseGetUserMedia = window.navigator.getUserMedia;
  1100. navigator.getUserMedia = function (constraints, successCb, failureCb) {
  1101. if (constraints && constraints.video && !!constraints.video.mediaSource) {
  1102. // would be fine since no methods
  1103. var updatedConstraints = clone(constraints);
  1104. // wait for plugin to be ready
  1105. AdapterJS.WebRTCPlugin.callWhenPluginReady(function() {
  1106. // check if screensharing feature is available
  1107. if (!!AdapterJS.WebRTCPlugin.plugin.HasScreensharingFeature &&
  1108. !!AdapterJS.WebRTCPlugin.plugin.isScreensharingAvailable) {
  1109. // set the constraints
  1110. updatedConstraints.video.optional = updatedConstraints.video.optional || [];
  1111. updatedConstraints.video.optional.push({
  1112. sourceId: AdapterJS.WebRTCPlugin.plugin.screensharingKey || 'Screensharing'
  1113. });
  1114. delete updatedConstraints.video.mediaSource;
  1115. } else {
  1116. throw new Error('Your WebRTC plugin does not support screensharing');
  1117. }
  1118. baseGetUserMedia(updatedConstraints, successCb, failureCb);
  1119. });
  1120. } else {
  1121. baseGetUserMedia(constraints, successCb, failureCb);
  1122. }
  1123. };
  1124. getUserMedia = window.navigator.getUserMedia;
  1125. }
  1126. if (window.webrtcDetectedBrowser === 'chrome') {
  1127. var iframe = document.createElement('iframe');
  1128. iframe.onload = function() {
  1129. iframe.isLoaded = true;
  1130. };
  1131. iframe.src = 'https://cdn.temasys.com.sg/skylink/extensions/detectRTC.html';
  1132. //'https://temasys-cdn.s3.amazonaws.com/skylink/extensions/detection-script-dev/detectRTC.html';
  1133. iframe.style.display = 'none';
  1134. (document.body || document.documentElement).appendChild(iframe);
  1135. var postFrameMessage = function (object) {
  1136. object = object || {};
  1137. if (!iframe.isLoaded) {
  1138. setTimeout(function () {
  1139. iframe.contentWindow.postMessage(object, '*');
  1140. }, 100);
  1141. return;
  1142. }
  1143. iframe.contentWindow.postMessage(object, '*');
  1144. };
  1145. }
  1146. })();