@nethesis/phone-island 0.7.7 → 0.7.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/package.json +21 -3
  2. package/dist/App.d.ts +0 -6
  3. package/dist/App.js +0 -2
  4. package/dist/App.js.map +0 -1
  5. package/dist/_virtual/_rollupPluginBabelHelpers.js +0 -2
  6. package/dist/_virtual/_rollupPluginBabelHelpers.js.map +0 -1
  7. package/dist/_virtual/sdp.js +0 -2
  8. package/dist/_virtual/sdp.js.map +0 -1
  9. package/dist/components/index.d.ts +0 -1
  10. package/dist/components/index.js +0 -2
  11. package/dist/components/index.js.map +0 -1
  12. package/dist/index.css +0 -1
  13. package/dist/index.d.ts +0 -1
  14. package/dist/index.js +0 -2
  15. package/dist/index.js.map +0 -1
  16. package/dist/lib/janus.js +0 -2
  17. package/dist/lib/janus.js.map +0 -1
  18. package/dist/node_modules/@socket.io/component-emitter/index.mjs.js +0 -2
  19. package/dist/node_modules/@socket.io/component-emitter/index.mjs.js.map +0 -1
  20. package/dist/node_modules/engine.io-client/build/esm/contrib/has-cors.js +0 -2
  21. package/dist/node_modules/engine.io-client/build/esm/contrib/has-cors.js.map +0 -1
  22. package/dist/node_modules/engine.io-client/build/esm/contrib/parseqs.js +0 -2
  23. package/dist/node_modules/engine.io-client/build/esm/contrib/parseqs.js.map +0 -1
  24. package/dist/node_modules/engine.io-client/build/esm/contrib/parseuri.js +0 -2
  25. package/dist/node_modules/engine.io-client/build/esm/contrib/parseuri.js.map +0 -1
  26. package/dist/node_modules/engine.io-client/build/esm/contrib/yeast.js +0 -2
  27. package/dist/node_modules/engine.io-client/build/esm/contrib/yeast.js.map +0 -1
  28. package/dist/node_modules/engine.io-client/build/esm/globalThis.browser.js +0 -2
  29. package/dist/node_modules/engine.io-client/build/esm/globalThis.browser.js.map +0 -1
  30. package/dist/node_modules/engine.io-client/build/esm/index.js +0 -2
  31. package/dist/node_modules/engine.io-client/build/esm/index.js.map +0 -1
  32. package/dist/node_modules/engine.io-client/build/esm/socket.js +0 -2
  33. package/dist/node_modules/engine.io-client/build/esm/socket.js.map +0 -1
  34. package/dist/node_modules/engine.io-client/build/esm/transport.js +0 -2
  35. package/dist/node_modules/engine.io-client/build/esm/transport.js.map +0 -1
  36. package/dist/node_modules/engine.io-client/build/esm/transports/index.js +0 -2
  37. package/dist/node_modules/engine.io-client/build/esm/transports/index.js.map +0 -1
  38. package/dist/node_modules/engine.io-client/build/esm/transports/polling.js +0 -2
  39. package/dist/node_modules/engine.io-client/build/esm/transports/polling.js.map +0 -1
  40. package/dist/node_modules/engine.io-client/build/esm/transports/websocket-constructor.browser.js +0 -2
  41. package/dist/node_modules/engine.io-client/build/esm/transports/websocket-constructor.browser.js.map +0 -1
  42. package/dist/node_modules/engine.io-client/build/esm/transports/websocket.js +0 -2
  43. package/dist/node_modules/engine.io-client/build/esm/transports/websocket.js.map +0 -1
  44. package/dist/node_modules/engine.io-client/build/esm/transports/xmlhttprequest.browser.js +0 -2
  45. package/dist/node_modules/engine.io-client/build/esm/transports/xmlhttprequest.browser.js.map +0 -1
  46. package/dist/node_modules/engine.io-client/build/esm/util.js +0 -2
  47. package/dist/node_modules/engine.io-client/build/esm/util.js.map +0 -1
  48. package/dist/node_modules/engine.io-parser/build/esm/commons.js +0 -2
  49. package/dist/node_modules/engine.io-parser/build/esm/commons.js.map +0 -1
  50. package/dist/node_modules/engine.io-parser/build/esm/contrib/base64-arraybuffer.js +0 -2
  51. package/dist/node_modules/engine.io-parser/build/esm/contrib/base64-arraybuffer.js.map +0 -1
  52. package/dist/node_modules/engine.io-parser/build/esm/decodePacket.browser.js +0 -2
  53. package/dist/node_modules/engine.io-parser/build/esm/decodePacket.browser.js.map +0 -1
  54. package/dist/node_modules/engine.io-parser/build/esm/encodePacket.browser.js +0 -2
  55. package/dist/node_modules/engine.io-parser/build/esm/encodePacket.browser.js.map +0 -1
  56. package/dist/node_modules/engine.io-parser/build/esm/index.js +0 -2
  57. package/dist/node_modules/engine.io-parser/build/esm/index.js.map +0 -1
  58. package/dist/node_modules/sdp/sdp.js +0 -2
  59. package/dist/node_modules/sdp/sdp.js.map +0 -1
  60. package/dist/node_modules/socket.io-client/build/esm/contrib/backo2.js +0 -2
  61. package/dist/node_modules/socket.io-client/build/esm/contrib/backo2.js.map +0 -1
  62. package/dist/node_modules/socket.io-client/build/esm/index.js +0 -2
  63. package/dist/node_modules/socket.io-client/build/esm/index.js.map +0 -1
  64. package/dist/node_modules/socket.io-client/build/esm/manager.js +0 -2
  65. package/dist/node_modules/socket.io-client/build/esm/manager.js.map +0 -1
  66. package/dist/node_modules/socket.io-client/build/esm/on.js +0 -2
  67. package/dist/node_modules/socket.io-client/build/esm/on.js.map +0 -1
  68. package/dist/node_modules/socket.io-client/build/esm/socket.js +0 -2
  69. package/dist/node_modules/socket.io-client/build/esm/socket.js.map +0 -1
  70. package/dist/node_modules/socket.io-client/build/esm/url.js +0 -2
  71. package/dist/node_modules/socket.io-client/build/esm/url.js.map +0 -1
  72. package/dist/node_modules/socket.io-parser/build/esm/binary.js +0 -2
  73. package/dist/node_modules/socket.io-parser/build/esm/binary.js.map +0 -1
  74. package/dist/node_modules/socket.io-parser/build/esm/index.js +0 -2
  75. package/dist/node_modules/socket.io-parser/build/esm/index.js.map +0 -1
  76. package/dist/node_modules/socket.io-parser/build/esm/is-binary.js +0 -2
  77. package/dist/node_modules/socket.io-parser/build/esm/is-binary.js.map +0 -1
  78. package/dist/node_modules/tslib/tslib.es6.js +0 -2
  79. package/dist/node_modules/tslib/tslib.es6.js.map +0 -1
  80. package/dist/node_modules/webrtc-adapter/src/js/adapter_core.js +0 -2
  81. package/dist/node_modules/webrtc-adapter/src/js/adapter_core.js.map +0 -1
  82. package/dist/node_modules/webrtc-adapter/src/js/adapter_factory.js +0 -2
  83. package/dist/node_modules/webrtc-adapter/src/js/adapter_factory.js.map +0 -1
  84. package/dist/node_modules/webrtc-adapter/src/js/chrome/chrome_shim.js +0 -2
  85. package/dist/node_modules/webrtc-adapter/src/js/chrome/chrome_shim.js.map +0 -1
  86. package/dist/node_modules/webrtc-adapter/src/js/chrome/getdisplaymedia.js +0 -2
  87. package/dist/node_modules/webrtc-adapter/src/js/chrome/getdisplaymedia.js.map +0 -1
  88. package/dist/node_modules/webrtc-adapter/src/js/chrome/getusermedia.js +0 -2
  89. package/dist/node_modules/webrtc-adapter/src/js/chrome/getusermedia.js.map +0 -1
  90. package/dist/node_modules/webrtc-adapter/src/js/common_shim.js +0 -2
  91. package/dist/node_modules/webrtc-adapter/src/js/common_shim.js.map +0 -1
  92. package/dist/node_modules/webrtc-adapter/src/js/firefox/firefox_shim.js +0 -2
  93. package/dist/node_modules/webrtc-adapter/src/js/firefox/firefox_shim.js.map +0 -1
  94. package/dist/node_modules/webrtc-adapter/src/js/firefox/getdisplaymedia.js +0 -2
  95. package/dist/node_modules/webrtc-adapter/src/js/firefox/getdisplaymedia.js.map +0 -1
  96. package/dist/node_modules/webrtc-adapter/src/js/firefox/getusermedia.js +0 -2
  97. package/dist/node_modules/webrtc-adapter/src/js/firefox/getusermedia.js.map +0 -1
  98. package/dist/node_modules/webrtc-adapter/src/js/safari/safari_shim.js +0 -2
  99. package/dist/node_modules/webrtc-adapter/src/js/safari/safari_shim.js.map +0 -1
  100. package/dist/node_modules/webrtc-adapter/src/js/utils.js +0 -2
  101. package/dist/node_modules/webrtc-adapter/src/js/utils.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"janus.js","sources":["../../src/lib/janus.js"],"sourcesContent":["\"use strict\";\n\n/*\n\tThe MIT License (MIT)\n\n\tCopyright (c) 2016 Meetecho\n\n\tPermission is hereby granted, free of charge, to any person obtaining\n\ta copy of this software and associated documentation files (the \"Software\"),\n\tto deal in the Software without restriction, including without limitation\n\tthe rights to use, copy, modify, merge, publish, distribute, sublicense,\n\tand/or sell copies of the Software, and to permit persons to whom the\n\tSoftware is furnished to do so, subject to the following conditions:\n\n\tThe above copyright notice and this permission notice shall be included\n\tin all copies or substantial portions of the Software.\n\n\tTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n\tOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n\tFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n\tTHE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR\n\tOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\n\tARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n\tOTHER DEALINGS IN THE SOFTWARE.\n */\n\n// List of sessions\nJanus.sessions = {};\n\nJanus.isExtensionEnabled = function() {\n\tif(navigator.mediaDevices && navigator.mediaDevices.getDisplayMedia) {\n\t\t// No need for the extension, getDisplayMedia is supported\n\t\treturn true;\n\t}\n\tif(window.navigator.userAgent.match('Chrome')) {\n\t\tvar chromever = parseInt(window.navigator.userAgent.match(/Chrome\\/(.*) /)[1], 10);\n\t\tvar maxver = 33;\n\t\tif(window.navigator.userAgent.match('Linux'))\n\t\t\tmaxver = 35;\t// \"known\" crash in chrome 34 and 35 on linux\n\t\tif(chromever >= 26 && chromever <= maxver) {\n\t\t\t// Older versions of Chrome don't support this extension-based approach, so lie\n\t\t\treturn true;\n\t\t}\n\t\treturn Janus.extension.isInstalled();\n\t} else {\n\t\t// Firefox and others, no need for the extension (but this doesn't mean it will work)\n\t\treturn true;\n\t}\n};\n\nvar defaultExtension = {\n\t// Screensharing Chrome Extension ID\n\textensionId: 'hapfgfdkleiggjjpfpenajgdnfckjpaj',\n\tisInstalled: function() { return document.querySelector('#janus-extension-installed') !== null; },\n\tgetScreen: function (callback) {\n\t\tvar pending = window.setTimeout(function () {\n\t\t\tvar error = new Error('NavigatorUserMediaError');\n\t\t\terror.name = 'The required Chrome extension is not installed: click <a href=\"#\">here</a> to install it. (NOTE: this will need you to refresh the page)';\n\t\t\treturn callback(error);\n\t\t}, 1000);\n\t\tthis.cache[pending] = callback;\n\t\twindow.postMessage({ type: 'janusGetScreen', id: pending }, '*');\n\t},\n\tinit: function () {\n\t\tvar cache = {};\n\t\tthis.cache = cache;\n\t\t// Wait for events from the Chrome Extension\n\t\twindow.addEventListener('message', function (event) {\n\t\t\tif(event.origin != window.location.origin)\n\t\t\t\treturn;\n\t\t\tif(event.data.type == 'janusGotScreen' && cache[event.data.id]) {\n\t\t\t\tvar callback = cache[event.data.id];\n\t\t\t\tdelete cache[event.data.id];\n\n\t\t\t\tif (event.data.sourceId === '') {\n\t\t\t\t\t// user canceled\n\t\t\t\t\tvar error = new Error('NavigatorUserMediaError');\n\t\t\t\t\terror.name = 'You cancelled the request for permission, giving up...';\n\t\t\t\t\tcallback(error);\n\t\t\t\t} else {\n\t\t\t\t\tcallback(null, event.data.sourceId);\n\t\t\t\t}\n\t\t\t} else if (event.data.type == 'janusGetScreenPending') {\n\t\t\t\tconsole.log('clearing ', event.data.id);\n\t\t\t\twindow.clearTimeout(event.data.id);\n\t\t\t}\n\t\t});\n\t}\n};\n\nJanus.useDefaultDependencies = function (deps) {\n\tvar f = (deps && deps.fetch) || fetch;\n\tvar p = (deps && deps.Promise) || Promise;\n\tvar socketCls = (deps && deps.WebSocket) || WebSocket;\n\n\treturn {\n\t\tnewWebSocket: function(server, proto) { return new socketCls(server, proto); },\n\t\textension: (deps && deps.extension) || defaultExtension,\n\t\tisArray: function(arr) { return Array.isArray(arr); },\n\t\twebRTCAdapter: (deps && deps.adapter) || adapter,\n\t\thttpAPICall: function(url, options) {\n\t\t\tvar fetchOptions = {\n\t\t\t\tmethod: options.verb,\n\t\t\t\theaders: {\n\t\t\t\t\t'Accept': 'application/json, text/plain, */*'\n\t\t\t\t},\n\t\t\t\tcache: 'no-cache'\n\t\t\t};\n\t\t\tif(options.verb === \"POST\") {\n\t\t\t\tfetchOptions.headers['Content-Type'] = 'application/json';\n\t\t\t}\n\t\t\tif(options.withCredentials !== undefined) {\n\t\t\t\tfetchOptions.credentials = options.withCredentials === true ? 'include' : (options.withCredentials ? options.withCredentials : 'omit');\n\t\t\t}\n\t\t\tif(options.body) {\n\t\t\t\tfetchOptions.body = JSON.stringify(options.body);\n\t\t\t}\n\n\t\t\tvar fetching = f(url, fetchOptions).catch(function(error) {\n\t\t\t\treturn p.reject({message: 'Probably a network error, is the server down?', error: error});\n\t\t\t});\n\n\t\t\t/*\n\t\t\t * fetch() does not natively support timeouts.\n\t\t\t * Work around this by starting a timeout manually, and racing it agains the fetch() to see which thing resolves first.\n\t\t\t */\n\n\t\t\tif(options.timeout) {\n\t\t\t\tvar timeout = new p(function(resolve, reject) {\n\t\t\t\t\tvar timerId = setTimeout(function() {\n\t\t\t\t\t\tclearTimeout(timerId);\n\t\t\t\t\t\treturn reject({message: 'Request timed out', timeout: options.timeout});\n\t\t\t\t\t}, options.timeout);\n\t\t\t\t});\n\t\t\t\tfetching = p.race([fetching, timeout]);\n\t\t\t}\n\n\t\t\tfetching.then(function(response) {\n\t\t\t\tif(response.ok) {\n\t\t\t\t\tif(typeof(options.success) === typeof(Janus.noop)) {\n\t\t\t\t\t\treturn response.json().then(function(parsed) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\toptions.success(parsed);\n\t\t\t\t\t\t\t} catch(error) {\n\t\t\t\t\t\t\t\tJanus.error('Unhandled httpAPICall success callback error', error);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}, function(error) {\n\t\t\t\t\t\t\treturn p.reject({message: 'Failed to parse response body', error: error, response: response});\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn p.reject({message: 'API call failed', response: response});\n\t\t\t\t}\n\t\t\t}).catch(function(error) {\n\t\t\t\tif(typeof(options.error) === typeof(Janus.noop)) {\n\t\t\t\t\toptions.error(error.message || '<< internal error >>', error);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\treturn fetching;\n\t\t}\n\t}\n};\n\nJanus.useOldDependencies = function (deps) {\n\tvar jq = (deps && deps.jQuery) || jQuery;\n\tvar socketCls = (deps && deps.WebSocket) || WebSocket;\n\treturn {\n\t\tnewWebSocket: function(server, proto) { return new socketCls(server, proto); },\n\t\tisArray: function(arr) { return jq.isArray(arr); },\n\t\textension: (deps && deps.extension) || defaultExtension,\n\t\twebRTCAdapter: (deps && deps.adapter) || adapter,\n\t\thttpAPICall: function(url, options) {\n\t\t\tvar payload = options.body !== undefined ? {\n\t\t\t\tcontentType: 'application/json',\n\t\t\t\tdata: JSON.stringify(options.body)\n\t\t\t} : {};\n\t\t\tvar credentials = options.withCredentials !== undefined ? {xhrFields: {withCredentials: options.withCredentials}} : {};\n\n\t\t\treturn jq.ajax(jq.extend(payload, credentials, {\n\t\t\t\turl: url,\n\t\t\t\ttype: options.verb,\n\t\t\t\tcache: false,\n\t\t\t\tdataType: 'json',\n\t\t\t\tasync: options.async,\n\t\t\t\ttimeout: options.timeout,\n\t\t\t\tsuccess: function(result) {\n\t\t\t\t\tif(typeof(options.success) === typeof(Janus.noop)) {\n\t\t\t\t\t\toptions.success(result);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\terror: function(xhr, status, err) {\n\t\t\t\t\tif(typeof(options.error) === typeof(Janus.noop)) {\n\t\t\t\t\t\toptions.error(status, err);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}));\n\t\t}\n\t};\n};\n\nJanus.noop = function() {};\n\nJanus.dataChanDefaultLabel = \"JanusDataChannel\";\n\n// Note: in the future we may want to change this, e.g., as was\n// attempted in https://github.com/meetecho/janus-gateway/issues/1670\nJanus.endOfCandidates = null;\n\n// Stop all tracks from a given stream\nJanus.stopAllTracks = function(stream) {\n\ttry {\n\t\t// Try a MediaStreamTrack.stop() for each track\n\t\tvar tracks = stream.getTracks();\n\t\tfor(var mst of tracks) {\n\t\t\tJanus.log(mst);\n\t\t\tif(mst) {\n\t\t\t\tmst.stop();\n\t\t\t}\n\t\t}\n\t} catch(e) {\n\t\t// Do nothing if this fails\n\t}\n}\n\n// Initialization\nJanus.init = function(options) {\n\toptions = options || {};\n\toptions.callback = (typeof options.callback == \"function\") ? options.callback : Janus.noop;\n\tif(Janus.initDone) {\n\t\t// Already initialized\n\t\toptions.callback();\n\t} else {\n\t\tif(typeof console.log == \"undefined\") {\n\t\t\tconsole.log = function() {};\n\t\t}\n\t\t// Console logging (all debugging disabled by default)\n\t\tJanus.trace = Janus.noop;\n\t\tJanus.debug = Janus.noop;\n\t\tJanus.vdebug = Janus.noop;\n\t\tJanus.log = Janus.noop;\n\t\tJanus.warn = Janus.noop;\n\t\tJanus.error = Janus.noop;\n\t\tif(options.debug === true || options.debug === \"all\") {\n\t\t\t// Enable all debugging levels\n\t\t\tJanus.trace = console.trace.bind(console);\n\t\t\tJanus.debug = console.debug.bind(console);\n\t\t\tJanus.vdebug = console.debug.bind(console);\n\t\t\tJanus.log = console.log.bind(console);\n\t\t\tJanus.warn = console.warn.bind(console);\n\t\t\tJanus.error = console.error.bind(console);\n\t\t} else if(Array.isArray(options.debug)) {\n\t\t\tfor(var d of options.debug) {\n\t\t\t\tswitch(d) {\n\t\t\t\t\tcase \"trace\":\n\t\t\t\t\t\tJanus.trace = console.trace.bind(console);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"debug\":\n\t\t\t\t\t\tJanus.debug = console.debug.bind(console);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"vdebug\":\n\t\t\t\t\t\tJanus.vdebug = console.debug.bind(console);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"log\":\n\t\t\t\t\t\tJanus.log = console.log.bind(console);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"warn\":\n\t\t\t\t\t\tJanus.warn = console.warn.bind(console);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"error\":\n\t\t\t\t\t\tJanus.error = console.error.bind(console);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tconsole.error(\"Unknown debugging option '\" + d + \"' (supported: 'trace', 'debug', 'vdebug', 'log', warn', 'error')\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tJanus.log(\"Initializing library\");\n\n\t\tvar usedDependencies = options.dependencies || Janus.useDefaultDependencies();\n\t\tJanus.isArray = usedDependencies.isArray;\n\t\tJanus.webRTCAdapter = usedDependencies.webRTCAdapter;\n\t\tJanus.httpAPICall = usedDependencies.httpAPICall;\n\t\tJanus.newWebSocket = usedDependencies.newWebSocket;\n\t\tJanus.extension = usedDependencies.extension;\n\t\tJanus.extension.init();\n\n\t\t// Helper method to enumerate devices\n\t\tJanus.listDevices = function(callback, config) {\n\t\t\tcallback = (typeof callback == \"function\") ? callback : Janus.noop;\n\t\t\tif (config == null) config = { audio: true, video: true };\n\t\t\tif(Janus.isGetUserMediaAvailable()) {\n\t\t\t\tnavigator.mediaDevices.getUserMedia(config)\n\t\t\t\t.then(function(stream) {\n\t\t\t\t\tnavigator.mediaDevices.enumerateDevices().then(function(devices) {\n\t\t\t\t\t\tJanus.debug(devices);\n\t\t\t\t\t\tcallback(devices);\n\t\t\t\t\t\t// Get rid of the now useless stream\n\t\t\t\t\t\tJanus.stopAllTracks(stream)\n\t\t\t\t\t});\n\t\t\t\t})\n\t\t\t\t.catch(function(err) {\n\t\t\t\t\tJanus.error(err);\n\t\t\t\t\tcallback([]);\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tJanus.warn(\"navigator.mediaDevices unavailable\");\n\t\t\t\tcallback([]);\n\t\t\t}\n\t\t};\n\t\t// Helper methods to attach/reattach a stream to a video element (previously part of adapter.js)\n\t\tJanus.attachMediaStream = function(element, stream) {\n\t\t\ttry {\n\t\t\t\telement.srcObject = stream;\n\t\t\t} catch (e) {\n\t\t\t\ttry {\n\t\t\t\t\telement.src = URL.createObjectURL(stream);\n\t\t\t\t} catch (e) {\n\t\t\t\t\tJanus.error(\"Error attaching stream to element\");\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tJanus.reattachMediaStream = function(to, from) {\n\t\t\ttry {\n\t\t\t\tto.srcObject = from.srcObject;\n\t\t\t} catch (e) {\n\t\t\t\ttry {\n\t\t\t\t\tto.src = from.src;\n\t\t\t\t} catch (e) {\n\t\t\t\t\tJanus.error(\"Error reattaching stream to element\");\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\t// Detect tab close: make sure we don't loose existing onbeforeunload handlers\n\t\t// (note: for iOS we need to subscribe to a different event, 'pagehide', see\n\t\t// https://gist.github.com/thehunmonkgroup/6bee8941a49b86be31a787fe8f4b8cfe)\n\t\tvar iOS = ['iPad', 'iPhone', 'iPod'].indexOf(navigator.platform) >= 0;\n\t\tvar eventName = iOS ? 'pagehide' : 'beforeunload';\n\t\tvar oldOBF = window[\"on\" + eventName];\n\t\twindow.addEventListener(eventName, function() {\n\t\t\tJanus.log(\"Closing window\");\n\t\t\tfor(var s in Janus.sessions) {\n\t\t\t\tif(Janus.sessions[s] && Janus.sessions[s].destroyOnUnload) {\n\t\t\t\t\tJanus.log(\"Destroying session \" + s);\n\t\t\t\t\tJanus.sessions[s].destroy({unload: true, notifyDestroyed: false});\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(oldOBF && typeof oldOBF == \"function\") {\n\t\t\t\toldOBF();\n\t\t\t}\n\t\t});\n\t\t// If this is a Safari Technology Preview, check if VP8 is supported\n\t\tJanus.safariVp8 = false;\n\t\tif(Janus.webRTCAdapter.browserDetails.browser === 'safari' &&\n\t\t\t\tJanus.webRTCAdapter.browserDetails.version >= 605) {\n\t\t\t// Let's see if RTCRtpSender.getCapabilities() is there\n\t\t\tif(RTCRtpSender && RTCRtpSender.getCapabilities && RTCRtpSender.getCapabilities(\"video\") &&\n\t\t\t\t\tRTCRtpSender.getCapabilities(\"video\").codecs && RTCRtpSender.getCapabilities(\"video\").codecs.length) {\n\t\t\t\tfor(var codec of RTCRtpSender.getCapabilities(\"video\").codecs) {\n\t\t\t\t\tif(codec && codec.mimeType && codec.mimeType.toLowerCase() === \"video/vp8\") {\n\t\t\t\t\t\tJanus.safariVp8 = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(Janus.safariVp8) {\n\t\t\t\t\tJanus.log(\"This version of Safari supports VP8\");\n\t\t\t\t} else {\n\t\t\t\t\tJanus.warn(\"This version of Safari does NOT support VP8: if you're using a Technology Preview, \" +\n\t\t\t\t\t\t\"try enabling the 'WebRTC VP8 codec' setting in the 'Experimental Features' Develop menu\");\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// We do it in a very ugly way, as there's no alternative...\n\t\t\t\t// We create a PeerConnection to see if VP8 is in an offer\n\t\t\t\tvar testpc = new RTCPeerConnection({});\n\t\t\t\ttestpc.createOffer({offerToReceiveVideo: true}).then(function(offer) {\n\t\t\t\t\tJanus.safariVp8 = offer.sdp.indexOf(\"VP8\") !== -1;\n\t\t\t\t\tif(Janus.safariVp8) {\n\t\t\t\t\t\tJanus.log(\"This version of Safari supports VP8\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tJanus.warn(\"This version of Safari does NOT support VP8: if you're using a Technology Preview, \" +\n\t\t\t\t\t\t\t\"try enabling the 'WebRTC VP8 codec' setting in the 'Experimental Features' Develop menu\");\n\t\t\t\t\t}\n\t\t\t\t\ttestpc.close();\n\t\t\t\t\ttestpc = null;\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\t// Check if this browser supports Unified Plan and transceivers\n\t\t// Based on https://codepen.io/anon/pen/ZqLwWV?editors=0010\n\t\tJanus.unifiedPlan = false;\n\t\tif(Janus.webRTCAdapter.browserDetails.browser === 'firefox' &&\n\t\t\t\tJanus.webRTCAdapter.browserDetails.version >= 59) {\n\t\t\t// Firefox definitely does, starting from version 59\n\t\t\tJanus.unifiedPlan = true;\n\t\t} else if(Janus.webRTCAdapter.browserDetails.browser === 'chrome' &&\n\t\t\t\tJanus.webRTCAdapter.browserDetails.version >= 72) {\n\t\t\t// Chrome does, but it's only usable from version 72 on\n\t\t\tJanus.unifiedPlan = true;\n\t\t} else if(!window.RTCRtpTransceiver || !('currentDirection' in RTCRtpTransceiver.prototype)) {\n\t\t\t// Safari supports addTransceiver() but not Unified Plan when\n\t\t\t// currentDirection is not defined (see codepen above).\n\t\t\tJanus.unifiedPlan = false;\n\t\t} else {\n\t\t\t// Check if addTransceiver() throws an exception\n\t\t\tvar tempPc = new RTCPeerConnection();\n\t\t\ttry {\n\t\t\t\ttempPc.addTransceiver('audio');\n\t\t\t\tJanus.unifiedPlan = true;\n\t\t\t} catch (e) {}\n\t\t\ttempPc.close();\n\t\t}\n\t\tJanus.initDone = true;\n\t\toptions.callback();\n\t}\n};\n\n// Helper method to check whether WebRTC is supported by this browser\nJanus.isWebrtcSupported = function() {\n\treturn !!window.RTCPeerConnection;\n};\n// Helper method to check whether devices can be accessed by this browser (e.g., not possible via plain HTTP)\nJanus.isGetUserMediaAvailable = function() {\n\treturn navigator.mediaDevices && navigator.mediaDevices.getUserMedia;\n};\n\n// Helper method to create random identifiers (e.g., transaction)\nJanus.randomString = function(len) {\n\tvar charSet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\n\tvar randomString = '';\n\tfor (var i = 0; i < len; i++) {\n\t\tvar randomPoz = Math.floor(Math.random() * charSet.length);\n\t\trandomString += charSet.substring(randomPoz,randomPoz+1);\n\t}\n\treturn randomString;\n};\n\nfunction Janus(gatewayCallbacks) {\n\tgatewayCallbacks = gatewayCallbacks || {};\n\tgatewayCallbacks.success = (typeof gatewayCallbacks.success == \"function\") ? gatewayCallbacks.success : Janus.noop;\n\tgatewayCallbacks.error = (typeof gatewayCallbacks.error == \"function\") ? gatewayCallbacks.error : Janus.noop;\n\tgatewayCallbacks.destroyed = (typeof gatewayCallbacks.destroyed == \"function\") ? gatewayCallbacks.destroyed : Janus.noop;\n\tif(!Janus.initDone) {\n\t\tgatewayCallbacks.error(\"Library not initialized\");\n\t\treturn {};\n\t}\n\tif(!Janus.isWebrtcSupported()) {\n\t\tgatewayCallbacks.error(\"WebRTC not supported by this browser\");\n\t\treturn {};\n\t}\n\tJanus.log(\"Library initialized: \" + Janus.initDone);\n\tif(!gatewayCallbacks.server) {\n\t\tgatewayCallbacks.error(\"Invalid server url\");\n\t\treturn {};\n\t}\n\tvar websockets = false;\n\tvar ws = null;\n\tvar wsHandlers = {};\n\tvar wsKeepaliveTimeoutId = null;\n\tvar servers = null;\n\tvar serversIndex = 0;\n\tvar server = gatewayCallbacks.server;\n\tif(Janus.isArray(server)) {\n\t\tJanus.log(\"Multiple servers provided (\" + server.length + \"), will use the first that works\");\n\t\tserver = null;\n\t\tservers = gatewayCallbacks.server;\n\t\tJanus.debug(servers);\n\t} else {\n\t\tif(server.indexOf(\"ws\") === 0) {\n\t\t\twebsockets = true;\n\t\t\tJanus.log(\"Using WebSockets to contact Janus: \" + server);\n\t\t} else {\n\t\t\twebsockets = false;\n\t\t\tJanus.log(\"Using REST API to contact Janus: \" + server);\n\t\t}\n\t}\n\tvar iceServers = gatewayCallbacks.iceServers || [{urls: \"stun:stun.l.google.com:19302\"}];\n\tvar iceTransportPolicy = gatewayCallbacks.iceTransportPolicy;\n\tvar bundlePolicy = gatewayCallbacks.bundlePolicy;\n\t// Whether IPv6 candidates should be gathered\n\tvar ipv6Support = (gatewayCallbacks.ipv6 === true);\n\t// Whether we should enable the withCredentials flag for XHR requests\n\tvar withCredentials = false;\n\tif(gatewayCallbacks.withCredentials !== undefined && gatewayCallbacks.withCredentials !== null)\n\t\twithCredentials = gatewayCallbacks.withCredentials === true;\n\t// Optional max events\n\tvar maxev = 10;\n\tif(gatewayCallbacks.max_poll_events !== undefined && gatewayCallbacks.max_poll_events !== null)\n\t\tmaxev = gatewayCallbacks.max_poll_events;\n\tif(maxev < 1)\n\t\tmaxev = 1;\n\t// Token to use (only if the token based authentication mechanism is enabled)\n\tvar token = null;\n\tif(gatewayCallbacks.token !== undefined && gatewayCallbacks.token !== null)\n\t\ttoken = gatewayCallbacks.token;\n\t// API secret to use (only if the shared API secret is enabled)\n\tvar apisecret = null;\n\tif(gatewayCallbacks.apisecret !== undefined && gatewayCallbacks.apisecret !== null)\n\t\tapisecret = gatewayCallbacks.apisecret;\n\t// Whether we should destroy this session when onbeforeunload is called\n\tthis.destroyOnUnload = true;\n\tif(gatewayCallbacks.destroyOnUnload !== undefined && gatewayCallbacks.destroyOnUnload !== null)\n\t\tthis.destroyOnUnload = (gatewayCallbacks.destroyOnUnload === true);\n\t// Some timeout-related values\n\tvar keepAlivePeriod = 25000;\n\tif(gatewayCallbacks.keepAlivePeriod !== undefined && gatewayCallbacks.keepAlivePeriod !== null)\n\t\tkeepAlivePeriod = gatewayCallbacks.keepAlivePeriod;\n\tif(isNaN(keepAlivePeriod))\n\t\tkeepAlivePeriod = 25000;\n\tvar longPollTimeout = 60000;\n\tif(gatewayCallbacks.longPollTimeout !== undefined && gatewayCallbacks.longPollTimeout !== null)\n\t\tlongPollTimeout = gatewayCallbacks.longPollTimeout;\n\tif(isNaN(longPollTimeout))\n\t\tlongPollTimeout = 60000;\n\n\t// overrides for default maxBitrate values for simulcasting\n\tfunction getMaxBitrates(simulcastMaxBitrates) {\n\t\tvar maxBitrates = {\n\t\t\thigh: 900000,\n\t\t\tmedium: 300000,\n\t\t\tlow: 100000,\n\t\t};\n\n\t\tif (simulcastMaxBitrates !== undefined && simulcastMaxBitrates !== null) {\n\t\t\tif (simulcastMaxBitrates.high)\n\t\t\t\tmaxBitrates.high = simulcastMaxBitrates.high;\n\t\t\tif (simulcastMaxBitrates.medium)\n\t\t\t\tmaxBitrates.medium = simulcastMaxBitrates.medium;\n\t\t\tif (simulcastMaxBitrates.low)\n\t\t\t\tmaxBitrates.low = simulcastMaxBitrates.low;\n\t\t}\n\n\t\treturn maxBitrates;\n\t}\n\n\tvar connected = false;\n\tvar sessionId = null;\n\tvar pluginHandles = {};\n\tvar that = this;\n\tvar retries = 0;\n\tvar transactions = {};\n\tcreateSession(gatewayCallbacks);\n\n\t// Public methods\n\tthis.getServer = function() { return server; };\n\tthis.isConnected = function() { return connected; };\n\tthis.reconnect = function(callbacks) {\n\t\tcallbacks = callbacks || {};\n\t\tcallbacks.success = (typeof callbacks.success == \"function\") ? callbacks.success : Janus.noop;\n\t\tcallbacks.error = (typeof callbacks.error == \"function\") ? callbacks.error : Janus.noop;\n\t\tcallbacks[\"reconnect\"] = true;\n\t\tcreateSession(callbacks);\n\t};\n\tthis.getSessionId = function() { return sessionId; };\n\tthis.getInfo = function(callbacks) { getInfo(callbacks); };\n\tthis.destroy = function(callbacks) { destroySession(callbacks); };\n\tthis.attach = function(callbacks) { createHandle(callbacks); };\n\n\tfunction eventHandler() {\n\t\tif(sessionId == null)\n\t\t\treturn;\n\t\tJanus.debug('Long poll...');\n\t\tif(!connected) {\n\t\t\tJanus.warn(\"Is the server down? (connected=false)\");\n\t\t\treturn;\n\t\t}\n\t\tvar longpoll = server + \"/\" + sessionId + \"?rid=\" + new Date().getTime();\n\t\tif(maxev)\n\t\t\tlongpoll = longpoll + \"&maxev=\" + maxev;\n\t\tif(token)\n\t\t\tlongpoll = longpoll + \"&token=\" + encodeURIComponent(token);\n\t\tif(apisecret)\n\t\t\tlongpoll = longpoll + \"&apisecret=\" + encodeURIComponent(apisecret);\n\t\tJanus.httpAPICall(longpoll, {\n\t\t\tverb: 'GET',\n\t\t\twithCredentials: withCredentials,\n\t\t\tsuccess: handleEvent,\n\t\t\ttimeout: longPollTimeout,\n\t\t\terror: function(textStatus, errorThrown) {\n\t\t\t\tJanus.error(textStatus + \":\", errorThrown);\n\t\t\t\tretries++;\n\t\t\t\tif(retries > 3) {\n\t\t\t\t\t// Did we just lose the server? :-(\n\t\t\t\t\tconnected = false;\n\t\t\t\t\tgatewayCallbacks.error(\"Lost connection to the server (is it down?)\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\teventHandler();\n\t\t\t}\n\t\t});\n\t}\n\n\t// Private event handler: this will trigger plugin callbacks, if set\n\tfunction handleEvent(json, skipTimeout) {\n\t\tretries = 0;\n\t\tif(!websockets && sessionId !== undefined && sessionId !== null && skipTimeout !== true)\n\t\t\teventHandler();\n\t\tif(!websockets && Janus.isArray(json)) {\n\t\t\t// We got an array: it means we passed a maxev > 1, iterate on all objects\n\t\t\tfor(var i=0; i<json.length; i++) {\n\t\t\t\thandleEvent(json[i], true);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif(json[\"janus\"] === \"keepalive\") {\n\t\t\t// Nothing happened\n\t\t\tJanus.vdebug(\"Got a keepalive on session \" + sessionId);\n\t\t\treturn;\n\t\t} else if(json[\"janus\"] === \"server_info\") {\n\t\t\t// Just info on the Janus instance\n\t\t\tJanus.debug(\"Got info on the Janus instance\");\n\t\t\tJanus.debug(json);\n\t\t\tconst transaction = json[\"transaction\"];\n\t\t\tif(transaction) {\n\t\t\t\tconst reportSuccess = transactions[transaction];\n\t\t\t\tif(reportSuccess)\n\t\t\t\t\treportSuccess(json);\n\t\t\t\tdelete transactions[transaction];\n\t\t\t}\n\t\t\treturn;\n\t\t} else if(json[\"janus\"] === \"ack\") {\n\t\t\t// Just an ack, we can probably ignore\n\t\t\tJanus.debug(\"Got an ack on session \" + sessionId);\n\t\t\tJanus.debug(json);\n\t\t\tconst transaction = json[\"transaction\"];\n\t\t\tif(transaction) {\n\t\t\t\tconst reportSuccess = transactions[transaction];\n\t\t\t\tif(reportSuccess)\n\t\t\t\t\treportSuccess(json);\n\t\t\t\tdelete transactions[transaction];\n\t\t\t}\n\t\t\treturn;\n\t\t} else if(json[\"janus\"] === \"success\") {\n\t\t\t// Success!\n\t\t\tJanus.debug(\"Got a success on session \" + sessionId);\n\t\t\tJanus.debug(json);\n\t\t\tconst transaction = json[\"transaction\"];\n\t\t\tif(transaction) {\n\t\t\t\tconst reportSuccess = transactions[transaction];\n\t\t\t\tif(reportSuccess)\n\t\t\t\t\treportSuccess(json);\n\t\t\t\tdelete transactions[transaction];\n\t\t\t}\n\t\t\treturn;\n\t\t} else if(json[\"janus\"] === \"trickle\") {\n\t\t\t// We got a trickle candidate from Janus\n\t\t\tconst sender = json[\"sender\"];\n\t\t\tif(!sender) {\n\t\t\t\tJanus.warn(\"Missing sender...\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst pluginHandle = pluginHandles[sender];\n\t\t\tif(!pluginHandle) {\n\t\t\t\tJanus.debug(\"This handle is not attached to this session\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar candidate = json[\"candidate\"];\n\t\t\tJanus.debug(\"Got a trickled candidate on session \" + sessionId);\n\t\t\tJanus.debug(candidate);\n\t\t\tvar config = pluginHandle.webrtcStuff;\n\t\t\tif(config.pc && config.remoteSdp) {\n\t\t\t\t// Add candidate right now\n\t\t\t\tJanus.debug(\"Adding remote candidate:\", candidate);\n\t\t\t\tif(!candidate || candidate.completed === true) {\n\t\t\t\t\t// end-of-candidates\n\t\t\t\t\tconfig.pc.addIceCandidate(Janus.endOfCandidates);\n\t\t\t\t} else {\n\t\t\t\t\t// New candidate\n\t\t\t\t\tconfig.pc.addIceCandidate(candidate);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// We didn't do setRemoteDescription (trickle got here before the offer?)\n\t\t\t\tJanus.debug(\"We didn't do setRemoteDescription (trickle got here before the offer?), caching candidate\");\n\t\t\t\tif(!config.candidates)\n\t\t\t\t\tconfig.candidates = [];\n\t\t\t\tconfig.candidates.push(candidate);\n\t\t\t\tJanus.debug(config.candidates);\n\t\t\t}\n\t\t} else if(json[\"janus\"] === \"webrtcup\") {\n\t\t\t// The PeerConnection with the server is up! Notify this\n\t\t\tJanus.debug(\"Got a webrtcup event on session \" + sessionId);\n\t\t\tJanus.debug(json);\n\t\t\tconst sender = json[\"sender\"];\n\t\t\tif(!sender) {\n\t\t\t\tJanus.warn(\"Missing sender...\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst pluginHandle = pluginHandles[sender];\n\t\t\tif(!pluginHandle) {\n\t\t\t\tJanus.debug(\"This handle is not attached to this session\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tpluginHandle.webrtcState(true);\n\t\t\treturn;\n\t\t} else if(json[\"janus\"] === \"hangup\") {\n\t\t\t// A plugin asked the core to hangup a PeerConnection on one of our handles\n\t\t\tJanus.debug(\"Got a hangup event on session \" + sessionId);\n\t\t\tJanus.debug(json);\n\t\t\tconst sender = json[\"sender\"];\n\t\t\tif(!sender) {\n\t\t\t\tJanus.warn(\"Missing sender...\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst pluginHandle = pluginHandles[sender];\n\t\t\tif(!pluginHandle) {\n\t\t\t\tJanus.debug(\"This handle is not attached to this session\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tpluginHandle.webrtcState(false, json[\"reason\"]);\n\t\t\tpluginHandle.hangup();\n\t\t} else if(json[\"janus\"] === \"detached\") {\n\t\t\t// A plugin asked the core to detach one of our handles\n\t\t\tJanus.debug(\"Got a detached event on session \" + sessionId);\n\t\t\tJanus.debug(json);\n\t\t\tconst sender = json[\"sender\"];\n\t\t\tif(!sender) {\n\t\t\t\tJanus.warn(\"Missing sender...\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst pluginHandle = pluginHandles[sender];\n\t\t\tif(!pluginHandle) {\n\t\t\t\t// Don't warn here because destroyHandle causes this situation.\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tpluginHandle.ondetached();\n\t\t\tpluginHandle.detach();\n\t\t} else if(json[\"janus\"] === \"media\") {\n\t\t\t// Media started/stopped flowing\n\t\t\tJanus.debug(\"Got a media event on session \" + sessionId);\n\t\t\tJanus.debug(json);\n\t\t\tconst sender = json[\"sender\"];\n\t\t\tif(!sender) {\n\t\t\t\tJanus.warn(\"Missing sender...\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst pluginHandle = pluginHandles[sender];\n\t\t\tif(!pluginHandle) {\n\t\t\t\tJanus.debug(\"This handle is not attached to this session\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tpluginHandle.mediaState(json[\"type\"], json[\"receiving\"]);\n\t\t} else if(json[\"janus\"] === \"slowlink\") {\n\t\t\tJanus.debug(\"Got a slowlink event on session \" + sessionId);\n\t\t\tJanus.debug(json);\n\t\t\t// Trouble uplink or downlink\n\t\t\tconst sender = json[\"sender\"];\n\t\t\tif(!sender) {\n\t\t\t\tJanus.warn(\"Missing sender...\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst pluginHandle = pluginHandles[sender];\n\t\t\tif(!pluginHandle) {\n\t\t\t\tJanus.debug(\"This handle is not attached to this session\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tpluginHandle.slowLink(json[\"uplink\"], json[\"lost\"]);\n\t\t} else if(json[\"janus\"] === \"error\") {\n\t\t\t// Oops, something wrong happened\n\t\t\tJanus.error(\"Ooops: \" + json[\"error\"].code + \" \" + json[\"error\"].reason);\t// FIXME\n\t\t\tJanus.debug(json);\n\t\t\tvar transaction = json[\"transaction\"];\n\t\t\tif(transaction) {\n\t\t\t\tvar reportSuccess = transactions[transaction];\n\t\t\t\tif(reportSuccess) {\n\t\t\t\t\treportSuccess(json);\n\t\t\t\t}\n\t\t\t\tdelete transactions[transaction];\n\t\t\t}\n\t\t\treturn;\n\t\t} else if(json[\"janus\"] === \"event\") {\n\t\t\tJanus.debug(\"Got a plugin event on session \" + sessionId);\n\t\t\tJanus.debug(json);\n\t\t\tconst sender = json[\"sender\"];\n\t\t\tif(!sender) {\n\t\t\t\tJanus.warn(\"Missing sender...\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar plugindata = json[\"plugindata\"];\n\t\t\tif(!plugindata) {\n\t\t\t\tJanus.warn(\"Missing plugindata...\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tJanus.debug(\" -- Event is coming from \" + sender + \" (\" + plugindata[\"plugin\"] + \")\");\n\t\t\tvar data = plugindata[\"data\"];\n\t\t\tJanus.debug(data);\n\t\t\tconst pluginHandle = pluginHandles[sender];\n\t\t\tif(!pluginHandle) {\n\t\t\t\tJanus.warn(\"This handle is not attached to this session\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar jsep = json[\"jsep\"];\n\t\t\tif(jsep) {\n\t\t\t\tJanus.debug(\"Handling SDP as well...\");\n\t\t\t\tJanus.debug(jsep);\n\t\t\t}\n\t\t\tvar callback = pluginHandle.onmessage;\n\t\t\tif(callback) {\n\t\t\t\tJanus.debug(\"Notifying application...\");\n\t\t\t\t// Send to callback specified when attaching plugin handle\n\t\t\t\tcallback(data, jsep);\n\t\t\t} else {\n\t\t\t\t// Send to generic callback (?)\n\t\t\t\tJanus.debug(\"No provided notification callback\");\n\t\t\t}\n\t\t} else if(json[\"janus\"] === \"timeout\") {\n\t\t\tJanus.error(\"Timeout on session \" + sessionId);\n\t\t\tJanus.debug(json);\n\t\t\tif (websockets) {\n\t\t\t\tws.close(3504, \"Gateway timeout\");\n\t\t\t}\n\t\t\treturn;\n\t\t} else {\n\t\t\tJanus.warn(\"Unknown message/event '\" + json[\"janus\"] + \"' on session \" + sessionId);\n\t\t\tJanus.debug(json);\n\t\t}\n\t}\n\n\t// Private helper to send keep-alive messages on WebSockets\n\tfunction keepAlive() {\n\t\tif(!server || !websockets || !connected)\n\t\t\treturn;\n\t\twsKeepaliveTimeoutId = setTimeout(keepAlive, keepAlivePeriod);\n\t\tvar request = { \"janus\": \"keepalive\", \"session_id\": sessionId, \"transaction\": Janus.randomString(12) };\n\t\tif(token)\n\t\t\trequest[\"token\"] = token;\n\t\tif(apisecret)\n\t\t\trequest[\"apisecret\"] = apisecret;\n\t\tws.send(JSON.stringify(request));\n\t}\n\n\t// Private method to create a session\n\tfunction createSession(callbacks) {\n\t\tvar transaction = Janus.randomString(12);\n\t\tvar request = { \"janus\": \"create\", \"transaction\": transaction };\n\t\tif(callbacks[\"reconnect\"]) {\n\t\t\t// We're reconnecting, claim the session\n\t\t\tconnected = false;\n\t\t\trequest[\"janus\"] = \"claim\";\n\t\t\trequest[\"session_id\"] = sessionId;\n\t\t\t// If we were using websockets, ignore the old connection\n\t\t\tif(ws) {\n\t\t\t\tws.onopen = null;\n\t\t\t\tws.onerror = null;\n\t\t\t\tws.onclose = null;\n\t\t\t\tif(wsKeepaliveTimeoutId) {\n\t\t\t\t\tclearTimeout(wsKeepaliveTimeoutId);\n\t\t\t\t\twsKeepaliveTimeoutId = null;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif(token)\n\t\t\trequest[\"token\"] = token;\n\t\tif(apisecret)\n\t\t\trequest[\"apisecret\"] = apisecret;\n\t\tif(!server && Janus.isArray(servers)) {\n\t\t\t// We still need to find a working server from the list we were given\n\t\t\tserver = servers[serversIndex];\n\t\t\tif(server.indexOf(\"ws\") === 0) {\n\t\t\t\twebsockets = true;\n\t\t\t\tJanus.log(\"Server #\" + (serversIndex+1) + \": trying WebSockets to contact Janus (\" + server + \")\");\n\t\t\t} else {\n\t\t\t\twebsockets = false;\n\t\t\t\tJanus.log(\"Server #\" + (serversIndex+1) + \": trying REST API to contact Janus (\" + server + \")\");\n\t\t\t}\n\t\t}\n\t\tif(websockets) {\n\t\t\tws = Janus.newWebSocket(server, 'janus-protocol');\n\t\t\twsHandlers = {\n\t\t\t\t'error': function() {\n\t\t\t\t\tJanus.error(\"Error connecting to the Janus WebSockets server... \" + server);\n\t\t\t\t\tif (Janus.isArray(servers) && !callbacks[\"reconnect\"]) {\n\t\t\t\t\t\tserversIndex++;\n\t\t\t\t\t\tif (serversIndex === servers.length) {\n\t\t\t\t\t\t\t// We tried all the servers the user gave us and they all failed\n\t\t\t\t\t\t\tcallbacks.error(\"Error connecting to any of the provided Janus servers: Is the server down?\");\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Let's try the next server\n\t\t\t\t\t\tserver = null;\n\t\t\t\t\t\tsetTimeout(function() {\n\t\t\t\t\t\t\tcreateSession(callbacks);\n\t\t\t\t\t\t}, 200);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tcallbacks.error(\"Error connecting to the Janus WebSockets server: Is the server down?\");\n\t\t\t\t},\n\n\t\t\t\t'open': function() {\n\t\t\t\t\t// We need to be notified about the success\n\t\t\t\t\ttransactions[transaction] = function(json) {\n\t\t\t\t\t\tJanus.debug(json);\n\t\t\t\t\t\tif (json[\"janus\"] !== \"success\") {\n\t\t\t\t\t\t\tJanus.error(\"Ooops: \" + json[\"error\"].code + \" \" + json[\"error\"].reason);\t// FIXME\n\t\t\t\t\t\t\tcallbacks.error(json[\"error\"].reason);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\twsKeepaliveTimeoutId = setTimeout(keepAlive, keepAlivePeriod);\n\t\t\t\t\t\tconnected = true;\n\t\t\t\t\t\tsessionId = json[\"session_id\"] ? json[\"session_id\"] : json.data[\"id\"];\n\t\t\t\t\t\tif(callbacks[\"reconnect\"]) {\n\t\t\t\t\t\t\tJanus.log(\"Claimed session: \" + sessionId);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tJanus.log(\"Created session: \" + sessionId);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tJanus.sessions[sessionId] = that;\n\t\t\t\t\t\tcallbacks.success();\n\t\t\t\t\t};\n\t\t\t\t\tws.send(JSON.stringify(request));\n\t\t\t\t},\n\n\t\t\t\t'message': function(event) {\n\t\t\t\t\thandleEvent(JSON.parse(event.data));\n\t\t\t\t},\n\n\t\t\t\t'close': function() {\n\t\t\t\t\tif (!server || !connected) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconnected = false;\n\t\t\t\t\t// FIXME What if this is called when the page is closed?\n\t\t\t\t\tgatewayCallbacks.error(\"Lost connection to the server (is it down?)\");\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tfor(var eventName in wsHandlers) {\n\t\t\t\tws.addEventListener(eventName, wsHandlers[eventName]);\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\t\tJanus.httpAPICall(server, {\n\t\t\tverb: 'POST',\n\t\t\twithCredentials: withCredentials,\n\t\t\tbody: request,\n\t\t\tsuccess: function(json) {\n\t\t\t\tJanus.debug(json);\n\t\t\t\tif(json[\"janus\"] !== \"success\") {\n\t\t\t\t\tJanus.error(\"Ooops: \" + json[\"error\"].code + \" \" + json[\"error\"].reason);\t// FIXME\n\t\t\t\t\tcallbacks.error(json[\"error\"].reason);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconnected = true;\n\t\t\t\tsessionId = json[\"session_id\"] ? json[\"session_id\"] : json.data[\"id\"];\n\t\t\t\tif(callbacks[\"reconnect\"]) {\n\t\t\t\t\tJanus.log(\"Claimed session: \" + sessionId);\n\t\t\t\t} else {\n\t\t\t\t\tJanus.log(\"Created session: \" + sessionId);\n\t\t\t\t}\n\t\t\t\tJanus.sessions[sessionId] = that;\n\t\t\t\teventHandler();\n\t\t\t\tcallbacks.success();\n\t\t\t},\n\t\t\terror: function(textStatus, errorThrown) {\n\t\t\t\tJanus.error(textStatus + \":\", errorThrown);\t// FIXME\n\t\t\t\tif(Janus.isArray(servers) && !callbacks[\"reconnect\"]) {\n\t\t\t\t\tserversIndex++;\n\t\t\t\t\tif(serversIndex === servers.length) {\n\t\t\t\t\t\t// We tried all the servers the user gave us and they all failed\n\t\t\t\t\t\tcallbacks.error(\"Error connecting to any of the provided Janus servers: Is the server down?\");\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t// Let's try the next server\n\t\t\t\t\tserver = null;\n\t\t\t\t\tsetTimeout(function() { createSession(callbacks); }, 200);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif(errorThrown === \"\")\n\t\t\t\t\tcallbacks.error(textStatus + \": Is the server down?\");\n\t\t\t\telse if (errorThrown && errorThrown.error)\n\t\t\t\t\tcallbacks.error(textStatus + \": \" + errorThrown.error.message);\n\t\t\t\telse\n\t\t\t\t\tcallbacks.error(textStatus + \": \" + errorThrown);\n\t\t\t}\n\t\t});\n\t}\n\n\t// Private method to get info on the server\n\tfunction getInfo(callbacks) {\n\t\tcallbacks = callbacks || {};\n\t\t// FIXME This method triggers a success even when we fail\n\t\tcallbacks.success = (typeof callbacks.success == \"function\") ? callbacks.success : Janus.noop;\n\t\tcallbacks.error = (typeof callbacks.error == \"function\") ? callbacks.error : Janus.noop;\n\t\tJanus.log(\"Getting info on Janus instance\");\n\t\tif(!connected) {\n\t\t\tJanus.warn(\"Is the server down? (connected=false)\");\n\t\t\tcallbacks.error(\"Is the server down? (connected=false)\");\n\t\t\treturn;\n\t\t}\n\t\t// We just need to send an \"info\" request\n\t\tvar transaction = Janus.randomString(12);\n\t\tvar request = { \"janus\": \"info\", \"transaction\": transaction };\n\t\tif(token)\n\t\t\trequest[\"token\"] = token;\n\t\tif(apisecret)\n\t\t\trequest[\"apisecret\"] = apisecret;\n\t\tif(websockets) {\n\t\t\ttransactions[transaction] = function(json) {\n\t\t\t\tJanus.log(\"Server info:\");\n\t\t\t\tJanus.debug(json);\n\t\t\t\tif(json[\"janus\"] !== \"server_info\") {\n\t\t\t\t\tJanus.error(\"Ooops: \" + json[\"error\"].code + \" \" + json[\"error\"].reason);\t// FIXME\n\t\t\t\t}\n\t\t\t\tcallbacks.success(json);\n\t\t\t}\n\t\t\tws.send(JSON.stringify(request));\n\t\t\treturn;\n\t\t}\n\t\tJanus.httpAPICall(server, {\n\t\t\tverb: 'POST',\n\t\t\twithCredentials: withCredentials,\n\t\t\tbody: request,\n\t\t\tsuccess: function(json) {\n\t\t\t\tJanus.log(\"Server info:\");\n\t\t\t\tJanus.debug(json);\n\t\t\t\tif(json[\"janus\"] !== \"server_info\") {\n\t\t\t\t\tJanus.error(\"Ooops: \" + json[\"error\"].code + \" \" + json[\"error\"].reason);\t// FIXME\n\t\t\t\t}\n\t\t\t\tcallbacks.success(json);\n\t\t\t},\n\t\t\terror: function(textStatus, errorThrown) {\n\t\t\t\tJanus.error(textStatus + \":\", errorThrown);\t// FIXME\n\t\t\t\tif(errorThrown === \"\")\n\t\t\t\t\tcallbacks.error(textStatus + \": Is the server down?\");\n\t\t\t\telse\n\t\t\t\t\tcallbacks.error(textStatus + \": \" + errorThrown);\n\t\t\t}\n\t\t});\n\t}\n\n\t// Private method to destroy a session\n\tfunction destroySession(callbacks) {\n\t\tcallbacks = callbacks || {};\n\t\t// FIXME This method triggers a success even when we fail\n\t\tcallbacks.success = (typeof callbacks.success == \"function\") ? callbacks.success : Janus.noop;\n\t\tcallbacks.error = (typeof callbacks.error == \"function\") ? callbacks.error : Janus.noop;\n\t\tvar unload = (callbacks.unload === true);\n\t\tvar notifyDestroyed = true;\n\t\tif(callbacks.notifyDestroyed !== undefined && callbacks.notifyDestroyed !== null)\n\t\t\tnotifyDestroyed = (callbacks.notifyDestroyed === true);\n\t\tvar cleanupHandles = (callbacks.cleanupHandles === true);\n\t\tJanus.log(\"Destroying session \" + sessionId + \" (unload=\" + unload + \")\");\n\t\tif(!sessionId) {\n\t\t\tJanus.warn(\"No session to destroy\");\n\t\t\tcallbacks.success();\n\t\t\tif(notifyDestroyed)\n\t\t\t\tgatewayCallbacks.destroyed();\n\t\t\treturn;\n\t\t}\n\t\tif(cleanupHandles) {\n\t\t\tfor(var handleId in pluginHandles)\n\t\t\t\tdestroyHandle(handleId, { noRequest: true });\n\t\t}\n\t\tif(!connected) {\n\t\t\tJanus.warn(\"Is the server down? (connected=false)\");\n\t\t\tsessionId = null;\n\t\t\tcallbacks.success();\n\t\t\treturn;\n\t\t}\n\t\t// No need to destroy all handles first, Janus will do that itself\n\t\tvar request = { \"janus\": \"destroy\", \"transaction\": Janus.randomString(12) };\n\t\tif(token)\n\t\t\trequest[\"token\"] = token;\n\t\tif(apisecret)\n\t\t\trequest[\"apisecret\"] = apisecret;\n\t\tif(unload) {\n\t\t\t// We're unloading the page: use sendBeacon for HTTP instead,\n\t\t\t// or just close the WebSocket connection if we're using that\n\t\t\tif(websockets) {\n\t\t\t\tws.onclose = null;\n\t\t\t\tws.close();\n\t\t\t\tws = null;\n\t\t\t} else {\n\t\t\t\tnavigator.sendBeacon(server + \"/\" + sessionId, JSON.stringify(request));\n\t\t\t}\n\t\t\tJanus.log(\"Destroyed session:\");\n\t\t\tsessionId = null;\n\t\t\tconnected = false;\n\t\t\tcallbacks.success();\n\t\t\tif(notifyDestroyed)\n\t\t\t\tgatewayCallbacks.destroyed();\n\t\t\treturn;\n\t\t}\n\t\tif(websockets) {\n\t\t\trequest[\"session_id\"] = sessionId;\n\n\t\t\tvar unbindWebSocket = function() {\n\t\t\t\tfor(var eventName in wsHandlers) {\n\t\t\t\t\tws.removeEventListener(eventName, wsHandlers[eventName]);\n\t\t\t\t}\n\t\t\t\tws.removeEventListener('message', onUnbindMessage);\n\t\t\t\tws.removeEventListener('error', onUnbindError);\n\t\t\t\tif(wsKeepaliveTimeoutId) {\n\t\t\t\t\tclearTimeout(wsKeepaliveTimeoutId);\n\t\t\t\t}\n\t\t\t\tws.close();\n\t\t\t};\n\n\t\t\tvar onUnbindMessage = function(event){\n\t\t\t\tvar data = JSON.parse(event.data);\n\t\t\t\tif(data.session_id == request.session_id && data.transaction == request.transaction) {\n\t\t\t\t\tunbindWebSocket();\n\t\t\t\t\tcallbacks.success();\n\t\t\t\t\tif(notifyDestroyed)\n\t\t\t\t\t\tgatewayCallbacks.destroyed();\n\t\t\t\t}\n\t\t\t};\n\t\t\tvar onUnbindError = function() {\n\t\t\t\tunbindWebSocket();\n\t\t\t\tcallbacks.error(\"Failed to destroy the server: Is the server down?\");\n\t\t\t\tif(notifyDestroyed)\n\t\t\t\t\tgatewayCallbacks.destroyed();\n\t\t\t};\n\n\t\t\tws.addEventListener('message', onUnbindMessage);\n\t\t\tws.addEventListener('error', onUnbindError);\n\n\t\t\tif (ws.readyState === 1) {\n\t\t\t\tws.send(JSON.stringify(request));\n\t\t\t} else {\n\t\t\t\tonUnbindError();\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\t\tJanus.httpAPICall(server + \"/\" + sessionId, {\n\t\t\tverb: 'POST',\n\t\t\twithCredentials: withCredentials,\n\t\t\tbody: request,\n\t\t\tsuccess: function(json) {\n\t\t\t\tJanus.log(\"Destroyed session:\");\n\t\t\t\tJanus.debug(json);\n\t\t\t\tsessionId = null;\n\t\t\t\tconnected = false;\n\t\t\t\tif(json[\"janus\"] !== \"success\") {\n\t\t\t\t\tJanus.error(\"Ooops: \" + json[\"error\"].code + \" \" + json[\"error\"].reason);\t// FIXME\n\t\t\t\t}\n\t\t\t\tcallbacks.success();\n\t\t\t\tif(notifyDestroyed)\n\t\t\t\t\tgatewayCallbacks.destroyed();\n\t\t\t},\n\t\t\terror: function(textStatus, errorThrown) {\n\t\t\t\tJanus.error(textStatus + \":\", errorThrown);\t// FIXME\n\t\t\t\t// Reset everything anyway\n\t\t\t\tsessionId = null;\n\t\t\t\tconnected = false;\n\t\t\t\tcallbacks.success();\n\t\t\t\tif(notifyDestroyed)\n\t\t\t\t\tgatewayCallbacks.destroyed();\n\t\t\t}\n\t\t});\n\t}\n\n\t// Private method to create a plugin handle\n\tfunction createHandle(callbacks) {\n\t\tcallbacks = callbacks || {};\n\t\tcallbacks.success = (typeof callbacks.success == \"function\") ? callbacks.success : Janus.noop;\n\t\tcallbacks.error = (typeof callbacks.error == \"function\") ? callbacks.error : Janus.noop;\n\t\tcallbacks.dataChannelOptions = callbacks.dataChannelOptions || { ordered: true };\n\t\tcallbacks.consentDialog = (typeof callbacks.consentDialog == \"function\") ? callbacks.consentDialog : Janus.noop;\n\t\tcallbacks.iceState = (typeof callbacks.iceState == \"function\") ? callbacks.iceState : Janus.noop;\n\t\tcallbacks.mediaState = (typeof callbacks.mediaState == \"function\") ? callbacks.mediaState : Janus.noop;\n\t\tcallbacks.webrtcState = (typeof callbacks.webrtcState == \"function\") ? callbacks.webrtcState : Janus.noop;\n\t\tcallbacks.slowLink = (typeof callbacks.slowLink == \"function\") ? callbacks.slowLink : Janus.noop;\n\t\tcallbacks.onmessage = (typeof callbacks.onmessage == \"function\") ? callbacks.onmessage : Janus.noop;\n\t\tcallbacks.onlocalstream = (typeof callbacks.onlocalstream == \"function\") ? callbacks.onlocalstream : Janus.noop;\n\t\tcallbacks.onremotestream = (typeof callbacks.onremotestream == \"function\") ? callbacks.onremotestream : Janus.noop;\n\t\tcallbacks.ondata = (typeof callbacks.ondata == \"function\") ? callbacks.ondata : Janus.noop;\n\t\tcallbacks.ondataopen = (typeof callbacks.ondataopen == \"function\") ? callbacks.ondataopen : Janus.noop;\n\t\tcallbacks.oncleanup = (typeof callbacks.oncleanup == \"function\") ? callbacks.oncleanup : Janus.noop;\n\t\tcallbacks.ondetached = (typeof callbacks.ondetached == \"function\") ? callbacks.ondetached : Janus.noop;\n\t\tif(!connected) {\n\t\t\tJanus.warn(\"Is the server down? (connected=false)\");\n\t\t\tcallbacks.error(\"Is the server down? (connected=false)\");\n\t\t\treturn;\n\t\t}\n\t\tvar plugin = callbacks.plugin;\n\t\tif(!plugin) {\n\t\t\tJanus.error(\"Invalid plugin\");\n\t\t\tcallbacks.error(\"Invalid plugin\");\n\t\t\treturn;\n\t\t}\n\t\tvar opaqueId = callbacks.opaqueId;\n\t\tvar loopIndex = callbacks.loopIndex;\n\t\tvar handleToken = callbacks.token ? callbacks.token : token;\n\t\tvar transaction = Janus.randomString(12);\n\t\tvar request = { \"janus\": \"attach\", \"plugin\": plugin, \"opaque_id\": opaqueId, \"loop_index\": loopIndex, \"transaction\": transaction };\n\t\tif(handleToken)\n\t\t\trequest[\"token\"] = handleToken;\n\t\tif(apisecret)\n\t\t\trequest[\"apisecret\"] = apisecret;\n\t\tif(websockets) {\n\t\t\ttransactions[transaction] = function(json) {\n\t\t\t\tJanus.debug(json);\n\t\t\t\tif(json[\"janus\"] !== \"success\") {\n\t\t\t\t\tJanus.error(\"Ooops: \" + json[\"error\"].code + \" \" + json[\"error\"].reason);\t// FIXME\n\t\t\t\t\tcallbacks.error(\"Ooops: \" + json[\"error\"].code + \" \" + json[\"error\"].reason);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tvar handleId = json.data[\"id\"];\n\t\t\t\tJanus.log(\"Created handle: \" + handleId);\n\t\t\t\tvar pluginHandle =\n\t\t\t\t\t{\n\t\t\t\t\t\tsession : that,\n\t\t\t\t\t\tplugin : plugin,\n\t\t\t\t\t\tid : handleId,\n\t\t\t\t\t\ttoken : handleToken,\n\t\t\t\t\t\tdetached : false,\n\t\t\t\t\t\twebrtcStuff : {\n\t\t\t\t\t\t\tstarted : false,\n\t\t\t\t\t\t\tmyStream : null,\n\t\t\t\t\t\t\tstreamExternal : false,\n\t\t\t\t\t\t\tremoteStream : null,\n\t\t\t\t\t\t\tmySdp : null,\n\t\t\t\t\t\t\tmediaConstraints : null,\n\t\t\t\t\t\t\tpc : null,\n\t\t\t\t\t\t\tdataChannelOptions: callbacks.dataChannelOptions,\n\t\t\t\t\t\t\tdataChannel : {},\n\t\t\t\t\t\t\tdtmfSender : null,\n\t\t\t\t\t\t\ttrickle : true,\n\t\t\t\t\t\t\ticeDone : false,\n\t\t\t\t\t\t\tvolume : {\n\t\t\t\t\t\t\t\tvalue : null,\n\t\t\t\t\t\t\t\ttimer : null\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tbitrate : {\n\t\t\t\t\t\t\t\tvalue : null,\n\t\t\t\t\t\t\t\tbsnow : null,\n\t\t\t\t\t\t\t\tbsbefore : null,\n\t\t\t\t\t\t\t\ttsnow : null,\n\t\t\t\t\t\t\t\ttsbefore : null,\n\t\t\t\t\t\t\t\ttimer : null\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\tgetId : function() { return handleId; },\n\t\t\t\t\t\tgetPlugin : function() { return plugin; },\n\t\t\t\t\t\tgetVolume : function() { return getVolume(handleId, true); },\n\t\t\t\t\t\tgetRemoteVolume : function() { return getVolume(handleId, true); },\n\t\t\t\t\t\tgetLocalVolume : function() { return getVolume(handleId, false); },\n\t\t\t\t\t\tisAudioMuted : function() { return isMuted(handleId, false); },\n\t\t\t\t\t\tmuteAudio : function() { return mute(handleId, false, true); },\n\t\t\t\t\t\tunmuteAudio : function() { return mute(handleId, false, false); },\n\t\t\t\t\t\tisVideoMuted : function() { return isMuted(handleId, true); },\n\t\t\t\t\t\tmuteVideo : function() { return mute(handleId, true, true); },\n\t\t\t\t\t\tunmuteVideo : function() { return mute(handleId, true, false); },\n\t\t\t\t\t\tgetBitrate : function() { return getBitrate(handleId); },\n\t\t\t\t\t\tsend : function(callbacks) { sendMessage(handleId, callbacks); },\n\t\t\t\t\t\tdata : function(callbacks) { sendData(handleId, callbacks); },\n\t\t\t\t\t\tdtmf : function(callbacks) { sendDtmf(handleId, callbacks); },\n\t\t\t\t\t\tconsentDialog : callbacks.consentDialog,\n\t\t\t\t\t\ticeState : callbacks.iceState,\n\t\t\t\t\t\tmediaState : callbacks.mediaState,\n\t\t\t\t\t\twebrtcState : callbacks.webrtcState,\n\t\t\t\t\t\tslowLink : callbacks.slowLink,\n\t\t\t\t\t\tonmessage : callbacks.onmessage,\n\t\t\t\t\t\tcreateOffer : function(callbacks) { prepareWebrtc(handleId, true, callbacks); },\n\t\t\t\t\t\tcreateAnswer : function(callbacks) { prepareWebrtc(handleId, false, callbacks); },\n\t\t\t\t\t\thandleRemoteJsep : function(callbacks) { prepareWebrtcPeer(handleId, callbacks); },\n\t\t\t\t\t\tonlocalstream : callbacks.onlocalstream,\n\t\t\t\t\t\tonremotestream : callbacks.onremotestream,\n\t\t\t\t\t\tondata : callbacks.ondata,\n\t\t\t\t\t\tondataopen : callbacks.ondataopen,\n\t\t\t\t\t\toncleanup : callbacks.oncleanup,\n\t\t\t\t\t\tondetached : callbacks.ondetached,\n\t\t\t\t\t\thangup : function(sendRequest) { cleanupWebrtc(handleId, sendRequest === true); },\n\t\t\t\t\t\tdetach : function(callbacks) { destroyHandle(handleId, callbacks); }\n\t\t\t\t\t};\n\t\t\t\tpluginHandles[handleId] = pluginHandle;\n\t\t\t\tcallbacks.success(pluginHandle);\n\t\t\t};\n\t\t\trequest[\"session_id\"] = sessionId;\n\t\t\tws.send(JSON.stringify(request));\n\t\t\treturn;\n\t\t}\n\t\tJanus.httpAPICall(server + \"/\" + sessionId, {\n\t\t\tverb: 'POST',\n\t\t\twithCredentials: withCredentials,\n\t\t\tbody: request,\n\t\t\tsuccess: function(json) {\n\t\t\t\tJanus.debug(json);\n\t\t\t\tif(json[\"janus\"] !== \"success\") {\n\t\t\t\t\tJanus.error(\"Ooops: \" + json[\"error\"].code + \" \" + json[\"error\"].reason);\t// FIXME\n\t\t\t\t\tcallbacks.error(\"Ooops: \" + json[\"error\"].code + \" \" + json[\"error\"].reason);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tvar handleId = json.data[\"id\"];\n\t\t\t\tJanus.log(\"Created handle: \" + handleId);\n\t\t\t\tvar pluginHandle =\n\t\t\t\t\t{\n\t\t\t\t\t\tsession : that,\n\t\t\t\t\t\tplugin : plugin,\n\t\t\t\t\t\tid : handleId,\n\t\t\t\t\t\ttoken : handleToken,\n\t\t\t\t\t\tdetached : false,\n\t\t\t\t\t\twebrtcStuff : {\n\t\t\t\t\t\t\tstarted : false,\n\t\t\t\t\t\t\tmyStream : null,\n\t\t\t\t\t\t\tstreamExternal : false,\n\t\t\t\t\t\t\tremoteStream : null,\n\t\t\t\t\t\t\tmySdp : null,\n\t\t\t\t\t\t\tmediaConstraints : null,\n\t\t\t\t\t\t\tpc : null,\n\t\t\t\t\t\t\tdataChannelOptions: callbacks.dataChannelOptions,\n\t\t\t\t\t\t\tdataChannel : {},\n\t\t\t\t\t\t\tdtmfSender : null,\n\t\t\t\t\t\t\ttrickle : true,\n\t\t\t\t\t\t\ticeDone : false,\n\t\t\t\t\t\t\tvolume : {\n\t\t\t\t\t\t\t\tvalue : null,\n\t\t\t\t\t\t\t\ttimer : null\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tbitrate : {\n\t\t\t\t\t\t\t\tvalue : null,\n\t\t\t\t\t\t\t\tbsnow : null,\n\t\t\t\t\t\t\t\tbsbefore : null,\n\t\t\t\t\t\t\t\ttsnow : null,\n\t\t\t\t\t\t\t\ttsbefore : null,\n\t\t\t\t\t\t\t\ttimer : null\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\tgetId : function() { return handleId; },\n\t\t\t\t\t\tgetPlugin : function() { return plugin; },\n\t\t\t\t\t\tgetVolume : function() { return getVolume(handleId, true); },\n\t\t\t\t\t\tgetRemoteVolume : function() { return getVolume(handleId, true); },\n\t\t\t\t\t\tgetLocalVolume : function() { return getVolume(handleId, false); },\n\t\t\t\t\t\tisAudioMuted : function() { return isMuted(handleId, false); },\n\t\t\t\t\t\tmuteAudio : function() { return mute(handleId, false, true); },\n\t\t\t\t\t\tunmuteAudio : function() { return mute(handleId, false, false); },\n\t\t\t\t\t\tisVideoMuted : function() { return isMuted(handleId, true); },\n\t\t\t\t\t\tmuteVideo : function() { return mute(handleId, true, true); },\n\t\t\t\t\t\tunmuteVideo : function() { return mute(handleId, true, false); },\n\t\t\t\t\t\tgetBitrate : function() { return getBitrate(handleId); },\n\t\t\t\t\t\tsend : function(callbacks) { sendMessage(handleId, callbacks); },\n\t\t\t\t\t\tdata : function(callbacks) { sendData(handleId, callbacks); },\n\t\t\t\t\t\tdtmf : function(callbacks) { sendDtmf(handleId, callbacks); },\n\t\t\t\t\t\tconsentDialog : callbacks.consentDialog,\n\t\t\t\t\t\ticeState : callbacks.iceState,\n\t\t\t\t\t\tmediaState : callbacks.mediaState,\n\t\t\t\t\t\twebrtcState : callbacks.webrtcState,\n\t\t\t\t\t\tslowLink : callbacks.slowLink,\n\t\t\t\t\t\tonmessage : callbacks.onmessage,\n\t\t\t\t\t\tcreateOffer : function(callbacks) { prepareWebrtc(handleId, true, callbacks); },\n\t\t\t\t\t\tcreateAnswer : function(callbacks) { prepareWebrtc(handleId, false, callbacks); },\n\t\t\t\t\t\thandleRemoteJsep : function(callbacks) { prepareWebrtcPeer(handleId, callbacks); },\n\t\t\t\t\t\tonlocalstream : callbacks.onlocalstream,\n\t\t\t\t\t\tonremotestream : callbacks.onremotestream,\n\t\t\t\t\t\tondata : callbacks.ondata,\n\t\t\t\t\t\tondataopen : callbacks.ondataopen,\n\t\t\t\t\t\toncleanup : callbacks.oncleanup,\n\t\t\t\t\t\tondetached : callbacks.ondetached,\n\t\t\t\t\t\thangup : function(sendRequest) { cleanupWebrtc(handleId, sendRequest === true); },\n\t\t\t\t\t\tdetach : function(callbacks) { destroyHandle(handleId, callbacks); }\n\t\t\t\t\t}\n\t\t\t\tpluginHandles[handleId] = pluginHandle;\n\t\t\t\tcallbacks.success(pluginHandle);\n\t\t\t},\n\t\t\terror: function(textStatus, errorThrown) {\n\t\t\t\tJanus.error(textStatus + \":\", errorThrown);\t// FIXME\n\t\t\t\tif(errorThrown === \"\")\n\t\t\t\t\tcallbacks.error(textStatus + \": Is the server down?\");\n\t\t\t\telse\n\t\t\t\t\tcallbacks.error(textStatus + \": \" + errorThrown);\n\t\t\t}\n\t\t});\n\t}\n\n\t// Private method to send a message\n\tfunction sendMessage(handleId, callbacks) {\n\t\tcallbacks = callbacks || {};\n\t\tcallbacks.success = (typeof callbacks.success == \"function\") ? callbacks.success : Janus.noop;\n\t\tcallbacks.error = (typeof callbacks.error == \"function\") ? callbacks.error : Janus.noop;\n\t\tif(!connected) {\n\t\t\tJanus.warn(\"Is the server down? (connected=false)\");\n\t\t\tcallbacks.error(\"Is the server down? (connected=false)\");\n\t\t\treturn;\n\t\t}\n\t\tvar pluginHandle = pluginHandles[handleId];\n\t\tif(!pluginHandle || !pluginHandle.webrtcStuff) {\n\t\t\tJanus.warn(\"Invalid handle\");\n\t\t\tcallbacks.error(\"Invalid handle\");\n\t\t\treturn;\n\t\t}\n\t\tvar message = callbacks.message;\n\t\tvar jsep = callbacks.jsep;\n\t\tvar transaction = Janus.randomString(12);\n\t\tvar request = { \"janus\": \"message\", \"body\": message, \"transaction\": transaction };\n\t\tif(pluginHandle.token)\n\t\t\trequest[\"token\"] = pluginHandle.token;\n\t\tif(apisecret)\n\t\t\trequest[\"apisecret\"] = apisecret;\n\t\tif(jsep) {\n\t\t\trequest.jsep = {\n\t\t\t\ttype: jsep.type,\n\t\t\t\tsdp: jsep.sdp\n\t\t\t};\n\t\t\tif(jsep.e2ee)\n\t\t\t\trequest.jsep.e2ee = true;\n\t\t\tif(jsep.rid_order === \"hml\" || jsep.rid_order === \"lmh\")\n\t\t\t\trequest.jsep.rid_order = jsep.rid_order;\n\t\t\tif(jsep.force_relay)\n\t\t\t\trequest.jsep.force_relay = true;\n\t\t}\n\t\tJanus.debug(\"Sending message to plugin (handle=\" + handleId + \"):\");\n\t\tJanus.debug(request);\n\t\tif(websockets) {\n\t\t\trequest[\"session_id\"] = sessionId;\n\t\t\trequest[\"handle_id\"] = handleId;\n\t\t\ttransactions[transaction] = function(json) {\n\t\t\t\tJanus.debug(\"Message sent!\");\n\t\t\t\tJanus.debug(json);\n\t\t\t\tif(json[\"janus\"] === \"success\") {\n\t\t\t\t\t// We got a success, must have been a synchronous transaction\n\t\t\t\t\tvar plugindata = json[\"plugindata\"];\n\t\t\t\t\tif(!plugindata) {\n\t\t\t\t\t\tJanus.warn(\"Request succeeded, but missing plugindata...\");\n\t\t\t\t\t\tcallbacks.success();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tJanus.log(\"Synchronous transaction successful (\" + plugindata[\"plugin\"] + \")\");\n\t\t\t\t\tvar data = plugindata[\"data\"];\n\t\t\t\t\tJanus.debug(data);\n\t\t\t\t\tcallbacks.success(data);\n\t\t\t\t\treturn;\n\t\t\t\t} else if(json[\"janus\"] !== \"ack\") {\n\t\t\t\t\t// Not a success and not an ack, must be an error\n\t\t\t\t\tif(json[\"error\"]) {\n\t\t\t\t\t\tJanus.error(\"Ooops: \" + json[\"error\"].code + \" \" + json[\"error\"].reason);\t// FIXME\n\t\t\t\t\t\tcallbacks.error(json[\"error\"].code + \" \" + json[\"error\"].reason);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tJanus.error(\"Unknown error\");\t// FIXME\n\t\t\t\t\t\tcallbacks.error(\"Unknown error\");\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// If we got here, the plugin decided to handle the request asynchronously\n\t\t\t\tcallbacks.success();\n\t\t\t};\n\t\t\tws.send(JSON.stringify(request));\n\t\t\treturn;\n\t\t}\n\t\tJanus.httpAPICall(server + \"/\" + sessionId + \"/\" + handleId, {\n\t\t\tverb: 'POST',\n\t\t\twithCredentials: withCredentials,\n\t\t\tbody: request,\n\t\t\tsuccess: function(json) {\n\t\t\t\tJanus.debug(\"Message sent!\");\n\t\t\t\tJanus.debug(json);\n\t\t\t\tif(json[\"janus\"] === \"success\") {\n\t\t\t\t\t// We got a success, must have been a synchronous transaction\n\t\t\t\t\tvar plugindata = json[\"plugindata\"];\n\t\t\t\t\tif(!plugindata) {\n\t\t\t\t\t\tJanus.warn(\"Request succeeded, but missing plugindata...\");\n\t\t\t\t\t\tcallbacks.success();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tJanus.log(\"Synchronous transaction successful (\" + plugindata[\"plugin\"] + \")\");\n\t\t\t\t\tvar data = plugindata[\"data\"];\n\t\t\t\t\tJanus.debug(data);\n\t\t\t\t\tcallbacks.success(data);\n\t\t\t\t\treturn;\n\t\t\t\t} else if(json[\"janus\"] !== \"ack\") {\n\t\t\t\t\t// Not a success and not an ack, must be an error\n\t\t\t\t\tif(json[\"error\"]) {\n\t\t\t\t\t\tJanus.error(\"Ooops: \" + json[\"error\"].code + \" \" + json[\"error\"].reason);\t// FIXME\n\t\t\t\t\t\tcallbacks.error(json[\"error\"].code + \" \" + json[\"error\"].reason);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tJanus.error(\"Unknown error\");\t// FIXME\n\t\t\t\t\t\tcallbacks.error(\"Unknown error\");\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// If we got here, the plugin decided to handle the request asynchronously\n\t\t\t\tcallbacks.success();\n\t\t\t},\n\t\t\terror: function(textStatus, errorThrown) {\n\t\t\t\tJanus.error(textStatus + \":\", errorThrown);\t// FIXME\n\t\t\t\tcallbacks.error(textStatus + \": \" + errorThrown);\n\t\t\t}\n\t\t});\n\t}\n\n\t// Private method to send a trickle candidate\n\tfunction sendTrickleCandidate(handleId, candidate) {\n\t\tif(!connected) {\n\t\t\tJanus.warn(\"Is the server down? (connected=false)\");\n\t\t\treturn;\n\t\t}\n\t\tvar pluginHandle = pluginHandles[handleId];\n\t\tif(!pluginHandle || !pluginHandle.webrtcStuff) {\n\t\t\tJanus.warn(\"Invalid handle\");\n\t\t\treturn;\n\t\t}\n\t\tvar request = { \"janus\": \"trickle\", \"candidate\": candidate, \"transaction\": Janus.randomString(12) };\n\t\tif(pluginHandle.token)\n\t\t\trequest[\"token\"] = pluginHandle.token;\n\t\tif(apisecret)\n\t\t\trequest[\"apisecret\"] = apisecret;\n\t\tJanus.vdebug(\"Sending trickle candidate (handle=\" + handleId + \"):\");\n\t\tJanus.vdebug(request);\n\t\tif(websockets) {\n\t\t\trequest[\"session_id\"] = sessionId;\n\t\t\trequest[\"handle_id\"] = handleId;\n\t\t\tws.send(JSON.stringify(request));\n\t\t\treturn;\n\t\t}\n\t\tJanus.httpAPICall(server + \"/\" + sessionId + \"/\" + handleId, {\n\t\t\tverb: 'POST',\n\t\t\twithCredentials: withCredentials,\n\t\t\tbody: request,\n\t\t\tsuccess: function(json) {\n\t\t\t\tJanus.vdebug(\"Candidate sent!\");\n\t\t\t\tJanus.vdebug(json);\n\t\t\t\tif(json[\"janus\"] !== \"ack\") {\n\t\t\t\t\tJanus.error(\"Ooops: \" + json[\"error\"].code + \" \" + json[\"error\"].reason);\t// FIXME\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t},\n\t\t\terror: function(textStatus, errorThrown) {\n\t\t\t\tJanus.error(textStatus + \":\", errorThrown);\t// FIXME\n\t\t\t}\n\t\t});\n\t}\n\n\t// Private method to create a data channel\n\tfunction createDataChannel(handleId, dclabel, dcprotocol, incoming, pendingData) {\n\t\tvar pluginHandle = pluginHandles[handleId];\n\t\tif(!pluginHandle || !pluginHandle.webrtcStuff) {\n\t\t\tJanus.warn(\"Invalid handle\");\n\t\t\treturn;\n\t\t}\n\t\tvar config = pluginHandle.webrtcStuff;\n\t\tif(!config.pc) {\n\t\t\tJanus.warn(\"Invalid PeerConnection\");\n\t\t\treturn;\n\t\t}\n\t\tvar onDataChannelMessage = function(event) {\n\t\t\tJanus.log('Received message on data channel:', event);\n\t\t\tvar label = event.target.label;\n\t\t\tpluginHandle.ondata(event.data, label);\n\t\t};\n\t\tvar onDataChannelStateChange = function(event) {\n\t\t\tJanus.log('Received state change on data channel:', event);\n\t\t\tvar label = event.target.label;\n\t\t\tvar protocol = event.target.protocol;\n\t\t\tvar dcState = config.dataChannel[label] ? config.dataChannel[label].readyState : \"null\";\n\t\t\tJanus.log('State change on <' + label + '> data channel: ' + dcState);\n\t\t\tif(dcState === 'open') {\n\t\t\t\t// Any pending messages to send?\n\t\t\t\tif(config.dataChannel[label].pending && config.dataChannel[label].pending.length > 0) {\n\t\t\t\t\tJanus.log(\"Sending pending messages on <\" + label + \">:\", config.dataChannel[label].pending.length);\n\t\t\t\t\tfor(var data of config.dataChannel[label].pending) {\n\t\t\t\t\t\tJanus.log(\"Sending data on data channel <\" + label + \">\");\n\t\t\t\t\t\tJanus.debug(data);\n\t\t\t\t\t\tconfig.dataChannel[label].send(data);\n\t\t\t\t\t}\n\t\t\t\t\tconfig.dataChannel[label].pending = [];\n\t\t\t\t}\n\t\t\t\t// Notify the open data channel\n\t\t\t\tpluginHandle.ondataopen(label, protocol);\n\t\t\t}\n\t\t};\n\t\tvar onDataChannelError = function(error) {\n\t\t\tJanus.error('Got error on data channel:', error);\n\t\t\t// TODO\n\t\t};\n\t\tif(!incoming) {\n\t\t\t// FIXME Add options (ordered, maxRetransmits, etc.)\n\t\t\tvar dcoptions = config.dataChannelOptions;\n\t\t\tif(dcprotocol)\n\t\t\t\tdcoptions.protocol = dcprotocol;\n\t\t\tconfig.dataChannel[dclabel] = config.pc.createDataChannel(dclabel, dcoptions);\n\t\t} else {\n\t\t\t// The channel was created by Janus\n\t\t\tconfig.dataChannel[dclabel] = incoming;\n\t\t}\n\t\tconfig.dataChannel[dclabel].onmessage = onDataChannelMessage;\n\t\tconfig.dataChannel[dclabel].onopen = onDataChannelStateChange;\n\t\tconfig.dataChannel[dclabel].onclose = onDataChannelStateChange;\n\t\tconfig.dataChannel[dclabel].onerror = onDataChannelError;\n\t\tconfig.dataChannel[dclabel].pending = [];\n\t\tif(pendingData)\n\t\t\tconfig.dataChannel[dclabel].pending.push(pendingData);\n\t}\n\n\t// Private method to send a data channel message\n\tfunction sendData(handleId, callbacks) {\n\t\tcallbacks = callbacks || {};\n\t\tcallbacks.success = (typeof callbacks.success == \"function\") ? callbacks.success : Janus.noop;\n\t\tcallbacks.error = (typeof callbacks.error == \"function\") ? callbacks.error : Janus.noop;\n\t\tvar pluginHandle = pluginHandles[handleId];\n\t\tif(!pluginHandle || !pluginHandle.webrtcStuff) {\n\t\t\tJanus.warn(\"Invalid handle\");\n\t\t\tcallbacks.error(\"Invalid handle\");\n\t\t\treturn;\n\t\t}\n\t\tvar config = pluginHandle.webrtcStuff;\n\t\tvar data = callbacks.text || callbacks.data;\n\t\tif(!data) {\n\t\t\tJanus.warn(\"Invalid data\");\n\t\t\tcallbacks.error(\"Invalid data\");\n\t\t\treturn;\n\t\t}\n\t\tvar label = callbacks.label ? callbacks.label : Janus.dataChanDefaultLabel;\n\t\tif(!config.dataChannel[label]) {\n\t\t\t// Create new data channel and wait for it to open\n\t\t\tcreateDataChannel(handleId, label, callbacks.protocol, false, data, callbacks.protocol);\n\t\t\tcallbacks.success();\n\t\t\treturn;\n\t\t}\n\t\tif(config.dataChannel[label].readyState !== \"open\") {\n\t\t\tconfig.dataChannel[label].pending.push(data);\n\t\t\tcallbacks.success();\n\t\t\treturn;\n\t\t}\n\t\tJanus.log(\"Sending data on data channel <\" + label + \">\");\n\t\tJanus.debug(data);\n\t\tconfig.dataChannel[label].send(data);\n\t\tcallbacks.success();\n\t}\n\n\t// Private method to send a DTMF tone\n\tfunction sendDtmf(handleId, callbacks) {\n\t\tcallbacks = callbacks || {};\n\t\tcallbacks.success = (typeof callbacks.success == \"function\") ? callbacks.success : Janus.noop;\n\t\tcallbacks.error = (typeof callbacks.error == \"function\") ? callbacks.error : Janus.noop;\n\t\tvar pluginHandle = pluginHandles[handleId];\n\t\tif(!pluginHandle || !pluginHandle.webrtcStuff) {\n\t\t\tJanus.warn(\"Invalid handle\");\n\t\t\tcallbacks.error(\"Invalid handle\");\n\t\t\treturn;\n\t\t}\n\t\tvar config = pluginHandle.webrtcStuff;\n\t\tif(!config.dtmfSender) {\n\t\t\t// Create the DTMF sender the proper way, if possible\n\t\t\tif(config.pc) {\n\t\t\t\tvar senders = config.pc.getSenders();\n\t\t\t\tvar audioSender = senders.find(function(sender) {\n\t\t\t\t\treturn sender.track && sender.track.kind === 'audio';\n\t\t\t\t});\n\t\t\t\tif(!audioSender) {\n\t\t\t\t\tJanus.warn(\"Invalid DTMF configuration (no audio track)\");\n\t\t\t\t\tcallbacks.error(\"Invalid DTMF configuration (no audio track)\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconfig.dtmfSender = audioSender.dtmf;\n\t\t\t\tif(config.dtmfSender) {\n\t\t\t\t\tJanus.log(\"Created DTMF Sender\");\n\t\t\t\t\tconfig.dtmfSender.ontonechange = function(tone) { Janus.debug(\"Sent DTMF tone: \" + tone.tone); };\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(!config.dtmfSender) {\n\t\t\t\tJanus.warn(\"Invalid DTMF configuration\");\n\t\t\t\tcallbacks.error(\"Invalid DTMF configuration\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tvar dtmf = callbacks.dtmf;\n\t\tif(!dtmf) {\n\t\t\tJanus.warn(\"Invalid DTMF parameters\");\n\t\t\tcallbacks.error(\"Invalid DTMF parameters\");\n\t\t\treturn;\n\t\t}\n\t\tvar tones = dtmf.tones;\n\t\tif(!tones) {\n\t\t\tJanus.warn(\"Invalid DTMF string\");\n\t\t\tcallbacks.error(\"Invalid DTMF string\");\n\t\t\treturn;\n\t\t}\n\t\tvar duration = (typeof dtmf.duration === 'number') ? dtmf.duration : 500; // We choose 500ms as the default duration for a tone\n\t\tvar gap = (typeof dtmf.gap === 'number') ? dtmf.gap : 50; // We choose 50ms as the default gap between tones\n\t\tJanus.debug(\"Sending DTMF string \" + tones + \" (duration \" + duration + \"ms, gap \" + gap + \"ms)\");\n\t\tconfig.dtmfSender.insertDTMF(tones, duration, gap);\n\t\tcallbacks.success();\n\t}\n\n\t// Private method to destroy a plugin handle\n\tfunction destroyHandle(handleId, callbacks) {\n\t\tcallbacks = callbacks || {};\n\t\tcallbacks.success = (typeof callbacks.success == \"function\") ? callbacks.success : Janus.noop;\n\t\tcallbacks.error = (typeof callbacks.error == \"function\") ? callbacks.error : Janus.noop;\n\t\tvar noRequest = (callbacks.noRequest === true);\n\t\tJanus.log(\"Destroying handle \" + handleId + \" (only-locally=\" + noRequest + \")\");\n\t\tcleanupWebrtc(handleId);\n\t\tvar pluginHandle = pluginHandles[handleId];\n\t\tif(!pluginHandle || pluginHandle.detached) {\n\t\t\t// Plugin was already detached by Janus, calling detach again will return a handle not found error, so just exit here\n\t\t\tdelete pluginHandles[handleId];\n\t\t\tcallbacks.success();\n\t\t\treturn;\n\t\t}\n\t\tpluginHandle.detached = true;\n\t\tif(noRequest) {\n\t\t\t// We're only removing the handle locally\n\t\t\tdelete pluginHandles[handleId];\n\t\t\tcallbacks.success();\n\t\t\treturn;\n\t\t}\n\t\tif(!connected) {\n\t\t\tJanus.warn(\"Is the server down? (connected=false)\");\n\t\t\tcallbacks.error(\"Is the server down? (connected=false)\");\n\t\t\treturn;\n\t\t}\n\t\tvar request = { \"janus\": \"detach\", \"transaction\": Janus.randomString(12) };\n\t\tif(pluginHandle.token)\n\t\t\trequest[\"token\"] = pluginHandle.token;\n\t\tif(apisecret)\n\t\t\trequest[\"apisecret\"] = apisecret;\n\t\tif(websockets) {\n\t\t\trequest[\"session_id\"] = sessionId;\n\t\t\trequest[\"handle_id\"] = handleId;\n\t\t\tws.send(JSON.stringify(request));\n\t\t\tdelete pluginHandles[handleId];\n\t\t\tcallbacks.success();\n\t\t\treturn;\n\t\t}\n\t\tJanus.httpAPICall(server + \"/\" + sessionId + \"/\" + handleId, {\n\t\t\tverb: 'POST',\n\t\t\twithCredentials: withCredentials,\n\t\t\tbody: request,\n\t\t\tsuccess: function(json) {\n\t\t\t\tJanus.log(\"Destroyed handle:\");\n\t\t\t\tJanus.debug(json);\n\t\t\t\tif(json[\"janus\"] !== \"success\") {\n\t\t\t\t\tJanus.error(\"Ooops: \" + json[\"error\"].code + \" \" + json[\"error\"].reason);\t// FIXME\n\t\t\t\t}\n\t\t\t\tdelete pluginHandles[handleId];\n\t\t\t\tcallbacks.success();\n\t\t\t},\n\t\t\terror: function(textStatus, errorThrown) {\n\t\t\t\tJanus.error(textStatus + \":\", errorThrown);\t// FIXME\n\t\t\t\t// We cleanup anyway\n\t\t\t\tdelete pluginHandles[handleId];\n\t\t\t\tcallbacks.success();\n\t\t\t}\n\t\t});\n\t}\n\n\t// WebRTC stuff\n\tfunction streamsDone(handleId, jsep, media, callbacks, stream) {\n\t\tvar pluginHandle = pluginHandles[handleId];\n\t\tif(!pluginHandle || !pluginHandle.webrtcStuff) {\n\t\t\tJanus.warn(\"Invalid handle\");\n\t\t\t// Close all tracks if the given stream has been created internally\n\t\t\tif(!callbacks.stream) {\n\t\t\t\tJanus.stopAllTracks(stream);\n\t\t\t}\n\t\t\tcallbacks.error(\"Invalid handle\");\n\t\t\treturn;\n\t\t}\n\t\tvar config = pluginHandle.webrtcStuff;\n\t\tJanus.debug(\"streamsDone:\", stream);\n\t\tif(stream) {\n\t\t\tJanus.debug(\" -- Audio tracks:\", stream.getAudioTracks());\n\t\t\tJanus.debug(\" -- Video tracks:\", stream.getVideoTracks());\n\t\t}\n\t\t// We're now capturing the new stream: check if we're updating or if it's a new thing\n\t\tvar addTracks = false;\n\t\tif(!config.myStream || !media.update || (config.streamExternal && !media.replaceAudio && !media.replaceVideo)) {\n\t\t\tconfig.myStream = stream;\n\t\t\taddTracks = true;\n\t\t} else {\n\t\t\t// We only need to update the existing stream\n\t\t\tif(((!media.update && isAudioSendEnabled(media)) || (media.update && (media.addAudio || media.replaceAudio))) &&\n\t\t\t\t\tstream.getAudioTracks() && stream.getAudioTracks().length) {\n\t\t\t\tconfig.myStream.addTrack(stream.getAudioTracks()[0]);\n\t\t\t\tif(Janus.unifiedPlan) {\n\t\t\t\t\t// Use Transceivers\n\t\t\t\t\tJanus.log((media.replaceAudio ? \"Replacing\" : \"Adding\") + \" audio track:\", stream.getAudioTracks()[0]);\n\t\t\t\t\tvar audioTransceiver = null;\n\t\t\t\t\tconst transceivers = config.pc.getTransceivers();\n\t\t\t\t\tif(transceivers && transceivers.length > 0) {\n\t\t\t\t\t\tfor(const t of transceivers) {\n\t\t\t\t\t\t\tif((t.sender && t.sender.track && t.sender.track.kind === \"audio\") ||\n\t\t\t\t\t\t\t\t\t(t.receiver && t.receiver.track && t.receiver.track.kind === \"audio\")) {\n\t\t\t\t\t\t\t\taudioTransceiver = t;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif(audioTransceiver && audioTransceiver.sender) {\n\t\t\t\t\t\taudioTransceiver.sender.replaceTrack(stream.getAudioTracks()[0]);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconfig.pc.addTrack(stream.getAudioTracks()[0], stream);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tJanus.log((media.replaceAudio ? \"Replacing\" : \"Adding\") + \" audio track:\", stream.getAudioTracks()[0]);\n\t\t\t\t\tconfig.pc.addTrack(stream.getAudioTracks()[0], stream);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(((!media.update && isVideoSendEnabled(media)) || (media.update && (media.addVideo || media.replaceVideo))) &&\n\t\t\t\t\tstream.getVideoTracks() && stream.getVideoTracks().length) {\n\t\t\t\tconfig.myStream.addTrack(stream.getVideoTracks()[0]);\n\t\t\t\tif(Janus.unifiedPlan) {\n\t\t\t\t\t// Use Transceivers\n\t\t\t\t\tJanus.log((media.replaceVideo ? \"Replacing\" : \"Adding\") + \" video track:\", stream.getVideoTracks()[0]);\n\t\t\t\t\tvar videoTransceiver = null;\n\t\t\t\t\tconst transceivers = config.pc.getTransceivers();\n\t\t\t\t\tif(transceivers && transceivers.length > 0) {\n\t\t\t\t\t\tfor(const t of transceivers) {\n\t\t\t\t\t\t\tif((t.sender && t.sender.track && t.sender.track.kind === \"video\") ||\n\t\t\t\t\t\t\t\t\t(t.receiver && t.receiver.track && t.receiver.track.kind === \"video\")) {\n\t\t\t\t\t\t\t\tvideoTransceiver = t;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif(videoTransceiver && videoTransceiver.sender) {\n\t\t\t\t\t\tvideoTransceiver.sender.replaceTrack(stream.getVideoTracks()[0]);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconfig.pc.addTrack(stream.getVideoTracks()[0], stream);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tJanus.log((media.replaceVideo ? \"Replacing\" : \"Adding\") + \" video track:\", stream.getVideoTracks()[0]);\n\t\t\t\t\tconfig.pc.addTrack(stream.getVideoTracks()[0], stream);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// If we still need to create a PeerConnection, let's do that\n\t\tif(!config.pc) {\n\t\t\tvar pc_config = {\"iceServers\": iceServers, \"iceTransportPolicy\": iceTransportPolicy, \"bundlePolicy\": bundlePolicy};\n\t\t\tif(Janus.webRTCAdapter.browserDetails.browser === \"chrome\") {\n\t\t\t\t// For Chrome versions before 72, we force a plan-b semantic, and unified-plan otherwise\n\t\t\t\tpc_config[\"sdpSemantics\"] = (Janus.webRTCAdapter.browserDetails.version < 72) ? \"plan-b\" : \"unified-plan\";\n\t\t\t}\n\t\t\tvar pc_constraints = {\n\t\t\t\t\"optional\": [{\"DtlsSrtpKeyAgreement\": true}]\n\t\t\t};\n\t\t\tif(ipv6Support) {\n\t\t\t\tpc_constraints.optional.push({\"googIPv6\":true});\n\t\t\t}\n\t\t\t// Any custom constraint to add?\n\t\t\tif(callbacks.rtcConstraints && typeof callbacks.rtcConstraints === 'object') {\n\t\t\t\tJanus.debug(\"Adding custom PeerConnection constraints:\", callbacks.rtcConstraints);\n\t\t\t\tfor(var i in callbacks.rtcConstraints) {\n\t\t\t\t\tpc_constraints.optional.push(callbacks.rtcConstraints[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(Janus.webRTCAdapter.browserDetails.browser === \"edge\") {\n\t\t\t\t// This is Edge, enable BUNDLE explicitly\n\t\t\t\tpc_config.bundlePolicy = \"max-bundle\";\n\t\t\t}\n\t\t\t// Check if a sender or receiver transform has been provided\n\t\t\tif(RTCRtpSender && (RTCRtpSender.prototype.createEncodedStreams ||\n\t\t\t\t\t(RTCRtpSender.prototype.createEncodedAudioStreams &&\n\t\t\t\t\tRTCRtpSender.prototype.createEncodedVideoStreams)) &&\n\t\t\t\t\t(callbacks.senderTransforms || callbacks.receiverTransforms)) {\n\t\t\t\tconfig.senderTransforms = callbacks.senderTransforms;\n\t\t\t\tconfig.receiverTransforms = callbacks.receiverTransforms;\n\t\t\t\tpc_config[\"forceEncodedAudioInsertableStreams\"] = true;\n\t\t\t\tpc_config[\"forceEncodedVideoInsertableStreams\"] = true;\n\t\t\t\tpc_config[\"encodedInsertableStreams\"] = true;\n\t\t\t}\n\t\t\tJanus.log(\"Creating PeerConnection\");\n\t\t\tJanus.debug(pc_constraints);\n\t\t\tconfig.pc = new RTCPeerConnection(pc_config, pc_constraints);\n\t\t\tJanus.debug(config.pc);\n\t\t\tif(config.pc.getStats) {\t// FIXME\n\t\t\t\tconfig.volume = {};\n\t\t\t\tconfig.bitrate.value = \"0 kbits/sec\";\n\t\t\t}\n\t\t\tJanus.log(\"Preparing local SDP and gathering candidates (trickle=\" + config.trickle + \")\");\n\t\t\tconfig.pc.oniceconnectionstatechange = function() {\n\t\t\t\tif(config.pc)\n\t\t\t\t\tpluginHandle.iceState(config.pc.iceConnectionState);\n\t\t\t};\n\t\t\tconfig.pc.onicecandidate = function(event) {\n\t\t\t\tif (!event.candidate ||\n\t\t\t\t\t\t(Janus.webRTCAdapter.browserDetails.browser === 'edge' && event.candidate.candidate.indexOf('endOfCandidates') > 0)) {\n\t\t\t\t\tJanus.log(\"End of candidates.\");\n\t\t\t\t\tconfig.iceDone = true;\n\t\t\t\t\tif(config.trickle === true) {\n\t\t\t\t\t\t// Notify end of candidates\n\t\t\t\t\t\tsendTrickleCandidate(handleId, {\"completed\": true});\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// No trickle, time to send the complete SDP (including all candidates)\n\t\t\t\t\t\tsendSDP(handleId, callbacks);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// JSON.stringify doesn't work on some WebRTC objects anymore\n\t\t\t\t\t// See https://code.google.com/p/chromium/issues/detail?id=467366\n\t\t\t\t\tvar candidate = {\n\t\t\t\t\t\t\"candidate\": event.candidate.candidate,\n\t\t\t\t\t\t\"sdpMid\": event.candidate.sdpMid,\n\t\t\t\t\t\t\"sdpMLineIndex\": event.candidate.sdpMLineIndex\n\t\t\t\t\t};\n\t\t\t\t\tif(config.trickle === true) {\n\t\t\t\t\t\t// Send candidate\n\t\t\t\t\t\tsendTrickleCandidate(handleId, candidate);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t\tconfig.pc.ontrack = function(event) {\n\t\t\t\tJanus.log(\"Handling Remote Track\");\n\t\t\t\tJanus.debug(event);\n\t\t\t\tif(!event.streams)\n\t\t\t\t\treturn;\n\t\t\t\tconfig.remoteStream = event.streams[0];\n\t\t\t\tpluginHandle.onremotestream(config.remoteStream);\n\t\t\t\tif(event.track.onended)\n\t\t\t\t\treturn;\n\t\t\t\tif(config.receiverTransforms) {\n\t\t\t\t\tvar receiverStreams = null;\n\t\t\t\t\tif(RTCRtpSender.prototype.createEncodedStreams) {\n\t\t\t\t\t\treceiverStreams = event.receiver.createEncodedStreams();\n\t\t\t\t\t} else if(RTCRtpSender.prototype.createAudioEncodedStreams || RTCRtpSender.prototype.createEncodedVideoStreams) {\n\t\t\t\t\t\tif(event.track.kind === \"audio\" && config.receiverTransforms[\"audio\"]) {\n\t\t\t\t\t\t\treceiverStreams = event.receiver.createEncodedAudioStreams();\n\t\t\t\t\t\t} else if(event.track.kind === \"video\" && config.receiverTransforms[\"video\"]) {\n\t\t\t\t\t\t\treceiverStreams = event.receiver.createEncodedVideoStreams();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif(receiverStreams) {\n\t\t\t\t\t\tconsole.log(receiverStreams);\n\t\t\t\t\t\tif(receiverStreams.readableStream && receiverStreams.writableStream) {\n\t\t\t\t\t\t\treceiverStreams.readableStream\n\t\t\t\t\t\t\t\t.pipeThrough(config.receiverTransforms[event.track.kind])\n\t\t\t\t\t\t\t\t.pipeTo(receiverStreams.writableStream);\n\t\t\t\t\t\t} else if(receiverStreams.readable && receiverStreams.writable) {\n\t\t\t\t\t\t\treceiverStreams.readable\n\t\t\t\t\t\t\t\t.pipeThrough(config.receiverTransforms[event.track.kind])\n\t\t\t\t\t\t\t\t.pipeTo(receiverStreams.writable);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tvar trackMutedTimeoutId = null;\n\t\t\t\tJanus.log(\"Adding onended callback to track:\", event.track);\n\t\t\t\tevent.track.onended = function(ev) {\n\t\t\t\t\tJanus.log(\"Remote track removed:\", ev);\n\t\t\t\t\tif(config.remoteStream) {\n\t\t\t\t\t\tclearTimeout(trackMutedTimeoutId);\n\t\t\t\t\t\tconfig.remoteStream.removeTrack(ev.target);\n\t\t\t\t\t\tpluginHandle.onremotestream(config.remoteStream);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tevent.track.onmute = function(ev) {\n\t\t\t\t\tJanus.log(\"Remote track muted:\", ev);\n\t\t\t\t\tif(config.remoteStream && trackMutedTimeoutId == null) {\n\t\t\t\t\t\ttrackMutedTimeoutId = setTimeout(function() {\n\t\t\t\t\t\t\tJanus.log(\"Removing remote track\");\n\t\t\t\t\t\t\tif (config.remoteStream) {\n\t\t\t\t\t\t\t\tconfig.remoteStream.removeTrack(ev.target);\n\t\t\t\t\t\t\t\tpluginHandle.onremotestream(config.remoteStream);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\ttrackMutedTimeoutId = null;\n\t\t\t\t\t\t// Chrome seems to raise mute events only at multiples of 834ms;\n\t\t\t\t\t\t// we set the timeout to three times this value (rounded to 840ms)\n\t\t\t\t\t\t}, 3 * 840);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tevent.track.onunmute = function(ev) {\n\t\t\t\t\tJanus.log(\"Remote track flowing again:\", ev);\n\t\t\t\t\tif(trackMutedTimeoutId != null) {\n\t\t\t\t\t\tclearTimeout(trackMutedTimeoutId);\n\t\t\t\t\t\ttrackMutedTimeoutId = null;\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconfig.remoteStream.addTrack(ev.target);\n\t\t\t\t\t\t\tpluginHandle.onremotestream(config.remoteStream);\n\t\t\t\t\t\t} catch(e) {\n\t\t\t\t\t\t\tJanus.error(e);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t};\n\t\t}\n\t\tif(addTracks && stream) {\n\t\t\tJanus.log('Adding local stream');\n\t\t\tvar simulcast = (callbacks.simulcast === true || callbacks.simulcast2 === true) && Janus.unifiedPlan;\n\t\t\tvar svc = callbacks.svc;\n\t\t\tstream.getTracks().forEach(function(track) {\n\t\t\t\tJanus.log('Adding local track:', track);\n\t\t\t\tvar sender = null;\n\t\t\t\tif((!simulcast && !svc) || track.kind === 'audio') {\n\t\t\t\t\tsender = config.pc.addTrack(track, stream);\n\t\t\t\t} else if(simulcast) {\n\t\t\t\t\tJanus.log('Enabling rid-based simulcasting:', track);\n\t\t\t\t\tlet maxBitrates = getMaxBitrates(callbacks.simulcastMaxBitrates);\n\t\t\t\t\tlet tr = config.pc.addTransceiver(track, {\n\t\t\t\t\t\tdirection: \"sendrecv\",\n\t\t\t\t\t\tstreams: [stream],\n\t\t\t\t\t\tsendEncodings: callbacks.sendEncodings || [\n\t\t\t\t\t\t\t{ rid: \"h\", active: true, maxBitrate: maxBitrates.high },\n\t\t\t\t\t\t\t{ rid: \"m\", active: true, maxBitrate: maxBitrates.medium, scaleResolutionDownBy: 2 },\n\t\t\t\t\t\t\t{ rid: \"l\", active: true, maxBitrate: maxBitrates.low, scaleResolutionDownBy: 4 }\n\t\t\t\t\t\t]\n\t\t\t\t\t});\n\t\t\t\t\tif(tr)\n\t\t\t\t\t\tsender = tr.sender;\n\t\t\t\t} else {\n\t\t\t\t\tJanus.log('Enabling SVC (' + svc + '):', track);\n\t\t\t\t\tlet tr = config.pc.addTransceiver(track, {\n\t\t\t\t\t\tdirection: \"sendrecv\",\n\t\t\t\t\t\tstreams: [stream],\n\t\t\t\t\t\tsendEncodings: [\n\t\t\t\t\t\t\t{ scalabilityMode: svc }\n\t\t\t\t\t\t]\n\t\t\t\t\t});\n\t\t\t\t\tif(tr)\n\t\t\t\t\t\tsender = tr.sender;\n\t\t\t\t}\n\t\t\t\t// Check if insertable streams are involved\n\t\t\t\tif(sender && config.senderTransforms) {\n\t\t\t\t\tvar senderStreams = null;\n\t\t\t\t\tif(RTCRtpSender.prototype.createEncodedStreams) {\n\t\t\t\t\t\tsenderStreams = sender.createEncodedStreams();\n\t\t\t\t\t} else if(RTCRtpSender.prototype.createAudioEncodedStreams || RTCRtpSender.prototype.createEncodedVideoStreams) {\n\t\t\t\t\t\tif(sender.track.kind === \"audio\" && config.senderTransforms[\"audio\"]) {\n\t\t\t\t\t\t\tsenderStreams = sender.createEncodedAudioStreams();\n\t\t\t\t\t\t} else if(sender.track.kind === \"video\" && config.senderTransforms[\"video\"]) {\n\t\t\t\t\t\t\tsenderStreams = sender.createEncodedVideoStreams();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif(senderStreams) {\n\t\t\t\t\t\tconsole.log(senderStreams);\n\t\t\t\t\t\tif(senderStreams.readableStream && senderStreams.writableStream) {\n\t\t\t\t\t\t\tsenderStreams.readableStream\n\t\t\t\t\t\t\t\t.pipeThrough(config.senderTransforms[sender.track.kind])\n\t\t\t\t\t\t\t\t.pipeTo(senderStreams.writableStream);\n\t\t\t\t\t\t} else if(senderStreams.readable && senderStreams.writable) {\n\t\t\t\t\t\t\tsenderStreams.readable\n\t\t\t\t\t\t\t\t.pipeThrough(config.senderTransforms[sender.track.kind])\n\t\t\t\t\t\t\t\t.pipeTo(senderStreams.writable);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\t// Any data channel to create?\n\t\tif(isDataEnabled(media) && !config.dataChannel[Janus.dataChanDefaultLabel]) {\n\t\t\tJanus.log(\"Creating default data channel\");\n\t\t\tcreateDataChannel(handleId, Janus.dataChanDefaultLabel, null, false);\n\t\t\tconfig.pc.ondatachannel = function(event) {\n\t\t\t\tJanus.log(\"Data channel created by Janus:\", event);\n\t\t\t\tcreateDataChannel(handleId, event.channel.label, event.channel.protocol, event.channel);\n\t\t\t};\n\t\t}\n\t\t// If there's a new local stream, let's notify the application\n\t\tif(config.myStream) {\n\t\t\tpluginHandle.onlocalstream(config.myStream);\n\t\t}\n\t\t// Create offer/answer now\n\t\tif(!jsep) {\n\t\t\tcreateOffer(handleId, media, callbacks);\n\t\t} else {\n\t\t\tconfig.pc.setRemoteDescription(jsep)\n\t\t\t\t.then(function() {\n\t\t\t\t\tJanus.log(\"Remote description accepted!\");\n\t\t\t\t\tconfig.remoteSdp = jsep.sdp;\n\t\t\t\t\t// Any trickle candidate we cached?\n\t\t\t\t\tif(config.candidates && config.candidates.length > 0) {\n\t\t\t\t\t\tfor(var i = 0; i< config.candidates.length; i++) {\n\t\t\t\t\t\t\tvar candidate = config.candidates[i];\n\t\t\t\t\t\t\tJanus.debug(\"Adding remote candidate:\", candidate);\n\t\t\t\t\t\t\tif(!candidate || candidate.completed === true) {\n\t\t\t\t\t\t\t\t// end-of-candidates\n\t\t\t\t\t\t\t\tconfig.pc.addIceCandidate(Janus.endOfCandidates);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t// New candidate\n\t\t\t\t\t\t\t\tconfig.pc.addIceCandidate(candidate);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconfig.candidates = [];\n\t\t\t\t\t}\n\t\t\t\t\t// Create the answer now\n\t\t\t\t\tcreateAnswer(handleId, media, callbacks);\n\t\t\t\t}, callbacks.error);\n\t\t}\n\t}\n\n\tfunction prepareWebrtc(handleId, offer, callbacks) {\n\t\tcallbacks = callbacks || {};\n\t\tcallbacks.success = (typeof callbacks.success == \"function\") ? callbacks.success : Janus.noop;\n\t\tcallbacks.error = (typeof callbacks.error == \"function\") ? callbacks.error : webrtcError;\n\t\tvar jsep = callbacks.jsep;\n\t\tif(offer && jsep) {\n\t\t\tJanus.error(\"Provided a JSEP to a createOffer\");\n\t\t\tcallbacks.error(\"Provided a JSEP to a createOffer\");\n\t\t\treturn;\n\t\t} else if(!offer && (!jsep || !jsep.type || !jsep.sdp)) {\n\t\t\tJanus.error(\"A valid JSEP is required for createAnswer\");\n\t\t\tcallbacks.error(\"A valid JSEP is required for createAnswer\");\n\t\t\treturn;\n\t\t}\n\t\t/* Check that callbacks.media is a (not null) Object */\n\t\tcallbacks.media = (typeof callbacks.media === 'object' && callbacks.media) ? callbacks.media : { audio: true, video: true };\n\t\tvar media = callbacks.media;\n\t\tvar pluginHandle = pluginHandles[handleId];\n\t\tif(!pluginHandle || !pluginHandle.webrtcStuff) {\n\t\t\tJanus.warn(\"Invalid handle\");\n\t\t\tcallbacks.error(\"Invalid handle\");\n\t\t\treturn;\n\t\t}\n\t\tvar config = pluginHandle.webrtcStuff;\n\t\tconfig.trickle = isTrickleEnabled(callbacks.trickle);\n\t\t// Are we updating a session?\n\t\tif(!config.pc) {\n\t\t\t// Nope, new PeerConnection\n\t\t\tmedia.update = false;\n\t\t\tmedia.keepAudio = false;\n\t\t\tmedia.keepVideo = false;\n\t\t} else {\n\t\t\tJanus.log(\"Updating existing media session\");\n\t\t\tmedia.update = true;\n\t\t\t// Check if there's anything to add/remove/replace, or if we\n\t\t\t// can go directly to preparing the new SDP offer or answer\n\t\t\tif(callbacks.stream) {\n\t\t\t\t// External stream: is this the same as the one we were using before?\n\t\t\t\tif(callbacks.stream !== config.myStream) {\n\t\t\t\t\tJanus.log(\"Renegotiation involves a new external stream\");\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Check if there are changes on audio\n\t\t\t\tif(media.addAudio) {\n\t\t\t\t\tmedia.keepAudio = false;\n\t\t\t\t\tmedia.replaceAudio = false;\n\t\t\t\t\tmedia.removeAudio = false;\n\t\t\t\t\tmedia.audioSend = true;\n\t\t\t\t\tif(config.myStream && config.myStream.getAudioTracks() && config.myStream.getAudioTracks().length) {\n\t\t\t\t\t\tJanus.error(\"Can't add audio stream, there already is one\");\n\t\t\t\t\t\tcallbacks.error(\"Can't add audio stream, there already is one\");\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t} else if(media.removeAudio) {\n\t\t\t\t\tmedia.keepAudio = false;\n\t\t\t\t\tmedia.replaceAudio = false;\n\t\t\t\t\tmedia.addAudio = false;\n\t\t\t\t\tmedia.audioSend = false;\n\t\t\t\t} else if(media.replaceAudio) {\n\t\t\t\t\tmedia.keepAudio = false;\n\t\t\t\t\tmedia.addAudio = false;\n\t\t\t\t\tmedia.removeAudio = false;\n\t\t\t\t\tmedia.audioSend = true;\n\t\t\t\t}\n\t\t\t\tif(!config.myStream) {\n\t\t\t\t\t// No media stream: if we were asked to replace, it's actually an \"add\"\n\t\t\t\t\tif(media.replaceAudio) {\n\t\t\t\t\t\tmedia.keepAudio = false;\n\t\t\t\t\t\tmedia.replaceAudio = false;\n\t\t\t\t\t\tmedia.addAudio = true;\n\t\t\t\t\t\tmedia.audioSend = true;\n\t\t\t\t\t}\n\t\t\t\t\tif(isAudioSendEnabled(media)) {\n\t\t\t\t\t\tmedia.keepAudio = false;\n\t\t\t\t\t\tmedia.addAudio = true;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif(!config.myStream.getAudioTracks() || config.myStream.getAudioTracks().length === 0) {\n\t\t\t\t\t\t// No audio track: if we were asked to replace, it's actually an \"add\"\n\t\t\t\t\t\tif(media.replaceAudio) {\n\t\t\t\t\t\t\tmedia.keepAudio = false;\n\t\t\t\t\t\t\tmedia.replaceAudio = false;\n\t\t\t\t\t\t\tmedia.addAudio = true;\n\t\t\t\t\t\t\tmedia.audioSend = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(isAudioSendEnabled(media)) {\n\t\t\t\t\t\t\tmedia.keepAudio = false;\n\t\t\t\t\t\t\tmedia.addAudio = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// We have an audio track: should we keep it as it is?\n\t\t\t\t\t\tif(isAudioSendEnabled(media) &&\n\t\t\t\t\t\t\t\t!media.removeAudio && !media.replaceAudio) {\n\t\t\t\t\t\t\tmedia.keepAudio = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Check if there are changes on video\n\t\t\t\tif(media.addVideo) {\n\t\t\t\t\tmedia.keepVideo = false;\n\t\t\t\t\tmedia.replaceVideo = false;\n\t\t\t\t\tmedia.removeVideo = false;\n\t\t\t\t\tmedia.videoSend = true;\n\t\t\t\t\tif(config.myStream && config.myStream.getVideoTracks() && config.myStream.getVideoTracks().length) {\n\t\t\t\t\t\tJanus.error(\"Can't add video stream, there already is one\");\n\t\t\t\t\t\tcallbacks.error(\"Can't add video stream, there already is one\");\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t} else if(media.removeVideo) {\n\t\t\t\t\tmedia.keepVideo = false;\n\t\t\t\t\tmedia.replaceVideo = false;\n\t\t\t\t\tmedia.addVideo = false;\n\t\t\t\t\tmedia.videoSend = false;\n\t\t\t\t} else if(media.replaceVideo) {\n\t\t\t\t\tmedia.keepVideo = false;\n\t\t\t\t\tmedia.addVideo = false;\n\t\t\t\t\tmedia.removeVideo = false;\n\t\t\t\t\tmedia.videoSend = true;\n\t\t\t\t}\n\t\t\t\tif(!config.myStream) {\n\t\t\t\t\t// No media stream: if we were asked to replace, it's actually an \"add\"\n\t\t\t\t\tif(media.replaceVideo) {\n\t\t\t\t\t\tmedia.keepVideo = false;\n\t\t\t\t\t\tmedia.replaceVideo = false;\n\t\t\t\t\t\tmedia.addVideo = true;\n\t\t\t\t\t\tmedia.videoSend = true;\n\t\t\t\t\t}\n\t\t\t\t\tif(isVideoSendEnabled(media)) {\n\t\t\t\t\t\tmedia.keepVideo = false;\n\t\t\t\t\t\tmedia.addVideo = true;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif(!config.myStream.getVideoTracks() || config.myStream.getVideoTracks().length === 0) {\n\t\t\t\t\t\t// No video track: if we were asked to replace, it's actually an \"add\"\n\t\t\t\t\t\tif(media.replaceVideo) {\n\t\t\t\t\t\t\tmedia.keepVideo = false;\n\t\t\t\t\t\t\tmedia.replaceVideo = false;\n\t\t\t\t\t\t\tmedia.addVideo = true;\n\t\t\t\t\t\t\tmedia.videoSend = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(isVideoSendEnabled(media)) {\n\t\t\t\t\t\t\tmedia.keepVideo = false;\n\t\t\t\t\t\t\tmedia.addVideo = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// We have a video track: should we keep it as it is?\n\t\t\t\t\t\tif(isVideoSendEnabled(media) && !media.removeVideo && !media.replaceVideo) {\n\t\t\t\t\t\t\tmedia.keepVideo = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Data channels can only be added\n\t\t\t\tif(media.addData) {\n\t\t\t\t\tmedia.data = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// If we're updating and keeping all tracks, let's skip the getUserMedia part\n\t\t\tif((isAudioSendEnabled(media) && media.keepAudio) &&\n\t\t\t\t\t(isVideoSendEnabled(media) && media.keepVideo)) {\n\t\t\t\tpluginHandle.consentDialog(false);\n\t\t\t\tstreamsDone(handleId, jsep, media, callbacks, config.myStream);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\t// If we're updating, check if we need to remove/replace one of the tracks\n\t\tif(media.update && (!config.streamExternal || (config.streamExternal && (media.replaceAudio || media.replaceVideo)))) {\n\t\t\tif(media.removeAudio || media.replaceAudio) {\n\t\t\t\tif(config.myStream && config.myStream.getAudioTracks() && config.myStream.getAudioTracks().length) {\n\t\t\t\t\tvar at = config.myStream.getAudioTracks()[0];\n\t\t\t\t\tJanus.log(\"Removing audio track:\", at);\n\t\t\t\t\tconfig.myStream.removeTrack(at);\n\t\t\t\t\ttry {\n\t\t\t\t\t\tat.stop();\n\t\t\t\t\t} catch(e) {}\n\t\t\t\t}\n\t\t\t\tif(config.pc.getSenders() && config.pc.getSenders().length) {\n\t\t\t\t\tvar ra = true;\n\t\t\t\t\tif(media.replaceAudio && Janus.unifiedPlan) {\n\t\t\t\t\t\t// We can use replaceTrack\n\t\t\t\t\t\tra = false;\n\t\t\t\t\t}\n\t\t\t\t\tif(ra) {\n\t\t\t\t\t\tfor(var asnd of config.pc.getSenders()) {\n\t\t\t\t\t\t\tif(asnd && asnd.track && asnd.track.kind === \"audio\") {\n\t\t\t\t\t\t\t\tJanus.log(\"Removing audio sender:\", asnd);\n\t\t\t\t\t\t\t\tconfig.pc.removeTrack(asnd);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(media.removeVideo || media.replaceVideo) {\n\t\t\t\tif(config.myStream && config.myStream.getVideoTracks() && config.myStream.getVideoTracks().length) {\n\t\t\t\t\tvar vt = config.myStream.getVideoTracks()[0];\n\t\t\t\t\tJanus.log(\"Removing video track:\", vt);\n\t\t\t\t\tconfig.myStream.removeTrack(vt);\n\t\t\t\t\ttry {\n\t\t\t\t\t\tvt.stop();\n\t\t\t\t\t} catch(e) {}\n\t\t\t\t}\n\t\t\t\tif(config.pc.getSenders() && config.pc.getSenders().length) {\n\t\t\t\t\tvar rv = true;\n\t\t\t\t\tif(media.replaceVideo && Janus.unifiedPlan) {\n\t\t\t\t\t\t// We can use replaceTrack\n\t\t\t\t\t\trv = false;\n\t\t\t\t\t}\n\t\t\t\t\tif(rv) {\n\t\t\t\t\t\tfor(var vsnd of config.pc.getSenders()) {\n\t\t\t\t\t\t\tif(vsnd && vsnd.track && vsnd.track.kind === \"video\") {\n\t\t\t\t\t\t\t\tJanus.log(\"Removing video sender:\", vsnd);\n\t\t\t\t\t\t\t\tconfig.pc.removeTrack(vsnd);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Was a MediaStream object passed, or do we need to take care of that?\n\t\tif(callbacks.stream) {\n\t\t\tvar stream = callbacks.stream;\n\t\t\tJanus.log(\"MediaStream provided by the application\");\n\t\t\tJanus.debug(stream);\n\t\t\t// If this is an update, let's check if we need to release the previous stream\n\t\t\tif(media.update && config.myStream && config.myStream !== callbacks.stream && !config.streamExternal && !media.replaceAudio && !media.replaceVideo) {\n\t\t\t\t// We're replacing a stream we captured ourselves with an external one\n\t\t\t\tJanus.stopAllTracks(config.myStream);\n\t\t\t\tconfig.myStream = null;\n\t\t\t}\n\t\t\t// Skip the getUserMedia part\n\t\t\tconfig.streamExternal = true;\n\t\t\tpluginHandle.consentDialog(false);\n\t\t\tstreamsDone(handleId, jsep, media, callbacks, stream);\n\t\t\treturn;\n\t\t}\n\t\tif(isAudioSendEnabled(media) || isVideoSendEnabled(media)) {\n\t\t\tif(!Janus.isGetUserMediaAvailable()) {\n\t\t\t\tcallbacks.error(\"getUserMedia not available\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar constraints = { mandatory: {}, optional: []};\n\t\t\tpluginHandle.consentDialog(true);\n\t\t\tvar audioSupport = isAudioSendEnabled(media);\n\t\t\tif(audioSupport && media && typeof media.audio === 'object')\n\t\t\t\taudioSupport = media.audio;\n\t\t\tvar videoSupport = isVideoSendEnabled(media);\n\t\t\tif(videoSupport && media) {\n\t\t\t\tvar simulcast = (callbacks.simulcast === true || callbacks.simulcast2 === true);\n\t\t\t\tvar svc = callbacks.svc;\n\t\t\t\tif((simulcast || svc) && !jsep && !media.video)\n\t\t\t\t\tmedia.video = \"hires\";\n\t\t\t\tif(media.video && media.video != 'screen' && media.video != 'window') {\n\t\t\t\t\tif(typeof media.video === 'object') {\n\t\t\t\t\t\tvideoSupport = media.video;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar width = 0;\n\t\t\t\t\t\tvar height = 0;\n\t\t\t\t\t\tif(media.video === 'lowres') {\n\t\t\t\t\t\t\t// Small resolution, 4:3\n\t\t\t\t\t\t\theight = 240;\n\t\t\t\t\t\t\twidth = 320;\n\t\t\t\t\t\t} else if(media.video === 'lowres-16:9') {\n\t\t\t\t\t\t\t// Small resolution, 16:9\n\t\t\t\t\t\t\theight = 180;\n\t\t\t\t\t\t\twidth = 320;\n\t\t\t\t\t\t} else if(media.video === 'hires' || media.video === 'hires-16:9' || media.video === 'hdres') {\n\t\t\t\t\t\t\t// High(HD) resolution is only 16:9\n\t\t\t\t\t\t\theight = 720;\n\t\t\t\t\t\t\twidth = 1280;\n\t\t\t\t\t\t} else if(media.video === 'fhdres') {\n\t\t\t\t\t\t\t// Full HD resolution is only 16:9\n\t\t\t\t\t\t\theight = 1080;\n\t\t\t\t\t\t\twidth = 1920;\n\t\t\t\t\t\t} else if(media.video === '4kres') {\n\t\t\t\t\t\t\t// 4K resolution is only 16:9\n\t\t\t\t\t\t\theight = 2160;\n\t\t\t\t\t\t\twidth = 3840;\n\t\t\t\t\t\t} else if(media.video === 'stdres') {\n\t\t\t\t\t\t\t// Normal resolution, 4:3\n\t\t\t\t\t\t\theight = 480;\n\t\t\t\t\t\t\twidth = 640;\n\t\t\t\t\t\t} else if(media.video === 'stdres-16:9') {\n\t\t\t\t\t\t\t// Normal resolution, 16:9\n\t\t\t\t\t\t\theight = 360;\n\t\t\t\t\t\t\twidth = 640;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tJanus.log(\"Default video setting is stdres 4:3\");\n\t\t\t\t\t\t\theight = 480;\n\t\t\t\t\t\t\twidth = 640;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tJanus.log(\"Adding media constraint:\", media.video);\n\t\t\t\t\t\tvideoSupport = {\n\t\t\t\t\t\t\t'height': {'ideal': height},\n\t\t\t\t\t\t\t'width': {'ideal': width}\n\t\t\t\t\t\t};\n\t\t\t\t\t\tJanus.log(\"Adding video constraint:\", videoSupport);\n\t\t\t\t\t}\n\t\t\t\t} else if(media.video === 'screen' || media.video === 'window') {\n\t\t\t\t\tif(navigator.mediaDevices && navigator.mediaDevices.getDisplayMedia) {\n\t\t\t\t\t\t// The new experimental getDisplayMedia API is available, let's use that\n\t\t\t\t\t\t// https://groups.google.com/forum/#!topic/discuss-webrtc/Uf0SrR4uxzk\n\t\t\t\t\t\t// https://webrtchacks.com/chrome-screensharing-getdisplaymedia/\n\t\t\t\t\t\tconstraints.video = {};\n\t\t\t\t\t\tif(media.screenshareFrameRate) {\n\t\t\t\t\t\t\tconstraints.video.frameRate = media.screenshareFrameRate;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(media.screenshareHeight) {\n\t\t\t\t\t\t\tconstraints.video.height = media.screenshareHeight;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(media.screenshareWidth) {\n\t\t\t\t\t\t\tconstraints.video.width = media.screenshareWidth;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconstraints.audio = media.captureDesktopAudio;\n\t\t\t\t\t\tnavigator.mediaDevices.getDisplayMedia(constraints)\n\t\t\t\t\t\t\t.then(function(stream) {\n\t\t\t\t\t\t\t\tpluginHandle.consentDialog(false);\n\t\t\t\t\t\t\t\tif(isAudioSendEnabled(media) && !media.keepAudio) {\n\t\t\t\t\t\t\t\t\tnavigator.mediaDevices.getUserMedia({ audio: true, video: false })\n\t\t\t\t\t\t\t\t\t.then(function (audioStream) {\n\t\t\t\t\t\t\t\t\t\tstream.addTrack(audioStream.getAudioTracks()[0]);\n\t\t\t\t\t\t\t\t\t\tstreamsDone(handleId, jsep, media, callbacks, stream);\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tstreamsDone(handleId, jsep, media, callbacks, stream);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}, function (error) {\n\t\t\t\t\t\t\t\tpluginHandle.consentDialog(false);\n\t\t\t\t\t\t\t\tcallbacks.error(error);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t// We're going to try and use the extension for Chrome 34+, the old approach\n\t\t\t\t\t// for older versions of Chrome, or the experimental support in Firefox 33+\n\t\t\t\t\tconst callbackUserMedia = function(error, stream) {\n\t\t\t\t\t\tpluginHandle.consentDialog(false);\n\t\t\t\t\t\tif(error) {\n\t\t\t\t\t\t\tcallbacks.error(error);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tstreamsDone(handleId, jsep, media, callbacks, stream);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tconst getScreenMedia = function(constraints, gsmCallback, useAudio) {\n\t\t\t\t\t\tJanus.log(\"Adding media constraint (screen capture)\");\n\t\t\t\t\t\tJanus.debug(constraints);\n\t\t\t\t\t\tnavigator.mediaDevices.getUserMedia(constraints)\n\t\t\t\t\t\t\t.then(function(stream) {\n\t\t\t\t\t\t\t\tif(useAudio) {\n\t\t\t\t\t\t\t\t\tnavigator.mediaDevices.getUserMedia({ audio: true, video: false })\n\t\t\t\t\t\t\t\t\t.then(function (audioStream) {\n\t\t\t\t\t\t\t\t\t\tstream.addTrack(audioStream.getAudioTracks()[0]);\n\t\t\t\t\t\t\t\t\t\tgsmCallback(null, stream);\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tgsmCallback(null, stream);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t.catch(function(error) { pluginHandle.consentDialog(false); gsmCallback(error); });\n\t\t\t\t\t}\n\t\t\t\t\tif(Janus.webRTCAdapter.browserDetails.browser === 'chrome') {\n\t\t\t\t\t\tvar chromever = Janus.webRTCAdapter.browserDetails.version;\n\t\t\t\t\t\tvar maxver = 33;\n\t\t\t\t\t\tif(window.navigator.userAgent.match('Linux'))\n\t\t\t\t\t\t\tmaxver = 35;\t// \"known\" crash in chrome 34 and 35 on linux\n\t\t\t\t\t\tif(chromever >= 26 && chromever <= maxver) {\n\t\t\t\t\t\t\t// Chrome 26->33 requires some awkward chrome://flags manipulation\n\t\t\t\t\t\t\tconstraints = {\n\t\t\t\t\t\t\t\tvideo: {\n\t\t\t\t\t\t\t\t\tmandatory: {\n\t\t\t\t\t\t\t\t\t\tgoogLeakyBucket: true,\n\t\t\t\t\t\t\t\t\t\tmaxWidth: window.screen.width,\n\t\t\t\t\t\t\t\t\t\tmaxHeight: window.screen.height,\n\t\t\t\t\t\t\t\t\t\tminFrameRate: media.screenshareFrameRate,\n\t\t\t\t\t\t\t\t\t\tmaxFrameRate: media.screenshareFrameRate,\n\t\t\t\t\t\t\t\t\t\tchromeMediaSource: 'screen'\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\taudio: isAudioSendEnabled(media) && !media.keepAudio\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tgetScreenMedia(constraints, callbackUserMedia);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Chrome 34+ requires an extension\n\t\t\t\t\t\t\tJanus.extension.getScreen(function (error, sourceId) {\n\t\t\t\t\t\t\t\tif (error) {\n\t\t\t\t\t\t\t\t\tpluginHandle.consentDialog(false);\n\t\t\t\t\t\t\t\t\treturn callbacks.error(error);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tconstraints = {\n\t\t\t\t\t\t\t\t\taudio: false,\n\t\t\t\t\t\t\t\t\tvideo: {\n\t\t\t\t\t\t\t\t\t\tmandatory: {\n\t\t\t\t\t\t\t\t\t\t\tchromeMediaSource: 'desktop',\n\t\t\t\t\t\t\t\t\t\t\tmaxWidth: window.screen.width,\n\t\t\t\t\t\t\t\t\t\t\tmaxHeight: window.screen.height,\n\t\t\t\t\t\t\t\t\t\t\tminFrameRate: media.screenshareFrameRate,\n\t\t\t\t\t\t\t\t\t\t\tmaxFrameRate: media.screenshareFrameRate,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\toptional: [\n\t\t\t\t\t\t\t\t\t\t\t{googLeakyBucket: true},\n\t\t\t\t\t\t\t\t\t\t\t{googTemporalLayeredScreencast: true}\n\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\tconstraints.video.mandatory.chromeMediaSourceId = sourceId;\n\t\t\t\t\t\t\t\tgetScreenMedia(constraints, callbackUserMedia,\n\t\t\t\t\t\t\t\t\tisAudioSendEnabled(media) && !media.keepAudio);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if(Janus.webRTCAdapter.browserDetails.browser === 'firefox') {\n\t\t\t\t\t\tif(Janus.webRTCAdapter.browserDetails.version >= 33) {\n\t\t\t\t\t\t\t// Firefox 33+ has experimental support for screen sharing\n\t\t\t\t\t\t\tconstraints = {\n\t\t\t\t\t\t\t\tvideo: {\n\t\t\t\t\t\t\t\t\tmozMediaSource: media.video,\n\t\t\t\t\t\t\t\t\tmediaSource: media.video\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\taudio: isAudioSendEnabled(media) && !media.keepAudio\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tgetScreenMedia(constraints, function (err, stream) {\n\t\t\t\t\t\t\t\tcallbackUserMedia(err, stream);\n\t\t\t\t\t\t\t\t// Workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=1045810\n\t\t\t\t\t\t\t\tif (!err) {\n\t\t\t\t\t\t\t\t\tvar lastTime = stream.currentTime;\n\t\t\t\t\t\t\t\t\tvar polly = window.setInterval(function () {\n\t\t\t\t\t\t\t\t\t\tif(!stream)\n\t\t\t\t\t\t\t\t\t\t\twindow.clearInterval(polly);\n\t\t\t\t\t\t\t\t\t\tif(stream.currentTime == lastTime) {\n\t\t\t\t\t\t\t\t\t\t\twindow.clearInterval(polly);\n\t\t\t\t\t\t\t\t\t\t\tif(stream.onended) {\n\t\t\t\t\t\t\t\t\t\t\t\tstream.onended();\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\tlastTime = stream.currentTime;\n\t\t\t\t\t\t\t\t\t}, 500);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tvar error = new Error('NavigatorUserMediaError');\n\t\t\t\t\t\t\terror.name = 'Your version of Firefox does not support screen sharing, please install Firefox 33 (or more recent versions)';\n\t\t\t\t\t\t\tpluginHandle.consentDialog(false);\n\t\t\t\t\t\t\tcallbacks.error(error);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// If we got here, we're not screensharing\n\t\t\tif(!media || media.video !== 'screen') {\n\t\t\t\t// Check whether all media sources are actually available or not\n\t\t\t\tnavigator.mediaDevices.enumerateDevices().then(function(devices) {\n\t\t\t\t\tvar audioExist = devices.some(function(device) {\n\t\t\t\t\t\treturn device.kind === 'audioinput';\n\t\t\t\t\t}),\n\t\t\t\t\tvideoExist = isScreenSendEnabled(media) || devices.some(function(device) {\n\t\t\t\t\t\treturn device.kind === 'videoinput';\n\t\t\t\t\t});\n\n\t\t\t\t\t// Check whether a missing device is really a problem\n\t\t\t\t\tvar audioSend = isAudioSendEnabled(media);\n\t\t\t\t\tvar videoSend = isVideoSendEnabled(media);\n\t\t\t\t\tvar needAudioDevice = isAudioSendRequired(media);\n\t\t\t\t\tvar needVideoDevice = isVideoSendRequired(media);\n\t\t\t\t\tif(audioSend || videoSend || needAudioDevice || needVideoDevice) {\n\t\t\t\t\t\t// We need to send either audio or video\n\t\t\t\t\t\tvar haveAudioDevice = audioSend ? audioExist : false;\n\t\t\t\t\t\tvar haveVideoDevice = videoSend ? videoExist : false;\n\t\t\t\t\t\tif(!haveAudioDevice && !haveVideoDevice) {\n\t\t\t\t\t\t\t// FIXME Should we really give up, or just assume recvonly for both?\n\t\t\t\t\t\t\tpluginHandle.consentDialog(false);\n\t\t\t\t\t\t\tcallbacks.error('No capture device found');\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t} else if(!haveAudioDevice && needAudioDevice) {\n\t\t\t\t\t\t\tpluginHandle.consentDialog(false);\n\t\t\t\t\t\t\tcallbacks.error('Audio capture is required, but no capture device found');\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t} else if(!haveVideoDevice && needVideoDevice) {\n\t\t\t\t\t\t\tpluginHandle.consentDialog(false);\n\t\t\t\t\t\t\tcallbacks.error('Video capture is required, but no capture device found');\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tvar gumConstraints = {\n\t\t\t\t\t\taudio: (audioExist && !media.keepAudio) ? audioSupport : false,\n\t\t\t\t\t\tvideo: (videoExist && !media.keepVideo) ? videoSupport : false\n\t\t\t\t\t};\n\t\t\t\t\tJanus.debug(\"getUserMedia constraints\", gumConstraints);\n\t\t\t\t\tif (!gumConstraints.audio && !gumConstraints.video) {\n\t\t\t\t\t\tpluginHandle.consentDialog(false);\n\t\t\t\t\t\tstreamsDone(handleId, jsep, media, callbacks, stream);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnavigator.mediaDevices.getUserMedia(gumConstraints)\n\t\t\t\t\t\t\t.then(function(stream) {\n\t\t\t\t\t\t\t\tpluginHandle.consentDialog(false);\n\t\t\t\t\t\t\t\tstreamsDone(handleId, jsep, media, callbacks, stream);\n\t\t\t\t\t\t\t}).catch(function(error) {\n\t\t\t\t\t\t\t\tpluginHandle.consentDialog(false);\n\t\t\t\t\t\t\t\tcallbacks.error({code: error.code, name: error.name, message: error.message});\n\t\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.catch(function(error) {\n\t\t\t\t\tpluginHandle.consentDialog(false);\n\t\t\t\t\tcallbacks.error(error);\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\t// No need to do a getUserMedia, create offer/answer right away\n\t\t\tstreamsDone(handleId, jsep, media, callbacks);\n\t\t}\n\t}\n\n\tfunction prepareWebrtcPeer(handleId, callbacks) {\n\t\tcallbacks = callbacks || {};\n\t\tcallbacks.success = (typeof callbacks.success == \"function\") ? callbacks.success : Janus.noop;\n\t\tcallbacks.error = (typeof callbacks.error == \"function\") ? callbacks.error : webrtcError;\n\t\tcallbacks.customizeSdp = (typeof callbacks.customizeSdp == \"function\") ? callbacks.customizeSdp : Janus.noop;\n\t\tvar jsep = callbacks.jsep;\n\t\tvar pluginHandle = pluginHandles[handleId];\n\t\tif(!pluginHandle || !pluginHandle.webrtcStuff) {\n\t\t\tJanus.warn(\"Invalid handle\");\n\t\t\tcallbacks.error(\"Invalid handle\");\n\t\t\treturn;\n\t\t}\n\t\tvar config = pluginHandle.webrtcStuff;\n\t\tif(jsep) {\n\t\t\tif(!config.pc) {\n\t\t\t\tJanus.warn(\"Wait, no PeerConnection?? if this is an answer, use createAnswer and not handleRemoteJsep\");\n\t\t\t\tcallbacks.error(\"No PeerConnection: if this is an answer, use createAnswer and not handleRemoteJsep\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcallbacks.customizeSdp(jsep);\n\t\t\tconfig.pc.setRemoteDescription(jsep)\n\t\t\t\t.then(function() {\n\t\t\t\t\tJanus.log(\"Remote description accepted!\");\n\t\t\t\t\tconfig.remoteSdp = jsep.sdp;\n\t\t\t\t\t// Any trickle candidate we cached?\n\t\t\t\t\tif(config.candidates && config.candidates.length > 0) {\n\t\t\t\t\t\tfor(var i = 0; i< config.candidates.length; i++) {\n\t\t\t\t\t\t\tvar candidate = config.candidates[i];\n\t\t\t\t\t\t\tJanus.debug(\"Adding remote candidate:\", candidate);\n\t\t\t\t\t\t\tif(!candidate || candidate.completed === true) {\n\t\t\t\t\t\t\t\t// end-of-candidates\n\t\t\t\t\t\t\t\tconfig.pc.addIceCandidate(Janus.endOfCandidates);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t// New candidate\n\t\t\t\t\t\t\t\tconfig.pc.addIceCandidate(candidate);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconfig.candidates = [];\n\t\t\t\t\t}\n\t\t\t\t\t// Done\n\t\t\t\t\tcallbacks.success();\n\t\t\t\t}, callbacks.error);\n\t\t} else {\n\t\t\tcallbacks.error(\"Invalid JSEP\");\n\t\t}\n\t}\n\n\tfunction createOffer(handleId, media, callbacks) {\n\t\tcallbacks = callbacks || {};\n\t\tcallbacks.success = (typeof callbacks.success == \"function\") ? callbacks.success : Janus.noop;\n\t\tcallbacks.error = (typeof callbacks.error == \"function\") ? callbacks.error : Janus.noop;\n\t\tcallbacks.customizeSdp = (typeof callbacks.customizeSdp == \"function\") ? callbacks.customizeSdp : Janus.noop;\n\t\tvar pluginHandle = pluginHandles[handleId];\n\t\tif(!pluginHandle || !pluginHandle.webrtcStuff) {\n\t\t\tJanus.warn(\"Invalid handle\");\n\t\t\tcallbacks.error(\"Invalid handle\");\n\t\t\treturn;\n\t\t}\n\t\tvar config = pluginHandle.webrtcStuff;\n\t\tvar simulcast = (callbacks.simulcast === true);\n\t\tif(!simulcast) {\n\t\t\tJanus.log(\"Creating offer (iceDone=\" + config.iceDone + \")\");\n\t\t} else {\n\t\t\tJanus.log(\"Creating offer (iceDone=\" + config.iceDone + \", simulcast=\" + simulcast + \")\");\n\t\t}\n\t\t// https://code.google.com/p/webrtc/issues/detail?id=3508\n\t\tvar mediaConstraints = {};\n\t\tif(Janus.unifiedPlan) {\n\t\t\t// We can use Transceivers\n\t\t\tvar audioTransceiver = null, videoTransceiver = null;\n\t\t\tvar transceivers = config.pc.getTransceivers();\n\t\t\tif(transceivers && transceivers.length > 0) {\n\t\t\t\tfor(var t of transceivers) {\n\t\t\t\t\tif((t.sender && t.sender.track && t.sender.track.kind === \"audio\") ||\n\t\t\t\t\t\t\t(t.receiver && t.receiver.track && t.receiver.track.kind === \"audio\")) {\n\t\t\t\t\t\tif(!audioTransceiver) {\n\t\t\t\t\t\t\taudioTransceiver = t;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif((t.sender && t.sender.track && t.sender.track.kind === \"video\") ||\n\t\t\t\t\t\t\t(t.receiver && t.receiver.track && t.receiver.track.kind === \"video\")) {\n\t\t\t\t\t\tif(!videoTransceiver) {\n\t\t\t\t\t\t\tvideoTransceiver = t;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Handle audio (and related changes, if any)\n\t\t\tvar audioSend = isAudioSendEnabled(media);\n\t\t\tvar audioRecv = isAudioRecvEnabled(media);\n\t\t\tif(!audioSend && !audioRecv) {\n\t\t\t\t// Audio disabled: have we removed it?\n\t\t\t\tif(media.removeAudio && audioTransceiver) {\n\t\t\t\t\tif (audioTransceiver.setDirection) {\n\t\t\t\t\t\taudioTransceiver.setDirection(\"inactive\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\taudioTransceiver.direction = \"inactive\";\n\t\t\t\t\t}\n\t\t\t\t\tJanus.log(\"Setting audio transceiver to inactive:\", audioTransceiver);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Take care of audio m-line\n\t\t\t\tif(audioSend && audioRecv) {\n\t\t\t\t\tif(audioTransceiver) {\n\t\t\t\t\t\tif (audioTransceiver.setDirection) {\n\t\t\t\t\t\t\taudioTransceiver.setDirection(\"sendrecv\");\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\taudioTransceiver.direction = \"sendrecv\";\n\t\t\t\t\t\t}\n\t\t\t\t\t\tJanus.log(\"Setting audio transceiver to sendrecv:\", audioTransceiver);\n\t\t\t\t\t}\n\t\t\t\t} else if(audioSend && !audioRecv) {\n\t\t\t\t\tif(audioTransceiver) {\n\t\t\t\t\t\tif (audioTransceiver.setDirection) {\n\t\t\t\t\t\t\taudioTransceiver.setDirection(\"sendonly\");\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\taudioTransceiver.direction = \"sendonly\";\n\t\t\t\t\t\t}\n\t\t\t\t\t\tJanus.log(\"Setting audio transceiver to sendonly:\", audioTransceiver);\n\t\t\t\t\t}\n\t\t\t\t} else if(!audioSend && audioRecv) {\n\t\t\t\t\tif(audioTransceiver) {\n\t\t\t\t\t\tif (audioTransceiver.setDirection) {\n\t\t\t\t\t\t\taudioTransceiver.setDirection(\"recvonly\");\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\taudioTransceiver.direction = \"recvonly\";\n\t\t\t\t\t\t}\n\t\t\t\t\t\tJanus.log(\"Setting audio transceiver to recvonly:\", audioTransceiver);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// In theory, this is the only case where we might not have a transceiver yet\n\t\t\t\t\t\taudioTransceiver = config.pc.addTransceiver(\"audio\", { direction: \"recvonly\" });\n\t\t\t\t\t\tJanus.log(\"Adding recvonly audio transceiver:\", audioTransceiver);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Handle video (and related changes, if any)\n\t\t\tvar videoSend = isVideoSendEnabled(media);\n\t\t\tvar videoRecv = isVideoRecvEnabled(media);\n\t\t\tif(!videoSend && !videoRecv) {\n\t\t\t\t// Video disabled: have we removed it?\n\t\t\t\tif(media.removeVideo && videoTransceiver) {\n\t\t\t\t\tif (videoTransceiver.setDirection) {\n\t\t\t\t\t\tvideoTransceiver.setDirection(\"inactive\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvideoTransceiver.direction = \"inactive\";\n\t\t\t\t\t}\n\t\t\t\t\tJanus.log(\"Setting video transceiver to inactive:\", videoTransceiver);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Take care of video m-line\n\t\t\t\tif(videoSend && videoRecv) {\n\t\t\t\t\tif(videoTransceiver) {\n\t\t\t\t\t\tif (videoTransceiver.setDirection) {\n\t\t\t\t\t\t\tvideoTransceiver.setDirection(\"sendrecv\");\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tvideoTransceiver.direction = \"sendrecv\";\n\t\t\t\t\t\t}\n\t\t\t\t\t\tJanus.log(\"Setting video transceiver to sendrecv:\", videoTransceiver);\n\t\t\t\t\t}\n\t\t\t\t} else if(videoSend && !videoRecv) {\n\t\t\t\t\tif(videoTransceiver) {\n\t\t\t\t\t\tif (videoTransceiver.setDirection) {\n\t\t\t\t\t\t\tvideoTransceiver.setDirection(\"sendonly\");\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tvideoTransceiver.direction = \"sendonly\";\n\t\t\t\t\t\t}\n\t\t\t\t\t\tJanus.log(\"Setting video transceiver to sendonly:\", videoTransceiver);\n\t\t\t\t\t}\n\t\t\t\t} else if(!videoSend && videoRecv) {\n\t\t\t\t\tif(videoTransceiver) {\n\t\t\t\t\t\tif (videoTransceiver.setDirection) {\n\t\t\t\t\t\t\tvideoTransceiver.setDirection(\"recvonly\");\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tvideoTransceiver.direction = \"recvonly\";\n\t\t\t\t\t\t}\n\t\t\t\t\t\tJanus.log(\"Setting video transceiver to recvonly:\", videoTransceiver);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// In theory, this is the only case where we might not have a transceiver yet\n\t\t\t\t\t\tvideoTransceiver = config.pc.addTransceiver(\"video\", { direction: \"recvonly\" });\n\t\t\t\t\t\tJanus.log(\"Adding recvonly video transceiver:\", videoTransceiver);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tmediaConstraints[\"offerToReceiveAudio\"] = isAudioRecvEnabled(media);\n\t\t\tmediaConstraints[\"offerToReceiveVideo\"] = isVideoRecvEnabled(media);\n\t\t}\n\t\tvar iceRestart = (callbacks.iceRestart === true);\n\t\tif(iceRestart) {\n\t\t\tmediaConstraints[\"iceRestart\"] = true;\n\t\t}\n\t\tJanus.debug(mediaConstraints);\n\t\t// Check if this is Firefox and we've been asked to do simulcasting\n\t\tvar sendVideo = isVideoSendEnabled(media);\n\t\tif(sendVideo && simulcast && Janus.webRTCAdapter.browserDetails.browser === \"firefox\") {\n\t\t\t// FIXME Based on https://gist.github.com/voluntas/088bc3cc62094730647b\n\t\t\tJanus.log(\"Enabling Simulcasting for Firefox (RID)\");\n\t\t\tvar sender = config.pc.getSenders().find(function(s) {return s.track && s.track.kind === \"video\"});\n\t\t\tif(sender) {\n\t\t\t\tvar parameters = sender.getParameters();\n\t\t\t\tif(!parameters) {\n\t\t\t\t\tparameters = {};\n\t\t\t\t}\n\t\t\t\tvar maxBitrates = getMaxBitrates(callbacks.simulcastMaxBitrates);\n\t\t\t\tparameters.encodings = callbacks.sendEncodings || [\n\t\t\t\t\t{ rid: \"h\", active: true, maxBitrate: maxBitrates.high },\n\t\t\t\t\t{ rid: \"m\", active: true, maxBitrate: maxBitrates.medium, scaleResolutionDownBy: 2 },\n\t\t\t\t\t{ rid: \"l\", active: true, maxBitrate: maxBitrates.low, scaleResolutionDownBy: 4 }\n\t\t\t\t];\n\t\t\t\tsender.setParameters(parameters);\n\t\t\t}\n\t\t}\n\t\tconfig.pc.createOffer(mediaConstraints)\n\t\t\t.then(function(offer) {\n\t\t\t\tJanus.debug(offer);\n\t\t\t\t// JSON.stringify doesn't work on some WebRTC objects anymore\n\t\t\t\t// See https://code.google.com/p/chromium/issues/detail?id=467366\n\t\t\t\tvar jsep = {\n\t\t\t\t\t\"type\": offer.type,\n\t\t\t\t\t\"sdp\": offer.sdp\n\t\t\t\t};\n\t\t\t\tcallbacks.customizeSdp(jsep);\n\t\t\t\toffer.sdp = jsep.sdp;\n\t\t\t\tJanus.log(\"Setting local description\");\n\t\t\t\tif(sendVideo && simulcast && !Janus.unifiedPlan) {\n\t\t\t\t\t// We only do simulcast via SDP munging on older versions of Chrome and Safari\n\t\t\t\t\tif(Janus.webRTCAdapter.browserDetails.browser === \"chrome\" ||\n\t\t\t\t\t\t\tJanus.webRTCAdapter.browserDetails.browser === \"safari\") {\n\t\t\t\t\t\tJanus.log(\"Enabling Simulcasting for Chrome (SDP munging)\");\n\t\t\t\t\t\toffer.sdp = mungeSdpForSimulcasting(offer.sdp);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconfig.mySdp = {\n\t\t\t\t\ttype: \"offer\",\n\t\t\t\t\tsdp: offer.sdp\n\t\t\t\t};\n\t\t\t\tconfig.pc.setLocalDescription(offer)\n\t\t\t\t\t.catch(callbacks.error);\n\t\t\t\tconfig.mediaConstraints = mediaConstraints;\n\t\t\t\tif(!config.iceDone && !config.trickle) {\n\t\t\t\t\t// Don't do anything until we have all candidates\n\t\t\t\t\tJanus.log(\"Waiting for all candidates...\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// If transforms are present, notify Janus that the media is end-to-end encrypted\n\t\t\t\tif(config.senderTransforms || config.receiverTransforms) {\n\t\t\t\t\toffer[\"e2ee\"] = true;\n\t\t\t\t}\n\t\t\t\tcallbacks.success(offer);\n\t\t\t}, callbacks.error);\n\t}\n\n\tfunction createAnswer(handleId, media, callbacks) {\n\t\tcallbacks = callbacks || {};\n\t\tcallbacks.success = (typeof callbacks.success == \"function\") ? callbacks.success : Janus.noop;\n\t\tcallbacks.error = (typeof callbacks.error == \"function\") ? callbacks.error : Janus.noop;\n\t\tcallbacks.customizeSdp = (typeof callbacks.customizeSdp == \"function\") ? callbacks.customizeSdp : Janus.noop;\n\t\tvar pluginHandle = pluginHandles[handleId];\n\t\tif(!pluginHandle || !pluginHandle.webrtcStuff) {\n\t\t\tJanus.warn(\"Invalid handle\");\n\t\t\tcallbacks.error(\"Invalid handle\");\n\t\t\treturn;\n\t\t}\n\t\tvar config = pluginHandle.webrtcStuff;\n\t\tvar simulcast = (callbacks.simulcast === true || callbacks.simulcast2 === true);\n\t\tif(!simulcast) {\n\t\t\tJanus.log(\"Creating answer (iceDone=\" + config.iceDone + \")\");\n\t\t} else {\n\t\t\tJanus.log(\"Creating answer (iceDone=\" + config.iceDone + \", simulcast=\" + simulcast + \")\");\n\t\t}\n\t\tvar mediaConstraints = null;\n\t\tif(Janus.unifiedPlan) {\n\t\t\t// We can use Transceivers\n\t\t\tmediaConstraints = {};\n\t\t\tvar audioTransceiver = null, videoTransceiver = null;\n\t\t\tvar transceivers = config.pc.getTransceivers();\n\t\t\tif(transceivers && transceivers.length > 0) {\n\t\t\t\tfor(var t of transceivers) {\n\t\t\t\t\tif((t.sender && t.sender.track && t.sender.track.kind === \"audio\") ||\n\t\t\t\t\t\t\t(t.receiver && t.receiver.track && t.receiver.track.kind === \"audio\")) {\n\t\t\t\t\t\tif(!audioTransceiver)\n\t\t\t\t\t\t\taudioTransceiver = t;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif((t.sender && t.sender.track && t.sender.track.kind === \"video\") ||\n\t\t\t\t\t\t\t(t.receiver && t.receiver.track && t.receiver.track.kind === \"video\")) {\n\t\t\t\t\t\tif(!videoTransceiver)\n\t\t\t\t\t\t\tvideoTransceiver = t;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Handle audio (and related changes, if any)\n\t\t\tvar audioSend = isAudioSendEnabled(media);\n\t\t\tvar audioRecv = isAudioRecvEnabled(media);\n\t\t\tif(!audioSend && !audioRecv) {\n\t\t\t\t// Audio disabled: have we removed it?\n\t\t\t\tif(media.removeAudio && audioTransceiver) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (audioTransceiver.setDirection) {\n\t\t\t\t\t\t\taudioTransceiver.setDirection(\"inactive\");\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\taudioTransceiver.direction = \"inactive\";\n\t\t\t\t\t\t}\n\t\t\t\t\t\tJanus.log(\"Setting audio transceiver to inactive:\", audioTransceiver);\n\t\t\t\t\t} catch(e) {\n\t\t\t\t\t\tJanus.error(e);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Take care of audio m-line\n\t\t\t\tif(audioSend && audioRecv) {\n\t\t\t\t\tif(audioTransceiver) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tif (audioTransceiver.setDirection) {\n\t\t\t\t\t\t\t\taudioTransceiver.setDirection(\"sendrecv\");\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\taudioTransceiver.direction = \"sendrecv\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tJanus.log(\"Setting audio transceiver to sendrecv:\", audioTransceiver);\n\t\t\t\t\t\t} catch(e) {\n\t\t\t\t\t\t\tJanus.error(e);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if(audioSend && !audioRecv) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif(audioTransceiver) {\n\t\t\t\t\t\t\tif (audioTransceiver.setDirection) {\n\t\t\t\t\t\t\t\taudioTransceiver.setDirection(\"sendonly\");\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\taudioTransceiver.direction = \"sendonly\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tJanus.log(\"Setting audio transceiver to sendonly:\", audioTransceiver);\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch(e) {\n\t\t\t\t\t\tJanus.error(e);\n\t\t\t\t\t}\n\t\t\t\t} else if(!audioSend && audioRecv) {\n\t\t\t\t\tif(audioTransceiver) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tif (audioTransceiver.setDirection) {\n\t\t\t\t\t\t\t\taudioTransceiver.setDirection(\"recvonly\");\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\taudioTransceiver.direction = \"recvonly\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tJanus.log(\"Setting audio transceiver to recvonly:\", audioTransceiver);\n\t\t\t\t\t\t} catch(e) {\n\t\t\t\t\t\t\tJanus.error(e);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// In theory, this is the only case where we might not have a transceiver yet\n\t\t\t\t\t\taudioTransceiver = config.pc.addTransceiver(\"audio\", { direction: \"recvonly\" });\n\t\t\t\t\t\tJanus.log(\"Adding recvonly audio transceiver:\", audioTransceiver);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Handle video (and related changes, if any)\n\t\t\tvar videoSend = isVideoSendEnabled(media);\n\t\t\tvar videoRecv = isVideoRecvEnabled(media);\n\t\t\tif(!videoSend && !videoRecv) {\n\t\t\t\t// Video disabled: have we removed it?\n\t\t\t\tif(media.removeVideo && videoTransceiver) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (videoTransceiver.setDirection) {\n\t\t\t\t\t\t\tvideoTransceiver.setDirection(\"inactive\");\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tvideoTransceiver.direction = \"inactive\";\n\t\t\t\t\t\t}\n\t\t\t\t\t\tJanus.log(\"Setting video transceiver to inactive:\", videoTransceiver);\n\t\t\t\t\t} catch(e) {\n\t\t\t\t\t\tJanus.error(e);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Take care of video m-line\n\t\t\t\tif(videoSend && videoRecv) {\n\t\t\t\t\tif(videoTransceiver) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tif (videoTransceiver.setDirection) {\n\t\t\t\t\t\t\t\tvideoTransceiver.setDirection(\"sendrecv\");\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tvideoTransceiver.direction = \"sendrecv\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tJanus.log(\"Setting video transceiver to sendrecv:\", videoTransceiver);\n\t\t\t\t\t\t} catch(e) {\n\t\t\t\t\t\t\tJanus.error(e);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if(videoSend && !videoRecv) {\n\t\t\t\t\tif(videoTransceiver) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tif (videoTransceiver.setDirection) {\n\t\t\t\t\t\t\t\tvideoTransceiver.setDirection(\"sendonly\");\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tvideoTransceiver.direction = \"sendonly\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tJanus.log(\"Setting video transceiver to sendonly:\", videoTransceiver);\n\t\t\t\t\t\t} catch(e) {\n\t\t\t\t\t\t\tJanus.error(e);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if(!videoSend && videoRecv) {\n\t\t\t\t\tif(videoTransceiver) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tif (videoTransceiver.setDirection) {\n\t\t\t\t\t\t\t\tvideoTransceiver.setDirection(\"recvonly\");\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tvideoTransceiver.direction = \"recvonly\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tJanus.log(\"Setting video transceiver to recvonly:\", videoTransceiver);\n\t\t\t\t\t\t} catch(e) {\n\t\t\t\t\t\t\tJanus.error(e);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// In theory, this is the only case where we might not have a transceiver yet\n\t\t\t\t\t\tvideoTransceiver = config.pc.addTransceiver(\"video\", { direction: \"recvonly\" });\n\t\t\t\t\t\tJanus.log(\"Adding recvonly video transceiver:\", videoTransceiver);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tif(Janus.webRTCAdapter.browserDetails.browser === \"firefox\" || Janus.webRTCAdapter.browserDetails.browser === \"edge\") {\n\t\t\t\tmediaConstraints = {\n\t\t\t\t\tofferToReceiveAudio: isAudioRecvEnabled(media),\n\t\t\t\t\tofferToReceiveVideo: isVideoRecvEnabled(media)\n\t\t\t\t};\n\t\t\t} else {\n\t\t\t\tmediaConstraints = {\n\t\t\t\t\tmandatory: {\n\t\t\t\t\t\tOfferToReceiveAudio: isAudioRecvEnabled(media),\n\t\t\t\t\t\tOfferToReceiveVideo: isVideoRecvEnabled(media)\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\tJanus.debug(mediaConstraints);\n\t\t// Check if this is Firefox and we've been asked to do simulcasting\n\t\tvar sendVideo = isVideoSendEnabled(media);\n\t\tif(sendVideo && simulcast && Janus.webRTCAdapter.browserDetails.browser === \"firefox\") {\n\t\t\t// FIXME Based on https://gist.github.com/voluntas/088bc3cc62094730647b\n\t\t\tJanus.log(\"Enabling Simulcasting for Firefox (RID)\");\n\t\t\tvar sender = config.pc.getSenders()[1];\n\t\t\tJanus.log(sender);\n\t\t\tvar parameters = sender.getParameters();\n\t\t\tJanus.log(parameters);\n\n\t\t\tvar maxBitrates = getMaxBitrates(callbacks.simulcastMaxBitrates);\n\t\t\tsender.setParameters({encodings: callbacks.sendEncodings || [\n\t\t\t\t{ rid: \"h\", active: true, maxBitrate: maxBitrates.high },\n\t\t\t\t{ rid: \"m\", active: true, maxBitrate: maxBitrates.medium, scaleResolutionDownBy: 2},\n\t\t\t\t{ rid: \"l\", active: true, maxBitrate: maxBitrates.low, scaleResolutionDownBy: 4}\n\t\t\t]});\n\t\t}\n\t\tconfig.pc.createAnswer(mediaConstraints)\n\t\t\t.then(function(answer) {\n\t\t\t\tJanus.debug(answer);\n\t\t\t\t// JSON.stringify doesn't work on some WebRTC objects anymore\n\t\t\t\t// See https://code.google.com/p/chromium/issues/detail?id=467366\n\t\t\t\tvar jsep = {\n\t\t\t\t\t\"type\": answer.type,\n\t\t\t\t\t\"sdp\": answer.sdp\n\t\t\t\t};\n\t\t\t\tcallbacks.customizeSdp(jsep);\n\t\t\t\tanswer.sdp = jsep.sdp;\n\t\t\t\tJanus.log(\"Setting local description\");\n\t\t\t\tif(sendVideo && simulcast && !Janus.unifiedPlan) {\n\t\t\t\t\t// We only do simulcast via SDP munging on older versions of Chrome and Safari\n\t\t\t\t\tif(Janus.webRTCAdapter.browserDetails.browser === \"chrome\") {\n\t\t\t\t\t\t// FIXME Apparently trying to simulcast when answering breaks video in Chrome...\n\t\t\t\t\t\t//~ Janus.log(\"Enabling Simulcasting for Chrome (SDP munging)\");\n\t\t\t\t\t\t//~ answer.sdp = mungeSdpForSimulcasting(answer.sdp);\n\t\t\t\t\t\tJanus.warn(\"simulcast=true, but this is an answer, and video breaks in Chrome if we enable it\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconfig.mySdp = {\n\t\t\t\t\ttype: \"answer\",\n\t\t\t\t\tsdp: answer.sdp\n\t\t\t\t};\n\t\t\t\tconfig.pc.setLocalDescription(answer)\n\t\t\t\t\t.catch(callbacks.error);\n\t\t\t\tconfig.mediaConstraints = mediaConstraints;\n\t\t\t\tif(!config.iceDone && !config.trickle) {\n\t\t\t\t\t// Don't do anything until we have all candidates\n\t\t\t\t\tJanus.log(\"Waiting for all candidates...\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// If transforms are present, notify Janus that the media is end-to-end encrypted\n\t\t\t\tif(config.senderTransforms || config.receiverTransforms) {\n\t\t\t\t\tanswer[\"e2ee\"] = true;\n\t\t\t\t}\n\t\t\t\tcallbacks.success(answer);\n\t\t\t}, callbacks.error);\n\t}\n\n\tfunction sendSDP(handleId, callbacks) {\n\t\tcallbacks = callbacks || {};\n\t\tcallbacks.success = (typeof callbacks.success == \"function\") ? callbacks.success : Janus.noop;\n\t\tcallbacks.error = (typeof callbacks.error == \"function\") ? callbacks.error : Janus.noop;\n\t\tvar pluginHandle = pluginHandles[handleId];\n\t\tif(!pluginHandle || !pluginHandle.webrtcStuff) {\n\t\t\tJanus.warn(\"Invalid handle, not sending anything\");\n\t\t\treturn;\n\t\t}\n\t\tvar config = pluginHandle.webrtcStuff;\n\t\tJanus.log(\"Sending offer/answer SDP...\");\n\t\tif(!config.mySdp) {\n\t\t\tJanus.warn(\"Local SDP instance is invalid, not sending anything...\");\n\t\t\treturn;\n\t\t}\n\t\tconfig.mySdp = {\n\t\t\t\"type\": config.pc.localDescription.type,\n\t\t\t\"sdp\": config.pc.localDescription.sdp\n\t\t};\n\t\tif(config.trickle === false)\n\t\t\tconfig.mySdp[\"trickle\"] = false;\n\t\tJanus.debug(callbacks);\n\t\tconfig.sdpSent = true;\n\t\tcallbacks.success(config.mySdp);\n\t}\n\n\tfunction getVolume(handleId, remote) {\n\t\tvar pluginHandle = pluginHandles[handleId];\n\t\tif(!pluginHandle || !pluginHandle.webrtcStuff) {\n\t\t\tJanus.warn(\"Invalid handle\");\n\t\t\treturn 0;\n\t\t}\n\t\tvar stream = remote ? \"remote\" : \"local\";\n\t\tvar config = pluginHandle.webrtcStuff;\n\t\tif(!config.volume[stream])\n\t\t\tconfig.volume[stream] = { value: 0 };\n\t\t// Start getting the volume, if audioLevel in getStats is supported (apparently\n\t\t// they're only available in Chrome/Safari right now: https://webrtc-stats.callstats.io/)\n\t\tif(config.pc.getStats && (Janus.webRTCAdapter.browserDetails.browser === \"chrome\" ||\n\t\t\t\tJanus.webRTCAdapter.browserDetails.browser === \"safari\")) {\n\t\t\tif(remote && !config.remoteStream) {\n\t\t\t\tJanus.warn(\"Remote stream unavailable\");\n\t\t\t\treturn 0;\n\t\t\t} else if(!remote && !config.myStream) {\n\t\t\t\tJanus.warn(\"Local stream unavailable\");\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tif(!config.volume[stream].timer) {\n\t\t\t\tJanus.log(\"Starting \" + stream + \" volume monitor\");\n\t\t\t\tconfig.volume[stream].timer = setInterval(function() {\n\t\t\t\t\tconfig.pc.getStats()\n\t\t\t\t\t\t.then(function(stats) {\n\t\t\t\t\t\t\tstats.forEach(function (res) {\n\t\t\t\t\t\t\t\tif(!res || res.kind !== \"audio\")\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\tif((remote && !res.remoteSource) || (!remote && res.type !== \"media-source\"))\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\tconfig.volume[stream].value = (res.audioLevel ? res.audioLevel : 0);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t});\n\t\t\t\t}, 200);\n\t\t\t\treturn 0;\t// We don't have a volume to return yet\n\t\t\t}\n\t\t\treturn config.volume[stream].value;\n\t\t} else {\n\t\t\t// audioInputLevel and audioOutputLevel seem only available in Chrome? audioLevel\n\t\t\t// seems to be available on Chrome and Firefox, but they don't seem to work\n\t\t\tJanus.warn(\"Getting the \" + stream + \" volume unsupported by browser\");\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tfunction isMuted(handleId, video) {\n\t\tvar pluginHandle = pluginHandles[handleId];\n\t\tif(!pluginHandle || !pluginHandle.webrtcStuff) {\n\t\t\tJanus.warn(\"Invalid handle\");\n\t\t\treturn true;\n\t\t}\n\t\tvar config = pluginHandle.webrtcStuff;\n\t\tif(!config.pc) {\n\t\t\tJanus.warn(\"Invalid PeerConnection\");\n\t\t\treturn true;\n\t\t}\n\t\tif(!config.myStream) {\n\t\t\tJanus.warn(\"Invalid local MediaStream\");\n\t\t\treturn true;\n\t\t}\n\t\tif(video) {\n\t\t\t// Check video track\n\t\t\tif(!config.myStream.getVideoTracks() || config.myStream.getVideoTracks().length === 0) {\n\t\t\t\tJanus.warn(\"No video track\");\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn !config.myStream.getVideoTracks()[0].enabled;\n\t\t} else {\n\t\t\t// Check audio track\n\t\t\tif(!config.myStream.getAudioTracks() || config.myStream.getAudioTracks().length === 0) {\n\t\t\t\tJanus.warn(\"No audio track\");\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn !config.myStream.getAudioTracks()[0].enabled;\n\t\t}\n\t}\n\n\tfunction mute(handleId, video, mute) {\n\t\tvar pluginHandle = pluginHandles[handleId];\n\t\tif(!pluginHandle || !pluginHandle.webrtcStuff) {\n\t\t\tJanus.warn(\"Invalid handle\");\n\t\t\treturn false;\n\t\t}\n\t\tvar config = pluginHandle.webrtcStuff;\n\t\tif(!config.pc) {\n\t\t\tJanus.warn(\"Invalid PeerConnection\");\n\t\t\treturn false;\n\t\t}\n\t\tif(!config.myStream) {\n\t\t\tJanus.warn(\"Invalid local MediaStream\");\n\t\t\treturn false;\n\t\t}\n\t\tif(video) {\n\t\t\t// Mute/unmute video track\n\t\t\tif(!config.myStream.getVideoTracks() || config.myStream.getVideoTracks().length === 0) {\n\t\t\t\tJanus.warn(\"No video track\");\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tconfig.myStream.getVideoTracks()[0].enabled = !mute;\n\t\t\treturn true;\n\t\t} else {\n\t\t\t// Mute/unmute audio track\n\t\t\tif(!config.myStream.getAudioTracks() || config.myStream.getAudioTracks().length === 0) {\n\t\t\t\tJanus.warn(\"No audio track\");\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tconfig.myStream.getAudioTracks()[0].enabled = !mute;\n\t\t\treturn true;\n\t\t}\n\t}\n\n\tfunction getBitrate(handleId) {\n\t\tvar pluginHandle = pluginHandles[handleId];\n\t\tif(!pluginHandle || !pluginHandle.webrtcStuff) {\n\t\t\tJanus.warn(\"Invalid handle\");\n\t\t\treturn \"Invalid handle\";\n\t\t}\n\t\tvar config = pluginHandle.webrtcStuff;\n\t\tif(!config.pc)\n\t\t\treturn \"Invalid PeerConnection\";\n\t\t// Start getting the bitrate, if getStats is supported\n\t\tif(config.pc.getStats) {\n\t\t\tif(!config.bitrate.timer) {\n\t\t\t\tJanus.log(\"Starting bitrate timer (via getStats)\");\n\t\t\t\tconfig.bitrate.timer = setInterval(function() {\n\t\t\t\t\tconfig.pc.getStats()\n\t\t\t\t\t\t.then(function(stats) {\n\t\t\t\t\t\t\tstats.forEach(function (res) {\n\t\t\t\t\t\t\t\tif(!res)\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\tvar inStats = false;\n\t\t\t\t\t\t\t\t// Check if these are statistics on incoming media\n\t\t\t\t\t\t\t\tif((res.mediaType === \"video\" || res.id.toLowerCase().indexOf(\"video\") > -1) &&\n\t\t\t\t\t\t\t\t\t\tres.type === \"inbound-rtp\" && res.id.indexOf(\"rtcp\") < 0) {\n\t\t\t\t\t\t\t\t\t// New stats\n\t\t\t\t\t\t\t\t\tinStats = true;\n\t\t\t\t\t\t\t\t} else if(res.type == 'ssrc' && res.bytesReceived &&\n\t\t\t\t\t\t\t\t\t\t(res.googCodecName === \"VP8\" || res.googCodecName === \"\")) {\n\t\t\t\t\t\t\t\t\t// Older Chromer versions\n\t\t\t\t\t\t\t\t\tinStats = true;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t// Parse stats now\n\t\t\t\t\t\t\t\tif(inStats) {\n\t\t\t\t\t\t\t\t\tconfig.bitrate.bsnow = res.bytesReceived;\n\t\t\t\t\t\t\t\t\tconfig.bitrate.tsnow = res.timestamp;\n\t\t\t\t\t\t\t\t\tif(config.bitrate.bsbefore === null || config.bitrate.tsbefore === null) {\n\t\t\t\t\t\t\t\t\t\t// Skip this round\n\t\t\t\t\t\t\t\t\t\tconfig.bitrate.bsbefore = config.bitrate.bsnow;\n\t\t\t\t\t\t\t\t\t\tconfig.bitrate.tsbefore = config.bitrate.tsnow;\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\t// Calculate bitrate\n\t\t\t\t\t\t\t\t\t\tvar timePassed = config.bitrate.tsnow - config.bitrate.tsbefore;\n\t\t\t\t\t\t\t\t\t\tif(Janus.webRTCAdapter.browserDetails.browser === \"safari\")\n\t\t\t\t\t\t\t\t\t\t\ttimePassed = timePassed/1000;\t// Apparently the timestamp is in microseconds, in Safari\n\t\t\t\t\t\t\t\t\t\tvar bitRate = Math.round((config.bitrate.bsnow - config.bitrate.bsbefore) * 8 / timePassed);\n\t\t\t\t\t\t\t\t\t\tif(Janus.webRTCAdapter.browserDetails.browser === \"safari\")\n\t\t\t\t\t\t\t\t\t\t\tbitRate = parseInt(bitRate/1000);\n\t\t\t\t\t\t\t\t\t\tconfig.bitrate.value = bitRate + ' kbits/sec';\n\t\t\t\t\t\t\t\t\t\t//~ Janus.log(\"Estimated bitrate is \" + config.bitrate.value);\n\t\t\t\t\t\t\t\t\t\tconfig.bitrate.bsbefore = config.bitrate.bsnow;\n\t\t\t\t\t\t\t\t\t\tconfig.bitrate.tsbefore = config.bitrate.tsnow;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t});\n\t\t\t\t}, 1000);\n\t\t\t\treturn \"0 kbits/sec\";\t// We don't have a bitrate value yet\n\t\t\t}\n\t\t\treturn config.bitrate.value;\n\t\t} else {\n\t\t\tJanus.warn(\"Getting the video bitrate unsupported by browser\");\n\t\t\treturn \"Feature unsupported by browser\";\n\t\t}\n\t}\n\n\tfunction webrtcError(error) {\n\t\tJanus.error(\"WebRTC error:\", error);\n\t}\n\n\tfunction cleanupWebrtc(handleId, hangupRequest) {\n\t\tJanus.log(\"Cleaning WebRTC stuff\");\n\t\tvar pluginHandle = pluginHandles[handleId];\n\t\tif(!pluginHandle) {\n\t\t\t// Nothing to clean\n\t\t\treturn;\n\t\t}\n\t\tvar config = pluginHandle.webrtcStuff;\n\t\tif(config) {\n\t\t\tif(hangupRequest === true) {\n\t\t\t\t// Send a hangup request (we don't really care about the response)\n\t\t\t\tvar request = { \"janus\": \"hangup\", \"transaction\": Janus.randomString(12) };\n\t\t\t\tif(pluginHandle.token)\n\t\t\t\t\trequest[\"token\"] = pluginHandle.token;\n\t\t\t\tif(apisecret)\n\t\t\t\t\trequest[\"apisecret\"] = apisecret;\n\t\t\t\tJanus.debug(\"Sending hangup request (handle=\" + handleId + \"):\");\n\t\t\t\tJanus.debug(request);\n\t\t\t\tif(websockets) {\n\t\t\t\t\trequest[\"session_id\"] = sessionId;\n\t\t\t\t\trequest[\"handle_id\"] = handleId;\n\t\t\t\t\tws.send(JSON.stringify(request));\n\t\t\t\t} else {\n\t\t\t\t\tJanus.httpAPICall(server + \"/\" + sessionId + \"/\" + handleId, {\n\t\t\t\t\t\tverb: 'POST',\n\t\t\t\t\t\twithCredentials: withCredentials,\n\t\t\t\t\t\tbody: request\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Cleanup stack\n\t\t\tconfig.remoteStream = null;\n\t\t\tif(config.volume) {\n\t\t\t\tif(config.volume[\"local\"] && config.volume[\"local\"].timer)\n\t\t\t\t\tclearInterval(config.volume[\"local\"].timer);\n\t\t\t\tif(config.volume[\"remote\"] && config.volume[\"remote\"].timer)\n\t\t\t\t\tclearInterval(config.volume[\"remote\"].timer);\n\t\t\t}\n\t\t\tconfig.volume = {};\n\t\t\tif(config.bitrate.timer)\n\t\t\t\tclearInterval(config.bitrate.timer);\n\t\t\tconfig.bitrate.timer = null;\n\t\t\tconfig.bitrate.bsnow = null;\n\t\t\tconfig.bitrate.bsbefore = null;\n\t\t\tconfig.bitrate.tsnow = null;\n\t\t\tconfig.bitrate.tsbefore = null;\n\t\t\tconfig.bitrate.value = null;\n\t\t\tif(!config.streamExternal && config.myStream) {\n\t\t\t\tJanus.log(\"Stopping local stream tracks\");\n\t\t\t\tJanus.stopAllTracks(config.myStream);\n\t\t\t}\n\t\t\tconfig.streamExternal = false;\n\t\t\tconfig.myStream = null;\n\t\t\t// Close PeerConnection\n\t\t\ttry {\n\t\t\t\tconfig.pc.close();\n\t\t\t} catch(e) {\n\t\t\t\t// Do nothing\n\t\t\t}\n\t\t\tconfig.pc = null;\n\t\t\tconfig.candidates = null;\n\t\t\tconfig.mySdp = null;\n\t\t\tconfig.remoteSdp = null;\n\t\t\tconfig.iceDone = false;\n\t\t\tconfig.dataChannel = {};\n\t\t\tconfig.dtmfSender = null;\n\t\t\tconfig.senderTransforms = null;\n\t\t\tconfig.receiverTransforms = null;\n\t\t}\n\t\tpluginHandle.oncleanup();\n\t}\n\n\t// Helper method to munge an SDP to enable simulcasting (Chrome only)\n\tfunction mungeSdpForSimulcasting(sdp) {\n\t\t// Let's munge the SDP to add the attributes for enabling simulcasting\n\t\t// (based on https://gist.github.com/ggarber/a19b4c33510028b9c657)\n\t\tvar lines = sdp.split(\"\\r\\n\");\n\t\tvar video = false;\n\t\tvar ssrc = [ -1 ], ssrc_fid = [ -1 ];\n\t\tvar cname = null, msid = null, mslabel = null, label = null;\n\t\tvar insertAt = -1;\n\t\tfor(let i=0; i<lines.length; i++) {\n\t\t\tconst mline = lines[i].match(/m=(\\w+) */);\n\t\t\tif(mline) {\n\t\t\t\tconst medium = mline[1];\n\t\t\t\tif(medium === \"video\") {\n\t\t\t\t\t// New video m-line: make sure it's the first one\n\t\t\t\t\tif(ssrc[0] < 0) {\n\t\t\t\t\t\tvideo = true;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// We're done, let's add the new attributes here\n\t\t\t\t\t\tinsertAt = i;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// New non-video m-line: do we have what we were looking for?\n\t\t\t\t\tif(ssrc[0] > -1) {\n\t\t\t\t\t\t// We're done, let's add the new attributes here\n\t\t\t\t\t\tinsertAt = i;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif(!video)\n\t\t\t\tcontinue;\n\t\t\tvar sim = lines[i].match(/a=ssrc-group:SIM (\\d+) (\\d+) (\\d+)/);\n\t\t\tif(sim) {\n\t\t\t\tJanus.warn(\"The SDP already contains a SIM attribute, munging will be skipped\");\n\t\t\t\treturn sdp;\n\t\t\t}\n\t\t\tvar fid = lines[i].match(/a=ssrc-group:FID (\\d+) (\\d+)/);\n\t\t\tif(fid) {\n\t\t\t\tssrc[0] = fid[1];\n\t\t\t\tssrc_fid[0] = fid[2];\n\t\t\t\tlines.splice(i, 1); i--;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif(ssrc[0]) {\n\t\t\t\tvar match = lines[i].match('a=ssrc:' + ssrc[0] + ' cname:(.+)')\n\t\t\t\tif(match) {\n\t\t\t\t\tcname = match[1];\n\t\t\t\t}\n\t\t\t\tmatch = lines[i].match('a=ssrc:' + ssrc[0] + ' msid:(.+)')\n\t\t\t\tif(match) {\n\t\t\t\t\tmsid = match[1];\n\t\t\t\t}\n\t\t\t\tmatch = lines[i].match('a=ssrc:' + ssrc[0] + ' mslabel:(.+)')\n\t\t\t\tif(match) {\n\t\t\t\t\tmslabel = match[1];\n\t\t\t\t}\n\t\t\t\tmatch = lines[i].match('a=ssrc:' + ssrc[0] + ' label:(.+)')\n\t\t\t\tif(match) {\n\t\t\t\t\tlabel = match[1];\n\t\t\t\t}\n\t\t\t\tif(lines[i].indexOf('a=ssrc:' + ssrc_fid[0]) === 0) {\n\t\t\t\t\tlines.splice(i, 1); i--;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif(lines[i].indexOf('a=ssrc:' + ssrc[0]) === 0) {\n\t\t\t\t\tlines.splice(i, 1); i--;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(lines[i].length == 0) {\n\t\t\t\tlines.splice(i, 1); i--;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\tif(ssrc[0] < 0) {\n\t\t\t// Couldn't find a FID attribute, let's just take the first video SSRC we find\n\t\t\tinsertAt = -1;\n\t\t\tvideo = false;\n\t\t\tfor(let i=0; i<lines.length; i++) {\n\t\t\t\tconst mline = lines[i].match(/m=(\\w+) */);\n\t\t\t\tif(mline) {\n\t\t\t\t\tconst medium = mline[1];\n\t\t\t\t\tif(medium === \"video\") {\n\t\t\t\t\t\t// New video m-line: make sure it's the first one\n\t\t\t\t\t\tif(ssrc[0] < 0) {\n\t\t\t\t\t\t\tvideo = true;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// We're done, let's add the new attributes here\n\t\t\t\t\t\t\tinsertAt = i;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// New non-video m-line: do we have what we were looking for?\n\t\t\t\t\t\tif(ssrc[0] > -1) {\n\t\t\t\t\t\t\t// We're done, let's add the new attributes here\n\t\t\t\t\t\t\tinsertAt = i;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif(!video)\n\t\t\t\t\tcontinue;\n\t\t\t\tif(ssrc[0] < 0) {\n\t\t\t\t\tvar value = lines[i].match(/a=ssrc:(\\d+)/);\n\t\t\t\t\tif(value) {\n\t\t\t\t\t\tssrc[0] = value[1];\n\t\t\t\t\t\tlines.splice(i, 1); i--;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tlet match = lines[i].match('a=ssrc:' + ssrc[0] + ' cname:(.+)')\n\t\t\t\t\tif(match) {\n\t\t\t\t\t\tcname = match[1];\n\t\t\t\t\t}\n\t\t\t\t\tmatch = lines[i].match('a=ssrc:' + ssrc[0] + ' msid:(.+)')\n\t\t\t\t\tif(match) {\n\t\t\t\t\t\tmsid = match[1];\n\t\t\t\t\t}\n\t\t\t\t\tmatch = lines[i].match('a=ssrc:' + ssrc[0] + ' mslabel:(.+)')\n\t\t\t\t\tif(match) {\n\t\t\t\t\t\tmslabel = match[1];\n\t\t\t\t\t}\n\t\t\t\t\tmatch = lines[i].match('a=ssrc:' + ssrc[0] + ' label:(.+)')\n\t\t\t\t\tif(match) {\n\t\t\t\t\t\tlabel = match[1];\n\t\t\t\t\t}\n\t\t\t\t\tif(lines[i].indexOf('a=ssrc:' + ssrc_fid[0]) === 0) {\n\t\t\t\t\t\tlines.splice(i, 1); i--;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif(lines[i].indexOf('a=ssrc:' + ssrc[0]) === 0) {\n\t\t\t\t\t\tlines.splice(i, 1); i--;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(lines[i].length === 0) {\n\t\t\t\t\tlines.splice(i, 1); i--;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif(ssrc[0] < 0) {\n\t\t\t// Still nothing, let's just return the SDP we were asked to munge\n\t\t\tJanus.warn(\"Couldn't find the video SSRC, simulcasting NOT enabled\");\n\t\t\treturn sdp;\n\t\t}\n\t\tif(insertAt < 0) {\n\t\t\t// Append at the end\n\t\t\tinsertAt = lines.length;\n\t\t}\n\t\t// Generate a couple of SSRCs (for retransmissions too)\n\t\t// Note: should we check if there are conflicts, here?\n\t\tssrc[1] = Math.floor(Math.random()*0xFFFFFFFF);\n\t\tssrc[2] = Math.floor(Math.random()*0xFFFFFFFF);\n\t\tssrc_fid[1] = Math.floor(Math.random()*0xFFFFFFFF);\n\t\tssrc_fid[2] = Math.floor(Math.random()*0xFFFFFFFF);\n\t\t// Add attributes to the SDP\n\t\tfor(var i=0; i<ssrc.length; i++) {\n\t\t\tif(cname) {\n\t\t\t\tlines.splice(insertAt, 0, 'a=ssrc:' + ssrc[i] + ' cname:' + cname);\n\t\t\t\tinsertAt++;\n\t\t\t}\n\t\t\tif(msid) {\n\t\t\t\tlines.splice(insertAt, 0, 'a=ssrc:' + ssrc[i] + ' msid:' + msid);\n\t\t\t\tinsertAt++;\n\t\t\t}\n\t\t\tif(mslabel) {\n\t\t\t\tlines.splice(insertAt, 0, 'a=ssrc:' + ssrc[i] + ' mslabel:' + mslabel);\n\t\t\t\tinsertAt++;\n\t\t\t}\n\t\t\tif(label) {\n\t\t\t\tlines.splice(insertAt, 0, 'a=ssrc:' + ssrc[i] + ' label:' + label);\n\t\t\t\tinsertAt++;\n\t\t\t}\n\t\t\t// Add the same info for the retransmission SSRC\n\t\t\tif(cname) {\n\t\t\t\tlines.splice(insertAt, 0, 'a=ssrc:' + ssrc_fid[i] + ' cname:' + cname);\n\t\t\t\tinsertAt++;\n\t\t\t}\n\t\t\tif(msid) {\n\t\t\t\tlines.splice(insertAt, 0, 'a=ssrc:' + ssrc_fid[i] + ' msid:' + msid);\n\t\t\t\tinsertAt++;\n\t\t\t}\n\t\t\tif(mslabel) {\n\t\t\t\tlines.splice(insertAt, 0, 'a=ssrc:' + ssrc_fid[i] + ' mslabel:' + mslabel);\n\t\t\t\tinsertAt++;\n\t\t\t}\n\t\t\tif(label) {\n\t\t\t\tlines.splice(insertAt, 0, 'a=ssrc:' + ssrc_fid[i] + ' label:' + label);\n\t\t\t\tinsertAt++;\n\t\t\t}\n\t\t}\n\t\tlines.splice(insertAt, 0, 'a=ssrc-group:FID ' + ssrc[2] + ' ' + ssrc_fid[2]);\n\t\tlines.splice(insertAt, 0, 'a=ssrc-group:FID ' + ssrc[1] + ' ' + ssrc_fid[1]);\n\t\tlines.splice(insertAt, 0, 'a=ssrc-group:FID ' + ssrc[0] + ' ' + ssrc_fid[0]);\n\t\tlines.splice(insertAt, 0, 'a=ssrc-group:SIM ' + ssrc[0] + ' ' + ssrc[1] + ' ' + ssrc[2]);\n\t\tsdp = lines.join(\"\\r\\n\");\n\t\tif(!sdp.endsWith(\"\\r\\n\"))\n\t\t\tsdp += \"\\r\\n\";\n\t\treturn sdp;\n\t}\n\n\t// Helper methods to parse a media object\n\tfunction isAudioSendEnabled(media) {\n\t\tJanus.debug(\"isAudioSendEnabled:\", media);\n\t\tif(!media)\n\t\t\treturn true;\t// Default\n\t\tif(media.audio === false)\n\t\t\treturn false;\t// Generic audio has precedence\n\t\tif(media.audioSend === undefined || media.audioSend === null)\n\t\t\treturn true;\t// Default\n\t\treturn (media.audioSend === true);\n\t}\n\n\tfunction isAudioSendRequired(media) {\n\t\tJanus.debug(\"isAudioSendRequired:\", media);\n\t\tif(!media)\n\t\t\treturn false;\t// Default\n\t\tif(media.audio === false || media.audioSend === false)\n\t\t\treturn false;\t// If we're not asking to capture audio, it's not required\n\t\tif(media.failIfNoAudio === undefined || media.failIfNoAudio === null)\n\t\t\treturn false;\t// Default\n\t\treturn (media.failIfNoAudio === true);\n\t}\n\n\tfunction isAudioRecvEnabled(media) {\n\t\tJanus.debug(\"isAudioRecvEnabled:\", media);\n\t\tif(!media)\n\t\t\treturn true;\t// Default\n\t\tif(media.audio === false)\n\t\t\treturn false;\t// Generic audio has precedence\n\t\tif(media.audioRecv === undefined || media.audioRecv === null)\n\t\t\treturn true;\t// Default\n\t\treturn (media.audioRecv === true);\n\t}\n\n\tfunction isVideoSendEnabled(media) {\n\t\tJanus.debug(\"isVideoSendEnabled:\", media);\n\t\tif(!media)\n\t\t\treturn true;\t// Default\n\t\tif(media.video === false)\n\t\t\treturn false;\t// Generic video has precedence\n\t\tif(media.videoSend === undefined || media.videoSend === null)\n\t\t\treturn true;\t// Default\n\t\treturn (media.videoSend === true);\n\t}\n\n\tfunction isVideoSendRequired(media) {\n\t\tJanus.debug(\"isVideoSendRequired:\", media);\n\t\tif(!media)\n\t\t\treturn false;\t// Default\n\t\tif(media.video === false || media.videoSend === false)\n\t\t\treturn false;\t// If we're not asking to capture video, it's not required\n\t\tif(media.failIfNoVideo === undefined || media.failIfNoVideo === null)\n\t\t\treturn false;\t// Default\n\t\treturn (media.failIfNoVideo === true);\n\t}\n\n\tfunction isVideoRecvEnabled(media) {\n\t\tJanus.debug(\"isVideoRecvEnabled:\", media);\n\t\tif(!media)\n\t\t\treturn true;\t// Default\n\t\tif(media.video === false)\n\t\t\treturn false;\t// Generic video has precedence\n\t\tif(media.videoRecv === undefined || media.videoRecv === null)\n\t\t\treturn true;\t// Default\n\t\treturn (media.videoRecv === true);\n\t}\n\n\tfunction isScreenSendEnabled(media) {\n\t\tJanus.debug(\"isScreenSendEnabled:\", media);\n\t\tif (!media)\n\t\t\treturn false;\n\t\tif (typeof media.video !== 'object' || typeof media.video.mandatory !== 'object')\n\t\t\treturn false;\n\t\tvar constraints = media.video.mandatory;\n\t\tif (constraints.chromeMediaSource)\n\t\t\treturn constraints.chromeMediaSource === 'desktop' || constraints.chromeMediaSource === 'screen';\n\t\telse if (constraints.mozMediaSource)\n\t\t\treturn constraints.mozMediaSource === 'window' || constraints.mozMediaSource === 'screen';\n\t\telse if (constraints.mediaSource)\n\t\t\treturn constraints.mediaSource === 'window' || constraints.mediaSource === 'screen';\n\t\treturn false;\n\t}\n\n\tfunction isDataEnabled(media) {\n\t\tJanus.debug(\"isDataEnabled:\", media);\n\t\tif(Janus.webRTCAdapter.browserDetails.browser === \"edge\") {\n\t\t\tJanus.warn(\"Edge doesn't support data channels yet\");\n\t\t\treturn false;\n\t\t}\n\t\tif(media === undefined || media === null)\n\t\t\treturn false;\t// Default\n\t\treturn (media.data === true);\n\t}\n\n\tfunction isTrickleEnabled(trickle) {\n\t\tJanus.debug(\"isTrickleEnabled:\", trickle);\n\t\treturn (trickle === false) ? false : true;\n\t}\n}\n\nexport default Janus"],"names":["Janus","sessions","isExtensionEnabled","navigator","mediaDevices","getDisplayMedia","window","userAgent","match","chromever","parseInt","maxver","extension","isInstalled","defaultExtension","extensionId","document","querySelector","getScreen","callback","pending","setTimeout","error","Error","name","this","cache","postMessage","type","id","init","addEventListener","event","origin","location","data","sourceId","console","log","clearTimeout","gatewayCallbacks","success","noop","destroyed","initDone","isWebrtcSupported","server","websockets","ws","wsHandlers","wsKeepaliveTimeoutId","servers","serversIndex","isArray","length","debug","indexOf","iceServers","urls","iceTransportPolicy","bundlePolicy","ipv6Support","ipv6","withCredentials","undefined","maxev","max_poll_events","token","apisecret","destroyOnUnload","keepAlivePeriod","isNaN","longPollTimeout","getMaxBitrates","simulcastMaxBitrates","maxBitrates","high","medium","low","connected","sessionId","pluginHandles","that","retries","transactions","eventHandler","longpoll","Date","getTime","encodeURIComponent","httpAPICall","verb","handleEvent","timeout","textStatus","errorThrown","warn","json","skipTimeout","sender","pluginHandle","candidate","config","webrtcStuff","pc","remoteSdp","completed","addIceCandidate","endOfCandidates","candidates","push","webrtcState","hangup","ondetached","detach","mediaState","slowLink","code","reason","transaction","reportSuccess","plugindata","jsep","onmessage","close","vdebug","i","keepAlive","request","janus","session_id","randomString","send","JSON","stringify","createSession","callbacks","onopen","onerror","onclose","eventName","newWebSocket","open","message","parse","body","sendMessage","handleId","sdp","e2ee","rid_order","force_relay","sendTrickleCandidate","createDataChannel","dclabel","dcprotocol","incoming","pendingData","onDataChannelStateChange","label","target","protocol","dcState","dataChannel","readyState","_step4","_iterator4","_createForOfIteratorHelper","s","n","done","value","err","e","f","ondataopen","dcoptions","dataChannelOptions","ondata","sendData","text","dataChanDefaultLabel","sendDtmf","dtmfSender","audioSender","getSenders","find","track","kind","dtmf","ontonechange","tone","tones","duration","gap","insertDTMF","destroyHandle","noRequest","cleanupWebrtc","detached","streamsDone","media","stream","stopAllTracks","getAudioTracks","getVideoTracks","addTracks","myStream","update","streamExternal","replaceAudio","replaceVideo","isAudioSendEnabled","addAudio","addTrack","unifiedPlan","audioTransceiver","transceivers","getTransceivers","_step5","_iterator5","createForOfIteratorHelper","t","receiver","replaceTrack","isVideoSendEnabled","addVideo","videoTransceiver","_step6","_iterator6","pc_config","webRTCAdapter","browserDetails","browser","version","pc_constraints","optional","DtlsSrtpKeyAgreement","googIPv6","rtcConstraints","_typeof","RTCRtpSender","prototype","createEncodedStreams","createEncodedAudioStreams","createEncodedVideoStreams","senderTransforms","receiverTransforms","RTCPeerConnection","getStats","volume","bitrate","trickle","oniceconnectionstatechange","iceState","iceConnectionState","onicecandidate","iceDone","mySdp","localDescription","sdpSent","sendSDP","sdpMid","sdpMLineIndex","ontrack","streams","remoteStream","onremotestream","onended","receiverStreams","createAudioEncodedStreams","readableStream","writableStream","pipeThrough","pipeTo","readable","writable","trackMutedTimeoutId","ev","removeTrack","onmute","onunmute","simulcast","simulcast2","svc","getTracks","forEach","tr","addTransceiver","direction","sendEncodings","rid","active","maxBitrate","scaleResolutionDownBy","scalabilityMode","senderStreams","isDataEnabled","ondatachannel","channel","onlocalstream","setRemoteDescription","then","customizeSdp","mediaConstraints","_step10","_iterator10","audioSend","audioRecv","isAudioRecvEnabled","setDirection","removeAudio","videoSend","videoRecv","isVideoRecvEnabled","removeVideo","offerToReceiveAudio","offerToReceiveVideo","mandatory","OfferToReceiveAudio","OfferToReceiveVideo","sendVideo","parameters","getParameters","setParameters","encodings","createAnswer","answer","setLocalDescription","catch","_step9","_iterator9","iceRestart","createOffer","offer","lines","split","video","ssrc","ssrc_fid","cname","msid","mslabel","insertAt","mline","fid","splice","Math","floor","random","join","endsWith","mungeSdpForSimulcasting","prepareWebrtc","webrtcError","audio","keepAudio","keepVideo","addData","consentDialog","at","stop","ra","_step7","_iterator7","asnd","vt","rv","_step8","_iterator8","vsnd","isGetUserMediaAvailable","constraints","audioSupport","videoSupport","width","height","ideal","screenshareFrameRate","frameRate","screenshareHeight","screenshareWidth","captureDesktopAudio","getUserMedia","audioStream","callbackUserMedia","getScreenMedia","gsmCallback","useAudio","googLeakyBucket","maxWidth","screen","maxHeight","minFrameRate","maxFrameRate","chromeMediaSource","googTemporalLayeredScreencast","chromeMediaSourceId","mozMediaSource","mediaSource","lastTime","currentTime","polly","setInterval","clearInterval","enumerateDevices","devices","audioExist","some","device","videoExist","isScreenSendEnabled","needAudioDevice","failIfNoAudio","isAudioSendRequired","needVideoDevice","failIfNoVideo","isVideoSendRequired","haveAudioDevice","haveVideoDevice","gumConstraints","prepareWebrtcPeer","getVolume","remote","timer","stats","res","remoteSource","audioLevel","isMuted","enabled","mute","getBitrate","inStats","mediaType","toLowerCase","bytesReceived","googCodecName","bsnow","tsnow","timestamp","bsbefore","tsbefore","timePassed","bitRate","round","hangupRequest","oncleanup","getServer","isConnected","reconnect","getSessionId","getInfo","destroy","unload","notifyDestroyed","cleanupHandles","sendBeacon","unbindWebSocket","removeEventListener","onUnbindMessage","onUnbindError","destroySession","attach","ordered","plugin","opaqueId","loopIndex","handleToken","opaque_id","loop_index","session","started","getId","getPlugin","getRemoteVolume","getLocalVolume","isAudioMuted","muteAudio","unmuteAudio","isVideoMuted","muteVideo","unmuteVideo","handleRemoteJsep","sendRequest","createHandle","useDefaultDependencies","deps","fetch","p","Promise","socketCls","WebSocket","proto","arr","Array","adapter","url","options","fetchOptions","method","headers","Accept","credentials","fetching","reject","resolve","timerId","race","response","ok","parsed","useOldDependencies","jq","jQuery","payload","contentType","xhrFields","ajax","extend","dataType","async","result","xhr","status","_step","tracks","_iterator","mst","trace","bind","_step2","_iterator2","d","usedDependencies","dependencies","listDevices","attachMediaStream","element","srcObject","src","URL","createObjectURL","reattachMediaStream","to","from","platform","oldOBF","safariVp8","getCapabilities","codecs","_step3","_iterator3","codec","mimeType","testpc","RTCRtpTransceiver","tempPc","len","charSet","randomPoz","substring"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- "use strict";function t(e){if(e)return function(e){for(var r in t.prototype)e[r]=t.prototype[r];return e}(e)}Object.defineProperty(exports,"__esModule",{value:!0}),t.prototype.on=t.prototype.addEventListener=function(t,e){return this._callbacks=this._callbacks||{},(this._callbacks["$"+t]=this._callbacks["$"+t]||[]).push(e),this},t.prototype.once=function(t,e){function r(){this.off(t,r),e.apply(this,arguments)}return r.fn=e,this.on(t,r),this},t.prototype.off=t.prototype.removeListener=t.prototype.removeAllListeners=t.prototype.removeEventListener=function(t,e){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var r,s=this._callbacks["$"+t];if(!s)return this;if(1==arguments.length)return delete this._callbacks["$"+t],this;for(var i=0;i<s.length;i++)if((r=s[i])===e||r.fn===e){s.splice(i,1);break}return 0===s.length&&delete this._callbacks["$"+t],this},t.prototype.emit=function(t){this._callbacks=this._callbacks||{};for(var e=new Array(arguments.length-1),r=this._callbacks["$"+t],s=1;s<arguments.length;s++)e[s-1]=arguments[s];if(r){s=0;for(var i=(r=r.slice(0)).length;s<i;++s)r[s].apply(this,e)}return this},t.prototype.emitReserved=t.prototype.emit,t.prototype.listeners=function(t){return this._callbacks=this._callbacks||{},this._callbacks["$"+t]||[]},t.prototype.hasListeners=function(t){return!!this.listeners(t).length},exports.Emitter=t;
2
- //# sourceMappingURL=index.mjs.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.mjs.js","sources":["../../../../node_modules/@socket.io/component-emitter/index.mjs"],"sourcesContent":["/**\n * Initialize a new `Emitter`.\n *\n * @api public\n */\n\nexport function Emitter(obj) {\n if (obj) return mixin(obj);\n}\n\n/**\n * Mixin the emitter properties.\n *\n * @param {Object} obj\n * @return {Object}\n * @api private\n */\n\nfunction mixin(obj) {\n for (var key in Emitter.prototype) {\n obj[key] = Emitter.prototype[key];\n }\n return obj;\n}\n\n/**\n * Listen on the given `event` with `fn`.\n *\n * @param {String} event\n * @param {Function} fn\n * @return {Emitter}\n * @api public\n */\n\nEmitter.prototype.on =\nEmitter.prototype.addEventListener = function(event, fn){\n this._callbacks = this._callbacks || {};\n (this._callbacks['$' + event] = this._callbacks['$' + event] || [])\n .push(fn);\n return this;\n};\n\n/**\n * Adds an `event` listener that will be invoked a single\n * time then automatically removed.\n *\n * @param {String} event\n * @param {Function} fn\n * @return {Emitter}\n * @api public\n */\n\nEmitter.prototype.once = function(event, fn){\n function on() {\n this.off(event, on);\n fn.apply(this, arguments);\n }\n\n on.fn = fn;\n this.on(event, on);\n return this;\n};\n\n/**\n * Remove the given callback for `event` or all\n * registered callbacks.\n *\n * @param {String} event\n * @param {Function} fn\n * @return {Emitter}\n * @api public\n */\n\nEmitter.prototype.off =\nEmitter.prototype.removeListener =\nEmitter.prototype.removeAllListeners =\nEmitter.prototype.removeEventListener = function(event, fn){\n this._callbacks = this._callbacks || {};\n\n // all\n if (0 == arguments.length) {\n this._callbacks = {};\n return this;\n }\n\n // specific event\n var callbacks = this._callbacks['$' + event];\n if (!callbacks) return this;\n\n // remove all handlers\n if (1 == arguments.length) {\n delete this._callbacks['$' + event];\n return this;\n }\n\n // remove specific handler\n var cb;\n for (var i = 0; i < callbacks.length; i++) {\n cb = callbacks[i];\n if (cb === fn || cb.fn === fn) {\n callbacks.splice(i, 1);\n break;\n }\n }\n\n // Remove event specific arrays for event types that no\n // one is subscribed for to avoid memory leak.\n if (callbacks.length === 0) {\n delete this._callbacks['$' + event];\n }\n\n return this;\n};\n\n/**\n * Emit `event` with the given args.\n *\n * @param {String} event\n * @param {Mixed} ...\n * @return {Emitter}\n */\n\nEmitter.prototype.emit = function(event){\n this._callbacks = this._callbacks || {};\n\n var args = new Array(arguments.length - 1)\n , callbacks = this._callbacks['$' + event];\n\n for (var i = 1; i < arguments.length; i++) {\n args[i - 1] = arguments[i];\n }\n\n if (callbacks) {\n callbacks = callbacks.slice(0);\n for (var i = 0, len = callbacks.length; i < len; ++i) {\n callbacks[i].apply(this, args);\n }\n }\n\n return this;\n};\n\n// alias used for reserved events (protected method)\nEmitter.prototype.emitReserved = Emitter.prototype.emit;\n\n/**\n * Return array of callbacks for `event`.\n *\n * @param {String} event\n * @return {Array}\n * @api public\n */\n\nEmitter.prototype.listeners = function(event){\n this._callbacks = this._callbacks || {};\n return this._callbacks['$' + event] || [];\n};\n\n/**\n * Check if this emitter has `event` handlers.\n *\n * @param {String} event\n * @return {Boolean}\n * @api public\n */\n\nEmitter.prototype.hasListeners = function(event){\n return !! this.listeners(event).length;\n};\n"],"names":["Emitter","obj","key","prototype","mixin","on","addEventListener","event","fn","this","_callbacks","push","once","off","apply","arguments","removeListener","removeAllListeners","removeEventListener","length","cb","callbacks","i","splice","emit","args","Array","len","slice","emitReserved","listeners","hasListeners"],"mappings":"aAMO,SAASA,EAAQC,GACtB,GAAIA,EAAK,OAWX,SAAeA,GACb,IAAK,IAAIC,KAAOF,EAAQG,UACtBF,EAAIC,GAAOF,EAAQG,UAAUD,GAE/B,OAAOD,CACT,CAhBkBG,CAAMH,EACxB,wDA0BAD,EAAQG,UAAUE,GAClBL,EAAQG,UAAUG,iBAAmB,SAASC,EAAOC,GAInD,OAHAC,KAAKC,WAAaD,KAAKC,YAAc,CAAA,GACpCD,KAAKC,WAAW,IAAMH,GAASE,KAAKC,WAAW,IAAMH,IAAU,IAC7DI,KAAKH,GACDC,IACT,EAYAT,EAAQG,UAAUS,KAAO,SAASL,EAAOC,GACvC,SAASH,IACPI,KAAKI,IAAIN,EAAOF,GAChBG,EAAGM,MAAML,KAAMM,UACjB,CAIA,OAFAV,EAAGG,GAAKA,EACRC,KAAKJ,GAAGE,EAAOF,GACRI,IACT,EAYAT,EAAQG,UAAUU,IAClBb,EAAQG,UAAUa,eAClBhB,EAAQG,UAAUc,mBAClBjB,EAAQG,UAAUe,oBAAsB,SAASX,EAAOC,GAItD,GAHAC,KAAKC,WAAaD,KAAKC,YAAc,CAAA,EAGjC,GAAKK,UAAUI,OAEjB,OADAV,KAAKC,WAAa,GACXD,KAIT,IAUIW,EAVAC,EAAYZ,KAAKC,WAAW,IAAMH,GACtC,IAAKc,EAAW,OAAOZ,KAGvB,GAAI,GAAKM,UAAUI,OAEjB,cADOV,KAAKC,WAAW,IAAMH,GACtBE,KAKT,IAAK,IAAIa,EAAI,EAAGA,EAAID,EAAUF,OAAQG,IAEpC,IADAF,EAAKC,EAAUC,MACJd,GAAMY,EAAGZ,KAAOA,EAAI,CAC7Ba,EAAUE,OAAOD,EAAG,GACpB,KACF,CASF,OAJyB,IAArBD,EAAUF,eACLV,KAAKC,WAAW,IAAMH,GAGxBE,IACT,EAUAT,EAAQG,UAAUqB,KAAO,SAASjB,GAChCE,KAAKC,WAAaD,KAAKC,YAAc,CAAA,EAKrC,IAHA,IAAIe,EAAO,IAAIC,MAAMX,UAAUI,OAAS,GACpCE,EAAYZ,KAAKC,WAAW,IAAMH,GAE7Be,EAAI,EAAGA,EAAIP,UAAUI,OAAQG,IACpCG,EAAKH,EAAI,GAAKP,UAAUO,GAG1B,GAAID,EAEG,CAAIC,EAAI,EAAb,IAAK,IAAWK,GADhBN,EAAYA,EAAUO,MAAM,IACIT,OAAQG,EAAIK,IAAOL,EACjDD,EAAUC,GAAGR,MAAML,KAAMgB,EADKN,CAKlC,OAAOV,IACT,EAGAT,EAAQG,UAAU0B,aAAe7B,EAAQG,UAAUqB,KAUnDxB,EAAQG,UAAU2B,UAAY,SAASvB,GAErC,OADAE,KAAKC,WAAaD,KAAKC,YAAc,CAAA,EAC9BD,KAAKC,WAAW,IAAMH,IAAU,EACzC,EAUAP,EAAQG,UAAU4B,aAAe,SAASxB,GACxC,QAAUE,KAAKqB,UAAUvB,GAAOY,MAClC"}
@@ -1,2 +0,0 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=!1;try{e="undefined"!=typeof XMLHttpRequest&&"withCredentials"in new XMLHttpRequest}catch(e){}var t=e;exports.hasCORS=t;
2
- //# sourceMappingURL=has-cors.js.map