From c862224ead8ed98aba0368512938d31a64e3ecc2 Mon Sep 17 00:00:00 2001 From: Sergiu Toma Date: Tue, 22 Nov 2022 10:28:45 +0200 Subject: [PATCH] LH-265: Update client and server --- app.js | 215 +++++-- public/bundle.js | 1385 +++++++++++++++++++-------------------------- public/config.js | 3 +- public/index.html | 2 +- public/index.js | 311 ++++++---- 5 files changed, 945 insertions(+), 971 deletions(-) diff --git a/app.js b/app.js index 702eb14..37f3305 100644 --- a/app.js +++ b/app.js @@ -90,28 +90,81 @@ worker = createWorker(); // https://mediasoup.org/documentation/v3/mediasoup/rtp-parameters-and-capabilities/#RtpCodecCapability // list of media codecs supported by mediasoup ... // https://github.com/versatica/mediasoup/blob/v3/src/supportedRtpCapabilities.ts -const mediaCodecs = [ +const mediaCodecs = [ { - kind: 'audio', - mimeType: 'audio/opus', - clockRate: 48000, - channels: 2, + kind : 'audio', + mimeType : 'audio/opus', + clockRate : 48000, + channels : 2 }, { - kind: 'video', - mimeType: 'video/VP8', - clockRate: 90000, - parameters: { - 'x-google-start-bitrate': 1000, + kind : 'video', + mimeType : 'video/VP8', + clockRate : 90000, + parameters : + { + 'x-google-start-bitrate' : 1000 }, + channels : 2 }, + { + kind : 'video', + mimeType : 'video/VP9', + clockRate : 90000, + parameters : + { + 'profile-id' : 2, + 'x-google-start-bitrate' : 1000 + } + }, + { + kind : 'video', + mimeType : 'video/h264', + clockRate : 90000, + parameters : + { + 'packetization-mode' : 1, + 'profile-level-id' : '4d0032', + 'level-asymmetry-allowed' : 1, + 'x-google-start-bitrate' : 1000 + } + }, + { + kind : 'video', + mimeType : 'video/h264', + clockRate : 90000, + parameters : + { + 'packetization-mode' : 1, + 'profile-level-id' : '42e01f', + 'level-asymmetry-allowed' : 1, + 'x-google-start-bitrate' : 1000 + } + } +// { +// kind: 'audio', +// mimeType: 'audio/opus', +// clockRate: 48000, +// channels: 2, +// }, +// { +// kind: 'video', +// mimeType: 'video/VP8', +// clockRate: 90000, +// parameters: { +// 'x-google-start-bitrate': 1000, +// }, +// }, ]; const closeCall = (callId) => { try { if (callId && videoCalls[callId]) { - videoCalls[callId].producer?.close(); - videoCalls[callId].consumer?.close(); + videoCalls[callId].producerVideo?.close(); + videoCalls[callId].producerAudio?.close(); + videoCalls[callId].consumerVideo?.close(); + videoCalls[callId].consumerAudio?.close(); + videoCalls[callId]?.consumerTransport?.close(); videoCalls[callId]?.producerTransport?.close(); videoCalls[callId]?.router?.close(); @@ -230,29 +283,54 @@ peers.on('connection', async socket => { - The event sent by the client (PRODUCER) after successfully connecting to producerTransport - For the router with the id callId, we make produce on producerTransport - Create the handler on producer at the 'transportclose' event - */ - socket.on('transport-produce', async ({ kind, rtpParameters, appData }, callback) => { - try { - const callId = socketDetails[socket.id]; - if (typeof rtpParameters === 'string') rtpParameters = JSON.parse(rtpParameters); + */ + socket.on('transport-produce', async ({ kind, rtpParameters, appData }, callback) => { + try { + const callId = socketDetails[socket.id]; + if (typeof rtpParameters === 'string') rtpParameters = JSON.parse(rtpParameters); + + console.log(`[transport-produce] kind: ${kind} | socket.id: ${socket.id} | callId: ${callId}`); + console.log('kind', kind); + console.log('rtpParameters', rtpParameters); - console.log('[transport-produce] | socket.id', socket.id, '| callId', callId); - videoCalls[callId].producer = await videoCalls[callId].producerTransport.produce({ - kind, - rtpParameters, - }); - console.log(`[transport-produce] Producer ID: ${videoCalls[callId].producer.id} | kind: ${videoCalls[callId].producer.kind}`); - - videoCalls[callId].producer.on('transportclose', () => { - const callId = socketDetails[socket.id]; - console.log('transport for this producer closed', callId) - closeCall(callId); - }); + if (kind === 'video') { + videoCalls[callId].producerVideo = await videoCalls[callId].producerTransport.produce({ + kind, + rtpParameters, + }); + - // Send back to the client the Producer's id - callback && callback({ - id: videoCalls[callId].producer.id - }); + console.log(`[transport-produce] Producer ID: ${videoCalls[callId].producerVideo.id} | kind: ${videoCalls[callId].producerVideo.kind}`); + + videoCalls[callId].producerVideo.on('transportclose', () => { + const callId = socketDetails[socket.id]; + console.log('transport for this producer closed', callId) + closeCall(callId); + }); + + // Send back to the client the Producer's id + callback && callback({ + id: videoCalls[callId].producerVideo.id + }); + } else if (kind === 'audio') { + videoCalls[callId].producerAudio = await videoCalls[callId].producerTransport.produce({ + kind, + rtpParameters, + }); + + console.log(`[transport-produce] Producer ID: ${videoCalls[callId].producerAudio.id} | kind: ${videoCalls[callId].producerAudio.kind}`); + + videoCalls[callId].producerAudio.on('transportclose', () => { + const callId = socketDetails[socket.id]; + console.log('transport for this producer closed', callId) + closeCall(callId); + }); + + // Send back to the client the Producer's id + callback && callback({ + id: videoCalls[callId].producerAudio.id + }); + } } catch (error) { console.log(`ERROR | transport-produce | callId ${socketDetails[socket.id]} | ${error.message}`); } @@ -281,46 +359,86 @@ peers.on('connection', async socket => { */ socket.on('consume', async ({ rtpCapabilities }, callback) => { try { + console.log(`[consume] rtpCapabilities: ${JSON.stringify(rtpCapabilities)}`); + const callId = socketDetails[socket.id]; console.log('[consume] callId', callId); // Check if the router can consume the specified producer - if (videoCalls[callId].router.canConsume({ - producerId: videoCalls[callId].producer.id, - rtpCapabilities - })) { + if ( + videoCalls[callId].router.canConsume({ + producerId: videoCalls[callId].producerVideo.id, + rtpCapabilities + }) && + videoCalls[callId].router.canConsume({ + producerId: videoCalls[callId].producerAudio.id, + rtpCapabilities + }) + ) { console.log('[consume] Can consume', callId); // Transport can now consume and return a consumer - videoCalls[callId].consumer = await videoCalls[callId].consumerTransport.consume({ - producerId: videoCalls[callId].producer.id, + videoCalls[callId].consumerVideo = await videoCalls[callId].consumerTransport.consume({ + producerId: videoCalls[callId].producerVideo.id, rtpCapabilities, paused: true, }); // https://mediasoup.org/documentation/v3/mediasoup/api/#consumer-on-transportclose - videoCalls[callId].consumer.on('transportclose', () => { + videoCalls[callId].consumerVideo.on('transportclose', () => { const callId = socketDetails[socket.id]; console.log('transport close from consumer', callId); closeCall(callId); }); // https://mediasoup.org/documentation/v3/mediasoup/api/#consumer-on-producerclose - videoCalls[callId].consumer.on('producerclose', () => { + videoCalls[callId].consumerVideo.on('producerclose', () => { const callId = socketDetails[socket.id]; console.log('producer of consumer closed', callId); closeCall(callId); }); + videoCalls[callId].consumerAudio = await videoCalls[callId].consumerTransport.consume({ + producerId: videoCalls[callId].producerAudio.id, + rtpCapabilities, + paused: true, + }); + + // https://mediasoup.org/documentation/v3/mediasoup/api/#consumer-on-transportclose + videoCalls[callId].consumerAudio.on('transportclose', () => { + const callId = socketDetails[socket.id]; + console.log('transport close from consumer', callId); + closeCall(callId); + }); + + // https://mediasoup.org/documentation/v3/mediasoup/api/#consumer-on-producerclose + videoCalls[callId].consumerAudio.on('producerclose', () => { + const callId = socketDetails[socket.id]; + console.log('producer of consumer closed', callId); + closeCall(callId); + }); + + console.log('🟠 videoCalls[callId].consumerVideo', videoCalls[callId].consumerVideo); + console.log('🟠 videoCalls[callId].consumerAudio', videoCalls[callId].consumerAudio); + // From the consumer extract the following params to send back to the Client - const params = { - id: videoCalls[callId].consumer.id, - producerId: videoCalls[callId].producer.id, - kind: videoCalls[callId].consumer.kind, - rtpParameters: videoCalls[callId].consumer.rtpParameters, + const videoParams = { + id: videoCalls[callId].consumerVideo.id, + producerId: videoCalls[callId].producerVideo.id, + kind: 'video', + rtpParameters: videoCalls[callId].consumerVideo.rtpParameters, }; + const audioParams = { + id: videoCalls[callId].consumerAudio.id, + producerId: videoCalls[callId].producerAudio.id, + kind: 'audio', + rtpParameters: videoCalls[callId].consumerAudio.rtpParameters, + }; + + console.log('[consume] videoParams', videoParams); + console.log('[consume] audioParams', audioParams); // Send the parameters to the client - callback({ params }); + callback({ videoParams, audioParams }); } else { console.log(`[canConsume] Can't consume | callId ${callId}`); callback(null); @@ -339,7 +457,7 @@ peers.on('connection', async socket => { try { const callId = socketDetails[socket.id]; console.log(`[consumer-resume] callId ${callId}`) - await videoCalls[callId].consumer.resume(); + await videoCalls[callId].consumerVideo.resume(); } catch (error) { console.log(`ERROR | consumer-resume | callId ${socketDetails[socket.id]} | ${error.message}`); } @@ -393,6 +511,7 @@ const createWebRtcTransportLayer = async (callId, callback) => { dtlsParameters: transport.dtlsParameters, }; + console.log('[createWebRtcTransportLayer] callback params', params); // Send back to the client the params callback({ params }); diff --git a/public/bundle.js b/public/bundle.js index 0b0166f..733c840 100644 --- a/public/bundle.js +++ b/public/bundle.js @@ -305,17 +305,9 @@ Backoff.prototype.setJitter = function(jitter){ * Copyright (c) 2012 Niklas von Hertzen * Licensed under the MIT license. */ -(function(){ +(function(chars){ "use strict"; - var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - // Use a lookup table to find the index. - var lookup = new Uint8Array(256); - for (var i = 0; i < chars.length; i++) { - lookup[chars.charCodeAt(i)] = i; - } - exports.encode = function(arraybuffer) { var bytes = new Uint8Array(arraybuffer), i, len = bytes.length, base64 = ""; @@ -352,10 +344,10 @@ Backoff.prototype.setJitter = function(jitter){ bytes = new Uint8Array(arraybuffer); for (i = 0; i < len; i+=4) { - encoded1 = lookup[base64.charCodeAt(i)]; - encoded2 = lookup[base64.charCodeAt(i+1)]; - encoded3 = lookup[base64.charCodeAt(i+2)]; - encoded4 = lookup[base64.charCodeAt(i+3)]; + encoded1 = chars.indexOf(base64[i]); + encoded2 = chars.indexOf(base64[i+1]); + encoded3 = chars.indexOf(base64[i+2]); + encoded4 = chars.indexOf(base64[i+3]); bytes[p++] = (encoded1 << 2) | (encoded2 >> 4); bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2); @@ -364,7 +356,7 @@ Backoff.prototype.setJitter = function(jitter){ return arraybuffer; }; -})(); +})("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"); },{}],6:[function(require,module,exports){ 'use strict' @@ -2405,7 +2397,7 @@ function numberIsNaN (obj) { } }).call(this)}).call(this,require("buffer").Buffer) -},{"base64-js":6,"buffer":10,"ieee754":37}],11:[function(require,module,exports){ +},{"base64-js":6,"buffer":10,"ieee754":36}],11:[function(require,module,exports){ /** * Slice reference. */ @@ -2544,6 +2536,13 @@ Emitter.prototype.removeEventListener = function(event, fn){ break; } } + + // Remove event specific arrays for event types that no + // one is subscribed for to avoid memory leak. + if (callbacks.length === 0) { + delete this._callbacks['$' + event]; + } + return this; }; @@ -2557,9 +2556,14 @@ Emitter.prototype.removeEventListener = function(event, fn){ Emitter.prototype.emit = function(event){ this._callbacks = this._callbacks || {}; - var args = [].slice.call(arguments, 1) + + var args = new Array(arguments.length - 1) , callbacks = this._callbacks['$' + event]; + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + if (callbacks) { callbacks = callbacks.slice(0); for (var i = 0, len = callbacks.length; i < len; ++i) { @@ -2604,399 +2608,17 @@ module.exports = function(a, b){ a.prototype.constructor = a; }; },{}],14:[function(require,module,exports){ -(function (process){(function (){ -/** - * This is the web browser implementation of `debug()`. - * - * Expose `debug()` as the module. - */ - -exports = module.exports = require('./debug'); -exports.log = log; -exports.formatArgs = formatArgs; -exports.save = save; -exports.load = load; -exports.useColors = useColors; -exports.storage = 'undefined' != typeof chrome - && 'undefined' != typeof chrome.storage - ? chrome.storage.local - : localstorage(); - -/** - * Colors. - */ - -exports.colors = [ - 'lightseagreen', - 'forestgreen', - 'goldenrod', - 'dodgerblue', - 'darkorchid', - 'crimson' -]; - -/** - * Currently only WebKit-based Web Inspectors, Firefox >= v31, - * and the Firebug extension (any Firefox version) are known - * to support "%c" CSS customizations. - * - * TODO: add a `localStorage` variable to explicitly enable/disable colors - */ - -function useColors() { - // NB: In an Electron preload script, document will be defined but not fully - // initialized. Since we know we're in Chrome, we'll just detect this case - // explicitly - if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') { - return true; +module.exports = (function () { + if (typeof self !== 'undefined') { + return self; + } else if (typeof window !== 'undefined') { + return window; + } else { + return Function('return this')(); // eslint-disable-line no-new-func } +})(); - // is webkit? http://stackoverflow.com/a/16459606/376773 - // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 - return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || - // is firebug? http://stackoverflow.com/a/398120/376773 - (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || - // is firefox >= v31? - // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages - (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || - // double check webkit in userAgent just in case we are in a worker - (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); -} - -/** - * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. - */ - -exports.formatters.j = function(v) { - try { - return JSON.stringify(v); - } catch (err) { - return '[UnexpectedJSONParseError]: ' + err.message; - } -}; - - -/** - * Colorize log arguments if enabled. - * - * @api public - */ - -function formatArgs(args) { - var useColors = this.useColors; - - args[0] = (useColors ? '%c' : '') - + this.namespace - + (useColors ? ' %c' : ' ') - + args[0] - + (useColors ? '%c ' : ' ') - + '+' + exports.humanize(this.diff); - - if (!useColors) return; - - var c = 'color: ' + this.color; - args.splice(1, 0, c, 'color: inherit') - - // the final "%c" is somewhat tricky, because there could be other - // arguments passed either before or after the %c, so we need to - // figure out the correct index to insert the CSS into - var index = 0; - var lastC = 0; - args[0].replace(/%[a-zA-Z%]/g, function(match) { - if ('%%' === match) return; - index++; - if ('%c' === match) { - // we only are interested in the *last* %c - // (the user may have provided their own) - lastC = index; - } - }); - - args.splice(lastC, 0, c); -} - -/** - * Invokes `console.log()` when available. - * No-op when `console.log` is not a "function". - * - * @api public - */ - -function log() { - // this hackery is required for IE8/9, where - // the `console.log` function doesn't have 'apply' - return 'object' === typeof console - && console.log - && Function.prototype.apply.call(console.log, console, arguments); -} - -/** - * Save `namespaces`. - * - * @param {String} namespaces - * @api private - */ - -function save(namespaces) { - try { - if (null == namespaces) { - exports.storage.removeItem('debug'); - } else { - exports.storage.debug = namespaces; - } - } catch(e) {} -} - -/** - * Load `namespaces`. - * - * @return {String} returns the previously persisted debug modes - * @api private - */ - -function load() { - var r; - try { - r = exports.storage.debug; - } catch(e) {} - - // If debug isn't set in LS, and we're in Electron, try to load $DEBUG - if (!r && typeof process !== 'undefined' && 'env' in process) { - r = process.env.DEBUG; - } - - return r; -} - -/** - * Enable namespaces listed in `localStorage.debug` initially. - */ - -exports.enable(load()); - -/** - * Localstorage attempts to return the localstorage. - * - * This is necessary because safari throws - * when a user disables cookies/localstorage - * and you attempt to access it. - * - * @return {LocalStorage} - * @api private - */ - -function localstorage() { - try { - return window.localStorage; - } catch (e) {} -} - -}).call(this)}).call(this,require('_process')) -},{"./debug":15,"_process":78}],15:[function(require,module,exports){ - -/** - * This is the common logic for both the Node.js and web browser - * implementations of `debug()`. - * - * Expose `debug()` as the module. - */ - -exports = module.exports = createDebug.debug = createDebug['default'] = createDebug; -exports.coerce = coerce; -exports.disable = disable; -exports.enable = enable; -exports.enabled = enabled; -exports.humanize = require('ms'); - -/** - * The currently active debug mode names, and names to skip. - */ - -exports.names = []; -exports.skips = []; - -/** - * Map of special "%n" handling functions, for the debug "format" argument. - * - * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". - */ - -exports.formatters = {}; - -/** - * Previous log timestamp. - */ - -var prevTime; - -/** - * Select a color. - * @param {String} namespace - * @return {Number} - * @api private - */ - -function selectColor(namespace) { - var hash = 0, i; - - for (i in namespace) { - hash = ((hash << 5) - hash) + namespace.charCodeAt(i); - hash |= 0; // Convert to 32bit integer - } - - return exports.colors[Math.abs(hash) % exports.colors.length]; -} - -/** - * Create a debugger with the given `namespace`. - * - * @param {String} namespace - * @return {Function} - * @api public - */ - -function createDebug(namespace) { - - function debug() { - // disabled? - if (!debug.enabled) return; - - var self = debug; - - // set `diff` timestamp - var curr = +new Date(); - var ms = curr - (prevTime || curr); - self.diff = ms; - self.prev = prevTime; - self.curr = curr; - prevTime = curr; - - // turn the `arguments` into a proper Array - var args = new Array(arguments.length); - for (var i = 0; i < args.length; i++) { - args[i] = arguments[i]; - } - - args[0] = exports.coerce(args[0]); - - if ('string' !== typeof args[0]) { - // anything else let's inspect with %O - args.unshift('%O'); - } - - // apply any `formatters` transformations - var index = 0; - args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) { - // if we encounter an escaped % then don't increase the array index - if (match === '%%') return match; - index++; - var formatter = exports.formatters[format]; - if ('function' === typeof formatter) { - var val = args[index]; - match = formatter.call(self, val); - - // now we need to remove `args[index]` since it's inlined in the `format` - args.splice(index, 1); - index--; - } - return match; - }); - - // apply env-specific formatting (colors, etc.) - exports.formatArgs.call(self, args); - - var logFn = debug.log || exports.log || console.log.bind(console); - logFn.apply(self, args); - } - - debug.namespace = namespace; - debug.enabled = exports.enabled(namespace); - debug.useColors = exports.useColors(); - debug.color = selectColor(namespace); - - // env-specific initialization logic for debug instances - if ('function' === typeof exports.init) { - exports.init(debug); - } - - return debug; -} - -/** - * Enables a debug mode by namespaces. This can include modes - * separated by a colon and wildcards. - * - * @param {String} namespaces - * @api public - */ - -function enable(namespaces) { - exports.save(namespaces); - - exports.names = []; - exports.skips = []; - - var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); - var len = split.length; - - for (var i = 0; i < len; i++) { - if (!split[i]) continue; // ignore empty strings - namespaces = split[i].replace(/\*/g, '.*?'); - if (namespaces[0] === '-') { - exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); - } else { - exports.names.push(new RegExp('^' + namespaces + '$')); - } - } -} - -/** - * Disable debug output. - * - * @api public - */ - -function disable() { - exports.enable(''); -} - -/** - * Returns true if the given mode name is enabled, false otherwise. - * - * @param {String} name - * @return {Boolean} - * @api public - */ - -function enabled(name) { - var i, len; - for (i = 0, len = exports.skips.length; i < len; i++) { - if (exports.skips[i].test(name)) { - return false; - } - } - for (i = 0, len = exports.names.length; i < len; i++) { - if (exports.names[i].test(name)) { - return true; - } - } - return false; -} - -/** - * Coerce `val`. - * - * @param {Mixed} val - * @return {Mixed} - * @api private - */ - -function coerce(val) { - if (val instanceof Error) return val.stack || val.message; - return val; -} - -},{"ms":75}],16:[function(require,module,exports){ +},{}],15:[function(require,module,exports){ module.exports = require('./socket'); @@ -3008,8 +2630,7 @@ module.exports = require('./socket'); */ module.exports.parser = require('engine.io-parser'); -},{"./socket":17,"engine.io-parser":27}],17:[function(require,module,exports){ -(function (global){(function (){ +},{"./socket":16,"engine.io-parser":26}],16:[function(require,module,exports){ /** * Module dependencies. */ @@ -3057,7 +2678,7 @@ function Socket (uri, opts) { } this.secure = null != opts.secure ? opts.secure - : (global.location && 'https:' === location.protocol); + : (typeof location !== 'undefined' && 'https:' === location.protocol); if (opts.hostname && !opts.port) { // if no port is specified manually, use the protocol default @@ -3066,8 +2687,8 @@ function Socket (uri, opts) { this.agent = opts.agent || false; this.hostname = opts.hostname || - (global.location ? location.hostname : 'localhost'); - this.port = opts.port || (global.location && location.port + (typeof location !== 'undefined' ? location.hostname : 'localhost'); + this.port = opts.port || (typeof location !== 'undefined' && location.port ? location.port : (this.secure ? 443 : 80)); this.query = opts.query || {}; @@ -3078,6 +2699,7 @@ function Socket (uri, opts) { this.jsonp = false !== opts.jsonp; this.forceBase64 = !!opts.forceBase64; this.enablesXDR = !!opts.enablesXDR; + this.withCredentials = false !== opts.withCredentials; this.timestampParam = opts.timestampParam || 't'; this.timestampRequests = opts.timestampRequests; this.transports = opts.transports || ['polling', 'websocket']; @@ -3097,18 +2719,20 @@ function Socket (uri, opts) { } // SSL options for Node.js client - this.pfx = opts.pfx || null; - this.key = opts.key || null; - this.passphrase = opts.passphrase || null; - this.cert = opts.cert || null; - this.ca = opts.ca || null; - this.ciphers = opts.ciphers || null; + this.pfx = opts.pfx || undefined; + this.key = opts.key || undefined; + this.passphrase = opts.passphrase || undefined; + this.cert = opts.cert || undefined; + this.ca = opts.ca || undefined; + this.ciphers = opts.ciphers || undefined; this.rejectUnauthorized = opts.rejectUnauthorized === undefined ? true : opts.rejectUnauthorized; this.forceNode = !!opts.forceNode; - // other options for Node.js client - var freeGlobal = typeof global === 'object' && global; - if (freeGlobal.global === freeGlobal) { + // detect ReactNative environment + this.isReactNative = (typeof navigator !== 'undefined' && typeof navigator.product === 'string' && navigator.product.toLowerCase() === 'reactnative'); + + // other options for Node.js or ReactNative client + if (typeof self === 'undefined' || this.isReactNative) { if (opts.extraHeaders && Object.keys(opts.extraHeaders).length > 0) { this.extraHeaders = opts.extraHeaders; } @@ -3193,6 +2817,7 @@ Socket.prototype.createTransport = function (name) { jsonp: options.jsonp || this.jsonp, forceBase64: options.forceBase64 || this.forceBase64, enablesXDR: options.enablesXDR || this.enablesXDR, + withCredentials: options.withCredentials || this.withCredentials, timestampRequests: options.timestampRequests || this.timestampRequests, timestampParam: options.timestampParam || this.timestampParam, policyPort: options.policyPort || this.policyPort, @@ -3208,7 +2833,8 @@ Socket.prototype.createTransport = function (name) { forceNode: options.forceNode || this.forceNode, localAddress: options.localAddress || this.localAddress, requestTimeout: options.requestTimeout || this.requestTimeout, - protocols: options.protocols || void (0) + protocols: options.protocols || void (0), + isReactNative: this.isReactNative }); return transport; @@ -3754,8 +3380,7 @@ Socket.prototype.filterUpgrades = function (upgrades) { return filteredUpgrades; }; -}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./transport":18,"./transports/index":19,"component-emitter":12,"debug":25,"engine.io-parser":27,"indexof":38,"parseqs":76,"parseuri":77}],18:[function(require,module,exports){ +},{"./transport":17,"./transports/index":18,"component-emitter":12,"debug":24,"engine.io-parser":26,"indexof":37,"parseqs":75,"parseuri":76}],17:[function(require,module,exports){ /** * Module dependencies. */ @@ -3788,6 +3413,7 @@ function Transport (opts) { this.agent = opts.agent || false; this.socket = opts.socket; this.enablesXDR = opts.enablesXDR; + this.withCredentials = opts.withCredentials; // SSL options for Node.js client this.pfx = opts.pfx; @@ -3799,6 +3425,9 @@ function Transport (opts) { this.rejectUnauthorized = opts.rejectUnauthorized; this.forceNode = opts.forceNode; + // results of ReactNative environment detection + this.isReactNative = opts.isReactNative; + // other options for Node.js client this.extraHeaders = opts.extraHeaders; this.localAddress = opts.localAddress; @@ -3914,13 +3543,12 @@ Transport.prototype.onClose = function () { this.emit('close'); }; -},{"component-emitter":12,"engine.io-parser":27}],19:[function(require,module,exports){ -(function (global){(function (){ +},{"component-emitter":12,"engine.io-parser":26}],18:[function(require,module,exports){ /** * Module dependencies */ -var XMLHttpRequest = require('xmlhttprequest-ssl'); +var XMLHttpRequest = require('./xmlhttprequest'); var XHR = require('./polling-xhr'); var JSONP = require('./polling-jsonp'); var websocket = require('./websocket'); @@ -3945,7 +3573,7 @@ function polling (opts) { var xs = false; var jsonp = false !== opts.jsonp; - if (global.location) { + if (typeof location !== 'undefined') { var isSSL = 'https:' === location.protocol; var port = location.port; @@ -3970,16 +3598,14 @@ function polling (opts) { } } -}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./polling-jsonp":20,"./polling-xhr":21,"./websocket":23,"xmlhttprequest-ssl":24}],20:[function(require,module,exports){ -(function (global){(function (){ - +},{"./polling-jsonp":19,"./polling-xhr":20,"./websocket":22,"./xmlhttprequest":23}],19:[function(require,module,exports){ /** * Module requirements. */ var Polling = require('./polling'); var inherit = require('component-inherit'); +var globalThis = require('../globalThis'); /** * Module exports. @@ -4022,8 +3648,7 @@ function JSONPPolling (opts) { // we do this here (lazily) to avoid unneeded global pollution if (!callbacks) { // we need to consider multiple engines in the same page - if (!global.___eio) global.___eio = []; - callbacks = global.___eio; + callbacks = globalThis.___eio = (globalThis.___eio || []); } // callback identifier @@ -4039,8 +3664,8 @@ function JSONPPolling (opts) { this.query.j = this.index; // prevent spurious errors from being emitted when the window is unloaded - if (global.document && global.addEventListener) { - global.addEventListener('beforeunload', function () { + if (typeof addEventListener === 'function') { + addEventListener('beforeunload', function () { if (self.script) self.script.onerror = empty; }, false); } @@ -4205,18 +3830,19 @@ JSONPPolling.prototype.doWrite = function (data, fn) { } }; -}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./polling":22,"component-inherit":13}],21:[function(require,module,exports){ -(function (global){(function (){ +},{"../globalThis":14,"./polling":21,"component-inherit":13}],20:[function(require,module,exports){ +/* global attachEvent */ + /** * Module requirements. */ -var XMLHttpRequest = require('xmlhttprequest-ssl'); +var XMLHttpRequest = require('./xmlhttprequest'); var Polling = require('./polling'); var Emitter = require('component-emitter'); var inherit = require('component-inherit'); var debug = require('debug')('engine.io-client:polling-xhr'); +var globalThis = require('../globalThis'); /** * Module exports. @@ -4243,7 +3869,7 @@ function XHR (opts) { this.requestTimeout = opts.requestTimeout; this.extraHeaders = opts.extraHeaders; - if (global.location) { + if (typeof location !== 'undefined') { var isSSL = 'https:' === location.protocol; var port = location.port; @@ -4252,7 +3878,7 @@ function XHR (opts) { port = isSSL ? 443 : 80; } - this.xd = opts.hostname !== global.location.hostname || + this.xd = (typeof location !== 'undefined' && opts.hostname !== location.hostname) || port !== opts.port; this.xs = opts.secure !== isSSL; } @@ -4285,6 +3911,7 @@ XHR.prototype.request = function (opts) { opts.agent = this.agent || false; opts.supportsBinary = this.supportsBinary; opts.enablesXDR = this.enablesXDR; + opts.withCredentials = this.withCredentials; // SSL options for Node.js client opts.pfx = this.pfx; @@ -4358,6 +3985,7 @@ function Request (opts) { this.isBinary = opts.isBinary; this.supportsBinary = opts.supportsBinary; this.enablesXDR = opts.enablesXDR; + this.withCredentials = opts.withCredentials; this.requestTimeout = opts.requestTimeout; // SSL options for Node.js client @@ -4432,7 +4060,7 @@ Request.prototype.create = function () { // ie6 check if ('withCredentials' in xhr) { - xhr.withCredentials = true; + xhr.withCredentials = this.withCredentials; } if (this.requestTimeout) { @@ -4451,7 +4079,7 @@ Request.prototype.create = function () { if (xhr.readyState === 2) { try { var contentType = xhr.getResponseHeader('Content-Type'); - if (self.supportsBinary && contentType === 'application/octet-stream') { + if (self.supportsBinary && contentType === 'application/octet-stream' || contentType === 'application/octet-stream; charset=UTF-8') { xhr.responseType = 'arraybuffer'; } } catch (e) {} @@ -4463,7 +4091,7 @@ Request.prototype.create = function () { // make sure the `error` event handler that's user-set // does not throw in the same tick and gets caught here setTimeout(function () { - self.onError(xhr.status); + self.onError(typeof xhr.status === 'number' ? xhr.status : 0); }, 0); } }; @@ -4481,7 +4109,7 @@ Request.prototype.create = function () { return; } - if (global.document) { + if (typeof document !== 'undefined') { this.index = Request.requestsCount++; Request.requests[this.index] = this; } @@ -4543,7 +4171,7 @@ Request.prototype.cleanup = function (fromError) { } catch (e) {} } - if (global.document) { + if (typeof document !== 'undefined') { delete Request.requests[this.index]; } @@ -4563,7 +4191,7 @@ Request.prototype.onLoad = function () { try { contentType = this.xhr.getResponseHeader('Content-Type'); } catch (e) {} - if (contentType === 'application/octet-stream') { + if (contentType === 'application/octet-stream' || contentType === 'application/octet-stream; charset=UTF-8') { data = this.xhr.response || this.xhr.responseText; } else { data = this.xhr.responseText; @@ -4583,7 +4211,7 @@ Request.prototype.onLoad = function () { */ Request.prototype.hasXDR = function () { - return 'undefined' !== typeof global.XDomainRequest && !this.xs && this.enablesXDR; + return typeof XDomainRequest !== 'undefined' && !this.xs && this.enablesXDR; }; /** @@ -4605,11 +4233,12 @@ Request.prototype.abort = function () { Request.requestsCount = 0; Request.requests = {}; -if (global.document) { - if (global.attachEvent) { - global.attachEvent('onunload', unloadHandler); - } else if (global.addEventListener) { - global.addEventListener('beforeunload', unloadHandler, false); +if (typeof document !== 'undefined') { + if (typeof attachEvent === 'function') { + attachEvent('onunload', unloadHandler); + } else if (typeof addEventListener === 'function') { + var terminationEvent = 'onpagehide' in globalThis ? 'pagehide' : 'unload'; + addEventListener(terminationEvent, unloadHandler, false); } } @@ -4621,8 +4250,7 @@ function unloadHandler () { } } -}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./polling":22,"component-emitter":12,"component-inherit":13,"debug":25,"xmlhttprequest-ssl":24}],22:[function(require,module,exports){ +},{"../globalThis":14,"./polling":21,"./xmlhttprequest":23,"component-emitter":12,"component-inherit":13,"debug":24}],21:[function(require,module,exports){ /** * Module dependencies. */ @@ -4645,7 +4273,7 @@ module.exports = Polling; */ var hasXHR2 = (function () { - var XMLHttpRequest = require('xmlhttprequest-ssl'); + var XMLHttpRequest = require('./xmlhttprequest'); var xhr = new XMLHttpRequest({ xdomain: false }); return null != xhr.responseType; })(); @@ -4755,7 +4383,7 @@ Polling.prototype.onData = function (data) { debug('polling got data %s', data); var callback = function (packet, index, total) { // if its the first message we consider the transport open - if ('opening' === self.readyState) { + if ('opening' === self.readyState && packet.type === 'open') { self.onOpen(); } @@ -4869,8 +4497,8 @@ Polling.prototype.uri = function () { return schema + '://' + (ipv6 ? '[' + this.hostname + ']' : this.hostname) + port + this.path + query; }; -},{"../transport":18,"component-inherit":13,"debug":25,"engine.io-parser":27,"parseqs":76,"xmlhttprequest-ssl":24,"yeast":94}],23:[function(require,module,exports){ -(function (global){(function (){ +},{"../transport":17,"./xmlhttprequest":23,"component-inherit":13,"debug":24,"engine.io-parser":26,"parseqs":75,"yeast":93}],22:[function(require,module,exports){ +(function (Buffer){(function (){ /** * Module dependencies. */ @@ -4881,8 +4509,15 @@ var parseqs = require('parseqs'); var inherit = require('component-inherit'); var yeast = require('yeast'); var debug = require('debug')('engine.io-client:websocket'); -var BrowserWebSocket = global.WebSocket || global.MozWebSocket; -var NodeWebSocket; + +var BrowserWebSocket, NodeWebSocket; + +if (typeof WebSocket !== 'undefined') { + BrowserWebSocket = WebSocket; +} else if (typeof self !== 'undefined') { + BrowserWebSocket = self.WebSocket || self.MozWebSocket; +} + if (typeof window === 'undefined') { try { NodeWebSocket = require('ws'); @@ -4895,10 +4530,7 @@ if (typeof window === 'undefined') { * interface exposed by `ws` for Node-like environment. */ -var WebSocket = BrowserWebSocket; -if (!WebSocket && typeof window === 'undefined') { - WebSocket = NodeWebSocket; -} +var WebSocketImpl = BrowserWebSocket || NodeWebSocket; /** * Module exports. @@ -4922,7 +4554,7 @@ function WS (opts) { this.usingBrowserWebSocket = BrowserWebSocket && !opts.forceNode; this.protocols = opts.protocols; if (!this.usingBrowserWebSocket) { - WebSocket = NodeWebSocket; + WebSocketImpl = NodeWebSocket; } Transport.call(this, opts); } @@ -4961,19 +4593,23 @@ WS.prototype.doOpen = function () { var uri = this.uri(); var protocols = this.protocols; - var opts = { - agent: this.agent, - perMessageDeflate: this.perMessageDeflate - }; - // SSL options for Node.js client - opts.pfx = this.pfx; - opts.key = this.key; - opts.passphrase = this.passphrase; - opts.cert = this.cert; - opts.ca = this.ca; - opts.ciphers = this.ciphers; - opts.rejectUnauthorized = this.rejectUnauthorized; + var opts = {}; + + if (!this.isReactNative) { + opts.agent = this.agent; + opts.perMessageDeflate = this.perMessageDeflate; + + // SSL options for Node.js client + opts.pfx = this.pfx; + opts.key = this.key; + opts.passphrase = this.passphrase; + opts.cert = this.cert; + opts.ca = this.ca; + opts.ciphers = this.ciphers; + opts.rejectUnauthorized = this.rejectUnauthorized; + } + if (this.extraHeaders) { opts.headers = this.extraHeaders; } @@ -4982,7 +4618,12 @@ WS.prototype.doOpen = function () { } try { - this.ws = this.usingBrowserWebSocket ? (protocols ? new WebSocket(uri, protocols) : new WebSocket(uri)) : new WebSocket(uri, protocols, opts); + this.ws = + this.usingBrowserWebSocket && !this.isReactNative + ? protocols + ? new WebSocketImpl(uri, protocols) + : new WebSocketImpl(uri) + : new WebSocketImpl(uri, protocols, opts); } catch (err) { return this.emit('error', err); } @@ -5049,7 +4690,7 @@ WS.prototype.write = function (packets) { } if (self.perMessageDeflate) { - var len = 'string' === typeof data ? global.Buffer.byteLength(data) : data.length; + var len = 'string' === typeof data ? Buffer.byteLength(data) : data.length; if (len < self.perMessageDeflate.threshold) { opts.compress = false; } @@ -5155,15 +4796,15 @@ WS.prototype.uri = function () { */ WS.prototype.check = function () { - return !!WebSocket && !('__initialize' in WebSocket && this.name === WS.prototype.name); + return !!WebSocketImpl && !('__initialize' in WebSocketImpl && this.name === WS.prototype.name); }; -}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"../transport":18,"component-inherit":13,"debug":25,"engine.io-parser":27,"parseqs":76,"ws":9,"yeast":94}],24:[function(require,module,exports){ -(function (global){(function (){ +}).call(this)}).call(this,require("buffer").Buffer) +},{"../transport":17,"buffer":10,"component-inherit":13,"debug":24,"engine.io-parser":26,"parseqs":75,"ws":9,"yeast":93}],23:[function(require,module,exports){ // browser shim for xmlhttprequest module var hasCORS = require('has-cors'); +var globalThis = require('../globalThis'); module.exports = function (opts) { var xdomain = opts.xdomain; @@ -5194,13 +4835,12 @@ module.exports = function (opts) { if (!xdomain) { try { - return new global[['Active'].concat('Object').join('X')]('Microsoft.XMLHTTP'); + return new globalThis[['Active'].concat('Object').join('X')]('Microsoft.XMLHTTP'); } catch (e) { } } }; -}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"has-cors":36}],25:[function(require,module,exports){ +},{"../globalThis":14,"has-cors":35}],24:[function(require,module,exports){ (function (process){(function (){ /** * This is the web browser implementation of `debug()`. @@ -5399,7 +5039,7 @@ function localstorage() { } }).call(this)}).call(this,require('_process')) -},{"./debug":26,"_process":78}],26:[function(require,module,exports){ +},{"./debug":25,"_process":77}],25:[function(require,module,exports){ /** * This is the common logic for both the Node.js and web browser @@ -5626,7 +5266,7 @@ function coerce(val) { return val; } -},{"ms":75}],27:[function(require,module,exports){ +},{"ms":74}],26:[function(require,module,exports){ /** * Module dependencies. */ @@ -6233,7 +5873,7 @@ exports.decodePayloadAsBinary = function (data, binaryType, callback) { }); }; -},{"./keys":28,"./utf8":29,"after":1,"arraybuffer.slice":2,"base64-arraybuffer":5,"blob":7,"has-binary2":35}],28:[function(require,module,exports){ +},{"./keys":27,"./utf8":28,"after":1,"arraybuffer.slice":2,"base64-arraybuffer":5,"blob":7,"has-binary2":34}],27:[function(require,module,exports){ /** * Gets the keys for an object. @@ -6254,7 +5894,7 @@ module.exports = Object.keys || function keys (obj){ return arr; }; -},{}],29:[function(require,module,exports){ +},{}],28:[function(require,module,exports){ /*! https://mths.be/utf8js v2.1.2 by @mathias */ var stringFromCharCode = String.fromCharCode; @@ -6466,7 +6106,7 @@ module.exports = { decode: utf8decode }; -},{}],30:[function(require,module,exports){ +},{}],29:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -6965,7 +6605,7 @@ function eventTargetAgnosticAddListener(emitter, name, listener, flags) { } } -},{}],31:[function(require,module,exports){ +},{}],30:[function(require,module,exports){ const debug = require('debug')('h264-profile-level-id'); /* eslint-disable no-console */ @@ -7420,7 +7060,7 @@ function isLevelAsymmetryAllowed(params = {}) ); } -},{"debug":32}],32:[function(require,module,exports){ +},{"debug":31}],31:[function(require,module,exports){ (function (process){(function (){ /* eslint-env browser */ @@ -7693,7 +7333,7 @@ formatters.j = function (v) { }; }).call(this)}).call(this,require('_process')) -},{"./common":33,"_process":78}],33:[function(require,module,exports){ +},{"./common":32,"_process":77}],32:[function(require,module,exports){ /** * This is the common logic for both the Node.js and web browser @@ -7969,7 +7609,7 @@ function setup(env) { module.exports = setup; -},{"ms":34}],34:[function(require,module,exports){ +},{"ms":33}],33:[function(require,module,exports){ /** * Helpers. */ @@ -8133,7 +7773,7 @@ function plural(ms, msAbs, n, name) { return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : ''); } -},{}],35:[function(require,module,exports){ +},{}],34:[function(require,module,exports){ (function (Buffer){(function (){ /* global Blob File */ @@ -8201,7 +7841,7 @@ function hasBinary (obj) { } }).call(this)}).call(this,require("buffer").Buffer) -},{"buffer":10,"isarray":39}],36:[function(require,module,exports){ +},{"buffer":10,"isarray":38}],35:[function(require,module,exports){ /** * Module exports. @@ -8220,7 +7860,7 @@ try { module.exports = false; } -},{}],37:[function(require,module,exports){ +},{}],36:[function(require,module,exports){ /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh */ exports.read = function (buffer, offset, isLE, mLen, nBytes) { var e, m @@ -8307,7 +7947,7 @@ exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { buffer[offset + i - d] |= s * 128 } -},{}],38:[function(require,module,exports){ +},{}],37:[function(require,module,exports){ var indexOf = [].indexOf; @@ -8318,14 +7958,14 @@ module.exports = function(arr, obj){ } return -1; }; -},{}],39:[function(require,module,exports){ +},{}],38:[function(require,module,exports){ var toString = {}.toString; module.exports = Array.isArray || function (arr) { return toString.call(arr) == '[object Array]'; }; -},{}],40:[function(require,module,exports){ +},{}],39:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Consumer = void 0; @@ -8507,7 +8147,7 @@ class Consumer extends EnhancedEventEmitter_1.EnhancedEventEmitter { } exports.Consumer = Consumer; -},{"./EnhancedEventEmitter":44,"./Logger":45,"./errors":50}],41:[function(require,module,exports){ +},{"./EnhancedEventEmitter":43,"./Logger":44,"./errors":49}],40:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DataConsumer = void 0; @@ -8663,7 +8303,7 @@ class DataConsumer extends EnhancedEventEmitter_1.EnhancedEventEmitter { } exports.DataConsumer = DataConsumer; -},{"./EnhancedEventEmitter":44,"./Logger":45}],42:[function(require,module,exports){ +},{"./EnhancedEventEmitter":43,"./Logger":44}],41:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DataProducer = void 0; @@ -8835,7 +8475,7 @@ class DataProducer extends EnhancedEventEmitter_1.EnhancedEventEmitter { } exports.DataProducer = DataProducer; -},{"./EnhancedEventEmitter":44,"./Logger":45,"./errors":50}],43:[function(require,module,exports){ +},{"./EnhancedEventEmitter":43,"./Logger":44,"./errors":49}],42:[function(require,module,exports){ "use strict"; /* global RTCRtpTransceiver */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { @@ -9230,7 +8870,7 @@ class Device { } exports.Device = Device; -},{"./EnhancedEventEmitter":44,"./Logger":45,"./Transport":49,"./errors":50,"./handlers/Chrome55":51,"./handlers/Chrome67":52,"./handlers/Chrome70":53,"./handlers/Chrome74":54,"./handlers/Edge11":55,"./handlers/Firefox60":56,"./handlers/ReactNative":58,"./handlers/Safari11":59,"./handlers/Safari12":60,"./ortc":68,"./utils":71,"bowser":8}],44:[function(require,module,exports){ +},{"./EnhancedEventEmitter":43,"./Logger":44,"./Transport":48,"./errors":49,"./handlers/Chrome55":50,"./handlers/Chrome67":51,"./handlers/Chrome70":52,"./handlers/Chrome74":53,"./handlers/Edge11":54,"./handlers/Firefox60":55,"./handlers/ReactNative":57,"./handlers/Safari11":58,"./handlers/Safari12":59,"./ortc":67,"./utils":70,"bowser":8}],43:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.EnhancedEventEmitter = void 0; @@ -9302,7 +8942,7 @@ class EnhancedEventEmitter extends events_1.EventEmitter { } exports.EnhancedEventEmitter = EnhancedEventEmitter; -},{"./Logger":45,"events":30}],45:[function(require,module,exports){ +},{"./Logger":44,"events":29}],44:[function(require,module,exports){ "use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; @@ -9341,7 +8981,7 @@ class Logger { } exports.Logger = Logger; -},{"debug":72}],46:[function(require,module,exports){ +},{"debug":71}],45:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Producer = void 0; @@ -9619,7 +9259,7 @@ class Producer extends EnhancedEventEmitter_1.EnhancedEventEmitter { } exports.Producer = Producer; -},{"./EnhancedEventEmitter":44,"./Logger":45,"./errors":50}],47:[function(require,module,exports){ +},{"./EnhancedEventEmitter":43,"./Logger":44,"./errors":49}],46:[function(require,module,exports){ "use strict"; /** * The RTP capabilities define what mediasoup or an endpoint can receive at @@ -9627,11 +9267,11 @@ exports.Producer = Producer; */ Object.defineProperty(exports, "__esModule", { value: true }); -},{}],48:[function(require,module,exports){ +},{}],47:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -},{}],49:[function(require,module,exports){ +},{}],48:[function(require,module,exports){ "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; @@ -10315,7 +9955,7 @@ class Transport extends EnhancedEventEmitter_1.EnhancedEventEmitter { } exports.Transport = Transport; -},{"./Consumer":40,"./DataConsumer":41,"./DataProducer":42,"./EnhancedEventEmitter":44,"./Logger":45,"./Producer":46,"./errors":50,"./ortc":68,"./utils":71,"awaitqueue":3}],50:[function(require,module,exports){ +},{"./Consumer":39,"./DataConsumer":40,"./DataProducer":41,"./EnhancedEventEmitter":43,"./Logger":44,"./Producer":45,"./errors":49,"./ortc":67,"./utils":70,"awaitqueue":3}],49:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.InvalidStateError = exports.UnsupportedError = void 0; @@ -10356,7 +9996,7 @@ class InvalidStateError extends Error { } exports.InvalidStateError = InvalidStateError; -},{}],51:[function(require,module,exports){ +},{}],50:[function(require,module,exports){ "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; @@ -10877,7 +10517,7 @@ class Chrome55 extends HandlerInterface_1.HandlerInterface { } exports.Chrome55 = Chrome55; -},{"../Logger":45,"../errors":50,"../ortc":68,"../utils":71,"./HandlerInterface":57,"./sdp/RemoteSdp":63,"./sdp/commonUtils":64,"./sdp/planBUtils":65,"sdp-transform":80}],52:[function(require,module,exports){ +},{"../Logger":44,"../errors":49,"../ortc":67,"../utils":70,"./HandlerInterface":56,"./sdp/RemoteSdp":62,"./sdp/commonUtils":63,"./sdp/planBUtils":64,"sdp-transform":79}],51:[function(require,module,exports){ "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; @@ -11445,7 +11085,7 @@ class Chrome67 extends HandlerInterface_1.HandlerInterface { } exports.Chrome67 = Chrome67; -},{"../Logger":45,"../ortc":68,"../utils":71,"./HandlerInterface":57,"./sdp/RemoteSdp":63,"./sdp/commonUtils":64,"./sdp/planBUtils":65,"sdp-transform":80}],53:[function(require,module,exports){ +},{"../Logger":44,"../ortc":67,"../utils":70,"./HandlerInterface":56,"./sdp/RemoteSdp":62,"./sdp/commonUtils":63,"./sdp/planBUtils":64,"sdp-transform":79}],52:[function(require,module,exports){ "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; @@ -12020,7 +11660,7 @@ class Chrome70 extends HandlerInterface_1.HandlerInterface { } exports.Chrome70 = Chrome70; -},{"../Logger":45,"../ortc":68,"../scalabilityModes":69,"../utils":71,"./HandlerInterface":57,"./sdp/RemoteSdp":63,"./sdp/commonUtils":64,"./sdp/unifiedPlanUtils":66,"sdp-transform":80}],54:[function(require,module,exports){ +},{"../Logger":44,"../ortc":67,"../scalabilityModes":68,"../utils":70,"./HandlerInterface":56,"./sdp/RemoteSdp":62,"./sdp/commonUtils":63,"./sdp/unifiedPlanUtils":65,"sdp-transform":79}],53:[function(require,module,exports){ "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; @@ -12609,7 +12249,7 @@ class Chrome74 extends HandlerInterface_1.HandlerInterface { } exports.Chrome74 = Chrome74; -},{"../Logger":45,"../ortc":68,"../scalabilityModes":69,"../utils":71,"./HandlerInterface":57,"./sdp/RemoteSdp":63,"./sdp/commonUtils":64,"./sdp/unifiedPlanUtils":66,"sdp-transform":80}],55:[function(require,module,exports){ +},{"../Logger":44,"../ortc":67,"../scalabilityModes":68,"../utils":70,"./HandlerInterface":56,"./sdp/RemoteSdp":62,"./sdp/commonUtils":63,"./sdp/unifiedPlanUtils":65,"sdp-transform":79}],54:[function(require,module,exports){ "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; @@ -13032,7 +12672,7 @@ class Edge11 extends HandlerInterface_1.HandlerInterface { } exports.Edge11 = Edge11; -},{"../Logger":45,"../errors":50,"../ortc":68,"../utils":71,"./HandlerInterface":57,"./ortc/edgeUtils":61}],56:[function(require,module,exports){ +},{"../Logger":44,"../errors":49,"../ortc":67,"../utils":70,"./HandlerInterface":56,"./ortc/edgeUtils":60}],55:[function(require,module,exports){ "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; @@ -13621,7 +13261,7 @@ class Firefox60 extends HandlerInterface_1.HandlerInterface { } exports.Firefox60 = Firefox60; -},{"../Logger":45,"../errors":50,"../ortc":68,"../utils":71,"./HandlerInterface":57,"./sdp/RemoteSdp":63,"./sdp/commonUtils":64,"./sdp/unifiedPlanUtils":66,"sdp-transform":80}],57:[function(require,module,exports){ +},{"../Logger":44,"../errors":49,"../ortc":67,"../utils":70,"./HandlerInterface":56,"./sdp/RemoteSdp":62,"./sdp/commonUtils":63,"./sdp/unifiedPlanUtils":65,"sdp-transform":79}],56:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.HandlerInterface = void 0; @@ -13633,7 +13273,7 @@ class HandlerInterface extends EnhancedEventEmitter_1.EnhancedEventEmitter { } exports.HandlerInterface = HandlerInterface; -},{"../EnhancedEventEmitter":44}],58:[function(require,module,exports){ +},{"../EnhancedEventEmitter":43}],57:[function(require,module,exports){ "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; @@ -14168,7 +13808,7 @@ class ReactNative extends HandlerInterface_1.HandlerInterface { } exports.ReactNative = ReactNative; -},{"../Logger":45,"../errors":50,"../ortc":68,"../utils":71,"./HandlerInterface":57,"./sdp/RemoteSdp":63,"./sdp/commonUtils":64,"./sdp/planBUtils":65,"sdp-transform":80}],59:[function(require,module,exports){ +},{"../Logger":44,"../errors":49,"../ortc":67,"../utils":70,"./HandlerInterface":56,"./sdp/RemoteSdp":62,"./sdp/commonUtils":63,"./sdp/planBUtils":64,"sdp-transform":79}],58:[function(require,module,exports){ "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; @@ -14728,7 +14368,7 @@ class Safari11 extends HandlerInterface_1.HandlerInterface { } exports.Safari11 = Safari11; -},{"../Logger":45,"../ortc":68,"../utils":71,"./HandlerInterface":57,"./sdp/RemoteSdp":63,"./sdp/commonUtils":64,"./sdp/planBUtils":65,"sdp-transform":80}],60:[function(require,module,exports){ +},{"../Logger":44,"../ortc":67,"../utils":70,"./HandlerInterface":56,"./sdp/RemoteSdp":62,"./sdp/commonUtils":63,"./sdp/planBUtils":64,"sdp-transform":79}],59:[function(require,module,exports){ "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; @@ -15285,7 +14925,7 @@ class Safari12 extends HandlerInterface_1.HandlerInterface { } exports.Safari12 = Safari12; -},{"../Logger":45,"../ortc":68,"../utils":71,"./HandlerInterface":57,"./sdp/RemoteSdp":63,"./sdp/commonUtils":64,"./sdp/unifiedPlanUtils":66,"sdp-transform":80}],61:[function(require,module,exports){ +},{"../Logger":44,"../ortc":67,"../utils":70,"./HandlerInterface":56,"./sdp/RemoteSdp":62,"./sdp/commonUtils":63,"./sdp/unifiedPlanUtils":65,"sdp-transform":79}],60:[function(require,module,exports){ "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; @@ -15369,7 +15009,7 @@ function mangleRtpParameters(rtpParameters) { } exports.mangleRtpParameters = mangleRtpParameters; -},{"../../utils":71}],62:[function(require,module,exports){ +},{"../../utils":70}],61:[function(require,module,exports){ "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; @@ -15903,7 +15543,7 @@ function getCodecName(codec) { return mimeTypeMatch[2]; } -},{"../../utils":71}],63:[function(require,module,exports){ +},{"../../utils":70}],62:[function(require,module,exports){ "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; @@ -16184,7 +15824,7 @@ class RemoteSdp { } exports.RemoteSdp = RemoteSdp; -},{"../../Logger":45,"./MediaSection":62,"sdp-transform":80}],64:[function(require,module,exports){ +},{"../../Logger":44,"./MediaSection":61,"sdp-transform":79}],63:[function(require,module,exports){ "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; @@ -16380,7 +16020,7 @@ function applyCodecParameters({ offerRtpParameters, answerMediaObject }) { } exports.applyCodecParameters = applyCodecParameters; -},{"sdp-transform":80}],65:[function(require,module,exports){ +},{"sdp-transform":79}],64:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.addLegacySimulcast = exports.getRtpEncodings = void 0; @@ -16526,7 +16166,7 @@ function addLegacySimulcast({ offerMediaObject, track, numStreams }) { } exports.addLegacySimulcast = addLegacySimulcast; -},{}],66:[function(require,module,exports){ +},{}],65:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.addLegacySimulcast = exports.getRtpEncodings = void 0; @@ -16651,7 +16291,7 @@ function addLegacySimulcast({ offerMediaObject, numStreams }) { } exports.addLegacySimulcast = addLegacySimulcast; -},{}],67:[function(require,module,exports){ +},{}],66:[function(require,module,exports){ "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; @@ -16698,7 +16338,7 @@ exports.version = '3.6.54'; var scalabilityModes_1 = require("./scalabilityModes"); Object.defineProperty(exports, "parseScalabilityMode", { enumerable: true, get: function () { return scalabilityModes_1.parse; } }); -},{"./Device":43,"./scalabilityModes":69,"./types":70,"debug":72}],68:[function(require,module,exports){ +},{"./Device":42,"./scalabilityModes":68,"./types":69,"debug":71}],67:[function(require,module,exports){ "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; @@ -17545,7 +17185,7 @@ function reduceRtcpFeedback(codecA, codecB) { return reducedRtcpFeedback; } -},{"./utils":71,"h264-profile-level-id":31}],69:[function(require,module,exports){ +},{"./utils":70,"h264-profile-level-id":30}],68:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.parse = void 0; @@ -17567,7 +17207,7 @@ function parse(scalabilityMode) { } exports.parse = parse; -},{}],70:[function(require,module,exports){ +},{}],69:[function(require,module,exports){ "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; @@ -17595,7 +17235,7 @@ __exportStar(require("./SctpParameters"), exports); __exportStar(require("./handlers/HandlerInterface"), exports); __exportStar(require("./errors"), exports); -},{"./Consumer":40,"./DataConsumer":41,"./DataProducer":42,"./Device":43,"./Producer":46,"./RtpParameters":47,"./SctpParameters":48,"./Transport":49,"./errors":50,"./handlers/HandlerInterface":57}],71:[function(require,module,exports){ +},{"./Consumer":39,"./DataConsumer":40,"./DataProducer":41,"./Device":42,"./Producer":45,"./RtpParameters":46,"./SctpParameters":47,"./Transport":48,"./errors":49,"./handlers/HandlerInterface":56}],70:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.generateRandomNumber = exports.clone = void 0; @@ -17616,13 +17256,13 @@ function generateRandomNumber() { } exports.generateRandomNumber = generateRandomNumber; -},{}],72:[function(require,module,exports){ +},{}],71:[function(require,module,exports){ +arguments[4][31][0].apply(exports,arguments) +},{"./common":72,"_process":77,"dup":31}],72:[function(require,module,exports){ arguments[4][32][0].apply(exports,arguments) -},{"./common":73,"_process":78,"dup":32}],73:[function(require,module,exports){ +},{"dup":32,"ms":73}],73:[function(require,module,exports){ arguments[4][33][0].apply(exports,arguments) -},{"dup":33,"ms":74}],74:[function(require,module,exports){ -arguments[4][34][0].apply(exports,arguments) -},{"dup":34}],75:[function(require,module,exports){ +},{"dup":33}],74:[function(require,module,exports){ /** * Helpers. */ @@ -17776,87 +17416,116 @@ function plural(ms, n, name) { return Math.ceil(ms / n) + ' ' + name + 's'; } +},{}],75:[function(require,module,exports){ +/** + * Compiles a querystring + * Returns string representation of the object + * + * @param {Object} + * @api private + */ + +exports.encode = function (obj) { + var str = ''; + + for (var i in obj) { + if (obj.hasOwnProperty(i)) { + if (str.length) str += '&'; + str += encodeURIComponent(i) + '=' + encodeURIComponent(obj[i]); + } + } + + return str; +}; + +/** + * Parses a simple querystring into an object + * + * @param {String} qs + * @api private + */ + +exports.decode = function(qs){ + var qry = {}; + var pairs = qs.split('&'); + for (var i = 0, l = pairs.length; i < l; i++) { + var pair = pairs[i].split('='); + qry[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]); + } + return qry; +}; + },{}],76:[function(require,module,exports){ -/** - * Compiles a querystring - * Returns string representation of the object - * - * @param {Object} - * @api private - */ - -exports.encode = function (obj) { - var str = ''; - - for (var i in obj) { - if (obj.hasOwnProperty(i)) { - if (str.length) str += '&'; - str += encodeURIComponent(i) + '=' + encodeURIComponent(obj[i]); - } - } - - return str; -}; - -/** - * Parses a simple querystring into an object - * - * @param {String} qs - * @api private - */ - -exports.decode = function(qs){ - var qry = {}; - var pairs = qs.split('&'); - for (var i = 0, l = pairs.length; i < l; i++) { - var pair = pairs[i].split('='); - qry[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]); - } - return qry; -}; +/** + * Parses an URI + * + * @author Steven Levithan (MIT license) + * @api private + */ + +var re = /^(?:(?![^:@]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/; + +var parts = [ + 'source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor' +]; + +module.exports = function parseuri(str) { + var src = str, + b = str.indexOf('['), + e = str.indexOf(']'); + + if (b != -1 && e != -1) { + str = str.substring(0, b) + str.substring(b, e).replace(/:/g, ';') + str.substring(e, str.length); + } + + var m = re.exec(str || ''), + uri = {}, + i = 14; + + while (i--) { + uri[parts[i]] = m[i] || ''; + } + + if (b != -1 && e != -1) { + uri.source = src; + uri.host = uri.host.substring(1, uri.host.length - 1).replace(/;/g, ':'); + uri.authority = uri.authority.replace('[', '').replace(']', '').replace(/;/g, ':'); + uri.ipv6uri = true; + } + + uri.pathNames = pathNames(uri, uri['path']); + uri.queryKey = queryKey(uri, uri['query']); + + return uri; +}; + +function pathNames(obj, path) { + var regx = /\/{2,9}/g, + names = path.replace(regx, "/").split("/"); + + if (path.substr(0, 1) == '/' || path.length === 0) { + names.splice(0, 1); + } + if (path.substr(path.length - 1, 1) == '/') { + names.splice(names.length - 1, 1); + } + + return names; +} + +function queryKey(uri, query) { + var data = {}; + + query.replace(/(?:^|&)([^&=]*)=?([^&]*)/g, function ($0, $1, $2) { + if ($1) { + data[$1] = $2; + } + }); + + return data; +} },{}],77:[function(require,module,exports){ -/** - * Parses an URI - * - * @author Steven Levithan (MIT license) - * @api private - */ - -var re = /^(?:(?![^:@]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/; - -var parts = [ - 'source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor' -]; - -module.exports = function parseuri(str) { - var src = str, - b = str.indexOf('['), - e = str.indexOf(']'); - - if (b != -1 && e != -1) { - str = str.substring(0, b) + str.substring(b, e).replace(/:/g, ';') + str.substring(e, str.length); - } - - var m = re.exec(str || ''), - uri = {}, - i = 14; - - while (i--) { - uri[parts[i]] = m[i] || ''; - } - - if (b != -1 && e != -1) { - uri.source = src; - uri.host = uri.host.substring(1, uri.host.length - 1).replace(/;/g, ':'); - uri.authority = uri.authority.replace('[', '').replace(']', '').replace(/;/g, ':'); - uri.ipv6uri = true; - } - - return uri; -}; - -},{}],78:[function(require,module,exports){ // shim for using process in browser var process = module.exports = {}; @@ -18042,7 +17711,7 @@ process.chdir = function (dir) { }; process.umask = function() { return 0; }; -},{}],79:[function(require,module,exports){ +},{}],78:[function(require,module,exports){ var grammar = module.exports = { v: [{ name: 'version', @@ -18538,7 +18207,7 @@ Object.keys(grammar).forEach(function (key) { }); }); -},{}],80:[function(require,module,exports){ +},{}],79:[function(require,module,exports){ var parser = require('./parser'); var writer = require('./writer'); @@ -18551,7 +18220,7 @@ exports.parseRemoteCandidates = parser.parseRemoteCandidates; exports.parseImageAttributes = parser.parseImageAttributes; exports.parseSimulcastStreamList = parser.parseSimulcastStreamList; -},{"./parser":81,"./writer":82}],81:[function(require,module,exports){ +},{"./parser":80,"./writer":81}],80:[function(require,module,exports){ var toIntIfInt = function (v) { return String(Number(v)) === v ? Number(v) : v; }; @@ -18677,7 +18346,7 @@ exports.parseSimulcastStreamList = function (str) { }); }; -},{"./grammar":79}],82:[function(require,module,exports){ +},{"./grammar":78}],81:[function(require,module,exports){ var grammar = require('./grammar'); // customized util.format - discards excess arguments and can void middle ones @@ -18793,7 +18462,7 @@ module.exports = function (session, opts) { return sdp.join('\r\n') + '\r\n'; }; -},{"./grammar":79}],83:[function(require,module,exports){ +},{"./grammar":78}],82:[function(require,module,exports){ /** * Module dependencies. @@ -18889,7 +18558,7 @@ exports.connect = lookup; exports.Manager = require('./manager'); exports.Socket = require('./socket'); -},{"./manager":84,"./socket":86,"./url":87,"debug":14,"socket.io-parser":89}],84:[function(require,module,exports){ +},{"./manager":83,"./socket":85,"./url":86,"debug":87,"socket.io-parser":90}],83:[function(require,module,exports){ /** * Module dependencies. @@ -19148,6 +18817,10 @@ Manager.prototype.connect = function (fn, opts) { var timeout = this._timeout; debug('connect attempt will timeout after %d', timeout); + if (timeout === 0) { + openSub.destroy(); // prevents a race condition with the 'open' event + } + // set timer var timer = setTimeout(function () { debug('connect attempt timed out after %d', timeout); @@ -19464,7 +19137,7 @@ Manager.prototype.onreconnect = function () { this.emitAll('reconnect', attempt); }; -},{"./on":85,"./socket":86,"backo2":4,"component-bind":11,"component-emitter":12,"debug":14,"engine.io-client":16,"indexof":38,"socket.io-parser":89}],85:[function(require,module,exports){ +},{"./on":84,"./socket":85,"backo2":4,"component-bind":11,"component-emitter":12,"debug":87,"engine.io-client":15,"indexof":37,"socket.io-parser":90}],84:[function(require,module,exports){ /** * Module exports. @@ -19490,7 +19163,7 @@ function on (obj, ev, fn) { }; } -},{}],86:[function(require,module,exports){ +},{}],85:[function(require,module,exports){ /** * Module dependencies. @@ -19503,6 +19176,7 @@ var on = require('./on'); var bind = require('component-bind'); var debug = require('debug')('socket.io-client:socket'); var parseqs = require('parseqs'); +var hasBin = require('has-binary2'); /** * Module exports. @@ -19555,6 +19229,7 @@ function Socket (io, nsp, opts) { this.sendBuffer = []; this.connected = false; this.disconnected = true; + this.flags = {}; if (opts && opts.query) { this.query = opts.query; } @@ -19595,7 +19270,7 @@ Socket.prototype.connect = function () { if (this.connected) return this; this.subEvents(); - this.io.open(); // ensure open + if (!this.io.reconnecting) this.io.open(); // ensure open if ('open' === this.io.readyState) this.onopen(); this.emit('connecting'); return this; @@ -19631,7 +19306,10 @@ Socket.prototype.emit = function (ev) { } var args = toArray(arguments); - var packet = { type: parser.EVENT, data: args }; + var packet = { + type: (this.flags.binary !== undefined ? this.flags.binary : hasBin(args)) ? parser.BINARY_EVENT : parser.EVENT, + data: args + }; packet.options = {}; packet.options.compress = !this.flags || false !== this.flags.compress; @@ -19649,7 +19327,7 @@ Socket.prototype.emit = function (ev) { this.sendBuffer.push(packet); } - delete this.flags; + this.flags = {}; return this; }; @@ -19710,7 +19388,10 @@ Socket.prototype.onclose = function (reason) { */ Socket.prototype.onpacket = function (packet) { - if (packet.nsp !== this.nsp) return; + var sameNamespace = packet.nsp === this.nsp; + var rootNamespaceError = packet.type === parser.ERROR && packet.nsp === '/'; + + if (!sameNamespace && !rootNamespaceError) return; switch (packet.type) { case parser.CONNECT: @@ -19783,7 +19464,7 @@ Socket.prototype.ack = function (id) { debug('sending ack %j', args); self.packet({ - type: parser.ACK, + type: hasBin(args) ? parser.BINARY_ACK : parser.ACK, id: id, data: args }); @@ -19817,8 +19498,8 @@ Socket.prototype.onack = function (packet) { Socket.prototype.onconnect = function () { this.connected = true; this.disconnected = false; - this.emit('connect'); this.emitBuffered(); + this.emit('connect'); }; /** @@ -19905,13 +19586,24 @@ Socket.prototype.disconnect = function () { */ Socket.prototype.compress = function (compress) { - this.flags = this.flags || {}; this.flags.compress = compress; return this; }; -},{"./on":85,"component-bind":11,"component-emitter":12,"debug":14,"parseqs":76,"socket.io-parser":89,"to-array":93}],87:[function(require,module,exports){ -(function (global){(function (){ +/** + * Sets the binary flag + * + * @param {Boolean} whether the emitted data contains binary + * @return {Socket} self + * @api public + */ + +Socket.prototype.binary = function (binary) { + this.flags.binary = binary; + return this; +}; + +},{"./on":84,"component-bind":11,"component-emitter":12,"debug":87,"has-binary2":34,"parseqs":75,"socket.io-parser":90,"to-array":92}],86:[function(require,module,exports){ /** * Module dependencies. @@ -19939,7 +19631,7 @@ function url (uri, loc) { var obj = uri; // default to window.location - loc = loc || global.location; + loc = loc || (typeof location !== 'undefined' && location); if (null == uri) uri = loc.protocol + '//' + loc.host; // relative path support @@ -19988,9 +19680,11 @@ function url (uri, loc) { return obj; } -}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"debug":14,"parseuri":77}],88:[function(require,module,exports){ -(function (global){(function (){ +},{"debug":87,"parseuri":76}],87:[function(require,module,exports){ +arguments[4][24][0].apply(exports,arguments) +},{"./debug":88,"_process":77,"dup":24}],88:[function(require,module,exports){ +arguments[4][25][0].apply(exports,arguments) +},{"dup":25,"ms":74}],89:[function(require,module,exports){ /*global Blob,File*/ /** @@ -20000,8 +19694,8 @@ function url (uri, loc) { var isArray = require('isarray'); var isBuf = require('./is-buffer'); var toString = Object.prototype.toString; -var withNativeBlob = typeof global.Blob === 'function' || toString.call(global.Blob) === '[object BlobConstructor]'; -var withNativeFile = typeof global.File === 'function' || toString.call(global.File) === '[object FileConstructor]'; +var withNativeBlob = typeof Blob === 'function' || (typeof Blob !== 'undefined' && toString.call(Blob) === '[object BlobConstructor]'); +var withNativeFile = typeof File === 'function' || (typeof File !== 'undefined' && toString.call(File) === '[object FileConstructor]'); /** * Replaces every Buffer | ArrayBuffer in packet with a numbered placeholder. @@ -20133,8 +19827,7 @@ exports.removeBlobs = function(data, callback) { } }; -}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./is-buffer":90,"isarray":39}],89:[function(require,module,exports){ +},{"./is-buffer":91,"isarray":38}],90:[function(require,module,exports){ /** * Module dependencies. @@ -20142,7 +19835,6 @@ exports.removeBlobs = function(data, callback) { var debug = require('debug')('socket.io-parser'); var Emitter = require('component-emitter'); -var hasBin = require('has-binary2'); var binary = require('./binary'); var isArray = require('isarray'); var isBuf = require('./is-buffer'); @@ -20251,6 +19943,8 @@ exports.Decoder = Decoder; function Encoder() {} +var ERROR_PACKET = exports.ERROR + '"encode error"'; + /** * Encode a packet as a single string if non-binary, or as a * buffer sequence, depending on packet type. @@ -20262,16 +19956,11 @@ function Encoder() {} */ Encoder.prototype.encode = function(obj, callback){ - if ((obj.type === exports.EVENT || obj.type === exports.ACK) && hasBin(obj.data)) { - obj.type = obj.type === exports.EVENT ? exports.BINARY_EVENT : exports.BINARY_ACK; - } - debug('encoding packet %j', obj); if (exports.BINARY_EVENT === obj.type || exports.BINARY_ACK === obj.type) { encodeAsBinary(obj, callback); - } - else { + } else { var encoding = encodeAsString(obj); callback([encoding]); } @@ -20308,13 +19997,26 @@ function encodeAsString(obj) { // json data if (null != obj.data) { - str += JSON.stringify(obj.data); + var payload = tryStringify(obj.data); + if (payload !== false) { + str += payload; + } else { + return ERROR_PACKET; + } } debug('encoded %j as %s', obj, str); return str; } +function tryStringify(str) { + try { + return JSON.stringify(str); + } catch(e){ + return false; + } +} + /** * Encode packet as 'buffer sequence' by removing blobs, and * deconstructing packet into object with placeholders and @@ -20357,7 +20059,7 @@ function Decoder() { Emitter(Decoder.prototype); /** - * Decodes an ecoded packet string into packet JSON. + * Decodes an encoded packet string into packet JSON. * * @param {String} obj - encoded packet * @return {Object} packet @@ -20378,8 +20080,7 @@ Decoder.prototype.add = function(obj) { } else { // non-binary full packet this.emit('decoded', packet); } - } - else if (isBuf(obj) || obj.base64) { // raw binary data + } else if (isBuf(obj) || obj.base64) { // raw binary data if (!this.reconstructor) { throw new Error('got binary data when not reconstructing a packet'); } else { @@ -20389,8 +20090,7 @@ Decoder.prototype.add = function(obj) { this.emit('decoded', packet); } } - } - else { + } else { throw new Error('Unknown type: ' + obj); } }; @@ -20416,11 +20116,9 @@ function decodeString(str) { // look up attachments if type binary if (exports.BINARY_EVENT === p.type || exports.BINARY_ACK === p.type) { - var buf = ''; - while (str.charAt(++i) !== '-') { - buf += str.charAt(i); - if (i == str.length) break; - } + var start = i + 1; + while (str.charAt(++i) !== '-' && i != str.length) {} + var buf = str.substring(start, i); if (buf != Number(buf) || str.charAt(i) !== '-') { throw new Error('Illegal attachments'); } @@ -20429,13 +20127,13 @@ function decodeString(str) { // look up namespace (if any) if ('/' === str.charAt(i + 1)) { - p.nsp = ''; + var start = i + 1; while (++i) { var c = str.charAt(i); if (',' === c) break; - p.nsp += c; if (i === str.length) break; } + p.nsp = str.substring(start, i); } else { p.nsp = '/'; } @@ -20443,17 +20141,16 @@ function decodeString(str) { // look up id var next = str.charAt(i + 1); if ('' !== next && Number(next) == next) { - p.id = ''; + var start = i + 1; while (++i) { var c = str.charAt(i); if (null == c || Number(c) != c) { --i; break; } - p.id += str.charAt(i); if (i === str.length) break; } - p.id = Number(p.id); + p.id = Number(str.substring(start, i + 1)); } // look up json data @@ -20544,11 +20241,18 @@ function error(msg) { }; } -},{"./binary":88,"./is-buffer":90,"component-emitter":12,"debug":91,"has-binary2":35,"isarray":39}],90:[function(require,module,exports){ -(function (global){(function (){ +},{"./binary":89,"./is-buffer":91,"component-emitter":12,"debug":87,"isarray":38}],91:[function(require,module,exports){ +(function (Buffer){(function (){ module.exports = isBuf; +var withNativeBuffer = typeof Buffer === 'function' && typeof Buffer.isBuffer === 'function'; +var withNativeArrayBuffer = typeof ArrayBuffer === 'function'; + +var isView = function (obj) { + return typeof ArrayBuffer.isView === 'function' ? ArrayBuffer.isView(obj) : (obj.buffer instanceof ArrayBuffer); +}; + /** * Returns true if obj is a buffer or an arraybuffer. * @@ -20556,16 +20260,12 @@ module.exports = isBuf; */ function isBuf(obj) { - return (global.Buffer && global.Buffer.isBuffer(obj)) || - (global.ArrayBuffer && (obj instanceof ArrayBuffer || ArrayBuffer.isView(obj))); + return (withNativeBuffer && Buffer.isBuffer(obj)) || + (withNativeArrayBuffer && (obj instanceof ArrayBuffer || isView(obj))); } -}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],91:[function(require,module,exports){ -arguments[4][25][0].apply(exports,arguments) -},{"./debug":92,"_process":78,"dup":25}],92:[function(require,module,exports){ -arguments[4][26][0].apply(exports,arguments) -},{"dup":26,"ms":75}],93:[function(require,module,exports){ +}).call(this)}).call(this,require("buffer").Buffer) +},{"buffer":10}],92:[function(require,module,exports){ module.exports = toArray function toArray(list, index) { @@ -20580,7 +20280,7 @@ function toArray(list, index) { return array } -},{}],94:[function(require,module,exports){ +},{}],93:[function(require,module,exports){ 'use strict'; var alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_'.split('') @@ -20650,13 +20350,12 @@ yeast.encode = encode; yeast.decode = decode; module.exports = yeast; -},{}],95:[function(require,module,exports){ +},{}],94:[function(require,module,exports){ module.exports = { hubAddress: 'https://hub.dev.linx.safemobile.com/', - // mediasoupAddress: 'https://video.safemobile.org/mediasoup', - mediasoupAddress: 'http://localhost:3000/mediasoup', + mediasoupAddress: 'https://video.safemobile.org', } -},{}],96:[function(require,module,exports){ +},{}],95:[function(require,module,exports){ const io = require('socket.io-client') const mediasoupClient = require('mediasoup-client') const urlParams = new URLSearchParams(location.search); @@ -20671,141 +20370,192 @@ let callId = parseInt(urlParams.get('callId')) || null; const IS_PRODUCER = urlParams.get('producer') === 'true' ? true : false console.log('[URL] ASSET_ID', ASSET_ID, '| ACCOUNT_ID', ACCOUNT_ID, '| callId', callId, ' | IS_PRODUCER', IS_PRODUCER) -let socket -hub = io(config.hubAddress) +console.log('🟩 config', config) -const connectToMediasoup = () => { +let socket, hub - socket = io(config.mediasoupAddress, { - reconnection: true, - reconnectionDelay: 1000, - reconnectionDelayMax : 5000, - reconnectionAttempts: Infinity - }) - - socket.on('connection-success', ({ _socketId, existsProducer }) => { - console.log(`[MEDIA] ${config.mediasoupAddress} | connected: ${socket.connected} | existsProducer: ${existsProducer}`) - if (!IS_PRODUCER && existsProducer && consumer === undefined) { - goConnect() - // document.getElementById('btnRecvSendTransport').click(); - } - if (IS_PRODUCER && urlParams.get('testing') === 'true') { getLocalStream() } - }) -} - -if (IS_PRODUCER === true) { - hub.on('connect', async () => { - console.log(`[HUB] ${config.hubAddress} | connected: ${hub.connected}`) - connectToMediasoup() - - hub.emit( - 'ars', - JSON.stringify({ - ars: true, - asset_id: ASSET_ID, - account_id: ACCOUNT_ID, - }) - ) +setTimeout(() => { + hub = io(config.hubAddress) - hub.on('video', (data) => { - const parsedData = JSON.parse(data); - - if (parsedData.type === 'notify-request') { - console.log('video', parsedData) - originAssetId = parsedData.origin_asset_id; - // originAssetName = parsedData.origin_asset_name; - // originAssetTypeName = parsedData.origin_asset_type_name; - callId = parsedData.video_call_id; + const connectToMediasoup = () => { - console.log('[VIDEO] notify-request | IS_PRODUCER', IS_PRODUCER, 'callId', callId); - getLocalStream() - } - - if (parsedData.type === 'notify-end') { - console.log('[VIDEO] notify-end | IS_PRODUCER', IS_PRODUCER, 'callId', callId); - resetCallSettings() - } + socket = io(config.mediasoupAddress, { + reconnection: true, + reconnectionDelay: 1000, + reconnectionDelayMax : 5000, + reconnectionAttempts: Infinity }) - }) + + socket.on('connection-success', ({ _socketId, existsProducer }) => { + console.log(`[MEDIA] ${config.mediasoupAddress} | connected: ${socket.connected} | existsProducer: ${existsProducer}`) + if (!IS_PRODUCER && existsProducer && consumer === undefined) { + goConnect() + // document.getElementById('btnRecvSendTransport').click(); + } + if (IS_PRODUCER && urlParams.get('testing') === 'true') { getLocalStream() } + }) + } + + if (IS_PRODUCER === true) { + hub.on('connect', async () => { + console.log(`[HUB]! ${config.hubAddress} | connected: ${hub.connected}`) + connectToMediasoup() + + hub.emit( + 'ars', + JSON.stringify({ + ars: true, + asset_id: ASSET_ID, + account_id: ACCOUNT_ID, + }) + ) + + hub.on('video', (data) => { + const parsedData = JSON.parse(data); + + if (parsedData.type === 'notify-request') { + console.log('video', parsedData) + originAssetId = parsedData.origin_asset_id; + // originAssetName = parsedData.origin_asset_name; + // originAssetTypeName = parsedData.origin_asset_type_name; + callId = parsedData.video_call_id; + + console.log('[VIDEO] notify-request | IS_PRODUCER', IS_PRODUCER, 'callId', callId); + getLocalStream() + } + + if (parsedData.type === 'notify-end') { + console.log('[VIDEO] notify-end | IS_PRODUCER', IS_PRODUCER, 'callId', callId); + resetCallSettings() + } + }) + }) + + hub.on('connect_error', (error) => { + console.log('connect_error', error); + }); + + hub.on('connection', () => { + console.log('connection') + }) + + hub.on('disconnect', () => { + console.log('disconnect') + }) + } else { + connectToMediasoup() + } + +}, 1600); - hub.on('connect_error', (error) => { - console.log('connect_error', error); - }); - - hub.on('connection', () => { - console.log('connection') - }) - - hub.on('disconnect', () => { - console.log('disconnect') - }) -} else { - connectToMediasoup() -} let device let rtpCapabilities let producerTransport let consumerTransport -let producer +let producerVideo +let producerAudio let consumer let originAssetId -// let originAssetName = 'Adi' -// let originAssetTypeName = 'linx' // https://mediasoup.org/documentation/v3/mediasoup-client/api/#ProducerOptions // https://mediasoup.org/documentation/v3/mediasoup-client/api/#transport-produce -let params = { - // mediasoup params +let videoParams = { encodings: [ - { - rid: 'r0', - maxBitrate: 100000, - scalabilityMode: 'S1T3', - }, - { - rid: 'r1', - maxBitrate: 300000, - scalabilityMode: 'S1T3', - }, - { - rid: 'r2', - maxBitrate: 900000, - scalabilityMode: 'S1T3', - }, + { scaleResolutionDownBy: 4, maxBitrate: 500000 }, + { scaleResolutionDownBy: 2, maxBitrate: 1000000 }, + { scaleResolutionDownBy: 1, maxBitrate: 5000000 }, + { scalabilityMode: 'S3T3_KEY' } ], - // https://mediasoup.org/documentation/v3/mediasoup-client/api/#ProducerCodecOptions codecOptions: { videoGoogleStartBitrate: 1000 } + // encodings: [ + // { + // rid: 'r0', + // maxBitrate: 100000, + // scalabilityMode: 'S1T3', + // }, + // { + // rid: 'r1', + // maxBitrate: 300000, + // scalabilityMode: 'S1T3', + // }, + // { + // rid: 'r2', + // maxBitrate: 900000, + // scalabilityMode: 'S1T3', + // }, + // ], + // // https://mediasoup.org/documentation/v3/mediasoup-client/api/#ProducerCodecOptions + // codecOptions: { + // videoGoogleStartBitrate: 1000 + // } } -const streamSuccess = (stream) => { - console.log('[streamSuccess]'); - localVideo.srcObject = stream - const track = stream.getVideoTracks()[0] - params = { - track, - ...params +let audioParams = { + codecOptions : + { + opusStereo : true, + opusDtx : true } +} + + +const streamSuccess = (stream) => { + console.log('[streamSuccess] device', device); + localVideo.srcObject = stream + console.log('stream', stream); + const videoTrack = stream.getVideoTracks()[0] + const audioTrack = stream.getAudioTracks()[0] + + videoParams = { + track: videoTrack, + // codec : device.rtpCapabilities.codecs.find((codec) => codec.mimeType.toLowerCase() === 'video/vp9'), + // codec : 'video/vp9', + ...videoParams + } + + audioParams = { + track: audioTrack, + ...audioParams + } + + console.log('[streamSuccess] videoParams', videoParams, ' | audioParams', audioParams); goConnect() + // console.log('[streamSuccess]'); + // localVideo.srcObject = stream + // const track = stream.getVideoTracks()[0] + // videoParams = { + // track, + // ...videoParams + // } + // goConnect() } const getLocalStream = () => { console.log('[getLocalStream]'); navigator.mediaDevices.getUserMedia({ - audio: false, + audio: true, video: { - width: { - min: 640, - max: 1920, - }, - height: { - min: 400, - max: 1080, - } + qvga : { width: { ideal: 320 }, height: { ideal: 240 } }, + vga : { width: { ideal: 640 }, height: { ideal: 480 } }, + hd : { width: { ideal: 1280 }, height: { ideal: 720 } } } }) + // navigator.mediaDevices.getUserMedia({ + // audio: false, + // video: { + // width: { + // min: 640, + // max: 1920, + // }, + // height: { + // min: 400, + // max: 1080, + // } + // } + // }) .then(streamSuccess) .catch(error => { console.log(error.message) @@ -20826,7 +20576,7 @@ const goCreateTransport = () => { // server side to send/recive media const createDevice = async () => { try { - console.log('[createDevice]'); + console.log('[createDevice] 1 device', device); device = new mediasoupClient.Device() // https://mediasoup.org/documentation/v3/mediasoup-client/api/#device-load @@ -20837,7 +20587,8 @@ const createDevice = async () => { }) console.log('Device RTP Capabilities', device.rtpCapabilities) - + console.log('[createDevice] 2 device', device); + // once the device loads, create transport goCreateTransport() @@ -20866,18 +20617,20 @@ const getRtpCapabilities = () => { } const createSendTransport = () => { + console.log('[createSendTransport'); // see server's socket.on('createWebRtcTransport', sender?, ...) // this is a call from Producer, so sender = true - socket.emit('createWebRtcTransport', { sender: true, callId }, ({ params }) => { + socket.emit('createWebRtcTransport', { sender: true, callId }, (value) => { + + console.log(`[createWebRtcTransport] value: ${JSON.stringify(value)}`); + + const params = value.params; // The server sends back params needed // to create Send Transport on the client side if (params.error) { console.log(params.error) return } - - console.log(params) - // creates a new WebRTC Transport to send media // based on the server's producer transport params // https://mediasoup.org/documentation/v3/mediasoup-client/api/#TransportOptions @@ -20903,7 +20656,7 @@ const createSendTransport = () => { }) producerTransport.on('produce', async (parameters, callback, errback) => { - console.log(parameters) + console.log('[produce] parameters', parameters) try { // tell the server to create a Producer @@ -20929,21 +20682,45 @@ const createSendTransport = () => { } const connectSendTransport = async () => { + + console.log('[connectSendTransport] producerTransport'); + // we now call produce() to instruct the producer transport // to send media to the Router // https://mediasoup.org/documentation/v3/mediasoup-client/api/#transport-produce // this action will trigger the 'connect' and 'produce' events above - producer = await producerTransport.produce(params) - - producer.on('trackended', () => { + + console.log('videoParams', videoParams); + producerVideo = await producerTransport.produce(videoParams) + console.log('producerVideo', producerVideo); + producerVideo.on('trackended', () => { console.log('track ended') // close video track - }) + }) - producer.on('transportclose', () => { + producerVideo.on('transportclose', () => { console.log('transport ended') // close video track - }) + }) + + console.log('audioParams', audioParams); + producerAudio = await producerTransport.produce(audioParams) + console.log('producerAudio', producerAudio); + producerAudio.on('trackended', () => { + console.log('track ended') + // close video track + }) + + producerAudio.on('transportclose', () => { + console.log('transport ended') + + // close video track + }) + + + + + const answer = { origin_asset_id: ASSET_ID, @@ -20979,7 +20756,7 @@ const createRecvTransport = async () => { return } - console.log(params) + console.log('[createRecvTransport] params', params) // creates a new WebRTC Transport to receive media // based on server's consumer transport params @@ -21009,11 +20786,11 @@ const createRecvTransport = async () => { } const resetCallSettings = () => { - socket.emit('transportclose', { callId }) localVideo.srcObject = null remoteVideo.srcObject = null consumer = null - producer = null + producerVideo = null + producerAudio = null producerTransport = null consumerTransport = null device = undefined @@ -21057,12 +20834,12 @@ const connectRecvTransport = async () => { const closeCall = () => { console.log('closeCall'); - + // Emit 'notify-end' to Hub so the consumer will know to close the video const notifyEnd = { - origin_asset_id: ASSET_ID, - dest_asset_id: originAssetId || parseInt(urlParams.get('dest_asset_id')), - type: 'notify-end', + origin_asset_id: ASSET_ID, + dest_asset_id: originAssetId || parseInt(urlParams.get('dest_asset_id')), + type: 'notify-end', video_call_id: callId } console.log('notifyEnd', notifyEnd) @@ -21072,11 +20849,11 @@ const closeCall = () => { const closeCallBtn = document.getElementById('btnCloseCall') closeCallBtn.setAttribute('disabled', '') - // Reset settings and send closeTransport to video server + // Reset settings resetCallSettings() } btnLocalVideo.addEventListener('click', getLocalStream) btnRecvSendTransport.addEventListener('click', goConnect) btnCloseCall.addEventListener('click', closeCall) -},{"./config":95,"mediasoup-client":67,"socket.io-client":83}]},{},[96]); +},{"./config":94,"mediasoup-client":66,"socket.io-client":82}]},{},[95]); diff --git a/public/config.js b/public/config.js index d12c148..fa3612f 100644 --- a/public/config.js +++ b/public/config.js @@ -1,5 +1,4 @@ module.exports = { hubAddress: 'https://hub.dev.linx.safemobile.com/', - mediasoupAddress: 'https://video.safemobile.org/mediasoup', - // mediasoupAddress: 'http://localhost:3000/mediasoup', + mediasoupAddress: 'https://video.safemobile.org', } \ No newline at end of file diff --git a/public/index.html b/public/index.html index fb0f078..71e0467 100644 --- a/public/index.html +++ b/public/index.html @@ -43,7 +43,7 @@
- +
diff --git a/public/index.js b/public/index.js index 5c3d177..b30af81 100644 --- a/public/index.js +++ b/public/index.js @@ -12,124 +12,167 @@ let callId = parseInt(urlParams.get('callId')) || null; const IS_PRODUCER = urlParams.get('producer') === 'true' ? true : false console.log('[URL] ASSET_ID', ASSET_ID, '| ACCOUNT_ID', ACCOUNT_ID, '| callId', callId, ' | IS_PRODUCER', IS_PRODUCER) -let socket -hub = io(config.hubAddress) +console.log('🟩 config', config) -const connectToMediasoup = () => { +let socket, hub - socket = io(config.mediasoupAddress, { - reconnection: true, - reconnectionDelay: 1000, - reconnectionDelayMax : 5000, - reconnectionAttempts: Infinity - }) - - socket.on('connection-success', ({ _socketId, existsProducer }) => { - console.log(`[MEDIA] ${config.mediasoupAddress} | connected: ${socket.connected} | existsProducer: ${existsProducer}`) - if (!IS_PRODUCER && existsProducer && consumer === undefined) { - goConnect() - // document.getElementById('btnRecvSendTransport').click(); - } - if (IS_PRODUCER && urlParams.get('testing') === 'true') { getLocalStream() } - }) -} - -if (IS_PRODUCER === true) { - hub.on('connect', async () => { - console.log(`[HUB] ${config.hubAddress} | connected: ${hub.connected}`) - connectToMediasoup() - - hub.emit( - 'ars', - JSON.stringify({ - ars: true, - asset_id: ASSET_ID, - account_id: ACCOUNT_ID, - }) - ) +setTimeout(() => { + hub = io(config.hubAddress) - hub.on('video', (data) => { - const parsedData = JSON.parse(data); - - if (parsedData.type === 'notify-request') { - console.log('video', parsedData) - originAssetId = parsedData.origin_asset_id; - // originAssetName = parsedData.origin_asset_name; - // originAssetTypeName = parsedData.origin_asset_type_name; - callId = parsedData.video_call_id; + const connectToMediasoup = () => { - console.log('[VIDEO] notify-request | IS_PRODUCER', IS_PRODUCER, 'callId', callId); - getLocalStream() - } - - if (parsedData.type === 'notify-end') { - console.log('[VIDEO] notify-end | IS_PRODUCER', IS_PRODUCER, 'callId', callId); - resetCallSettings() - } + socket = io(config.mediasoupAddress, { + reconnection: true, + reconnectionDelay: 1000, + reconnectionDelayMax : 5000, + reconnectionAttempts: Infinity }) - }) + + socket.on('connection-success', ({ _socketId, existsProducer }) => { + console.log(`[MEDIA] ${config.mediasoupAddress} | connected: ${socket.connected} | existsProducer: ${existsProducer}`) + if (!IS_PRODUCER && existsProducer && consumer === undefined) { + goConnect() + // document.getElementById('btnRecvSendTransport').click(); + } + if (IS_PRODUCER && urlParams.get('testing') === 'true') { getLocalStream() } + }) + } + + if (IS_PRODUCER === true) { + hub.on('connect', async () => { + console.log(`[HUB]! ${config.hubAddress} | connected: ${hub.connected}`) + connectToMediasoup() + + hub.emit( + 'ars', + JSON.stringify({ + ars: true, + asset_id: ASSET_ID, + account_id: ACCOUNT_ID, + }) + ) + + hub.on('video', (data) => { + const parsedData = JSON.parse(data); + + if (parsedData.type === 'notify-request') { + console.log('video', parsedData) + originAssetId = parsedData.origin_asset_id; + // originAssetName = parsedData.origin_asset_name; + // originAssetTypeName = parsedData.origin_asset_type_name; + callId = parsedData.video_call_id; + + console.log('[VIDEO] notify-request | IS_PRODUCER', IS_PRODUCER, 'callId', callId); + getLocalStream() + } + + if (parsedData.type === 'notify-end') { + console.log('[VIDEO] notify-end | IS_PRODUCER', IS_PRODUCER, 'callId', callId); + resetCallSettings() + } + }) + }) + + hub.on('connect_error', (error) => { + console.log('connect_error', error); + }); + + hub.on('connection', () => { + console.log('connection') + }) + + hub.on('disconnect', () => { + console.log('disconnect') + }) + } else { + connectToMediasoup() + } + +}, 1600); - hub.on('connect_error', (error) => { - console.log('connect_error', error); - }); - - hub.on('connection', () => { - console.log('connection') - }) - - hub.on('disconnect', () => { - console.log('disconnect') - }) -} else { - connectToMediasoup() -} let device let rtpCapabilities let producerTransport let consumerTransport -let producer +let producerVideo +let producerAudio let consumer let originAssetId -// let originAssetName = 'Adi' -// let originAssetTypeName = 'linx' // https://mediasoup.org/documentation/v3/mediasoup-client/api/#ProducerOptions // https://mediasoup.org/documentation/v3/mediasoup-client/api/#transport-produce -let params = { - // mediasoup params +let videoParams = { encodings: [ - { - rid: 'r0', - maxBitrate: 100000, - scalabilityMode: 'S1T3', - }, - { - rid: 'r1', - maxBitrate: 300000, - scalabilityMode: 'S1T3', - }, - { - rid: 'r2', - maxBitrate: 900000, - scalabilityMode: 'S1T3', - }, + { scaleResolutionDownBy: 4, maxBitrate: 500000 }, + { scaleResolutionDownBy: 2, maxBitrate: 1000000 }, + { scaleResolutionDownBy: 1, maxBitrate: 5000000 }, + { scalabilityMode: 'S3T3_KEY' } ], - // https://mediasoup.org/documentation/v3/mediasoup-client/api/#ProducerCodecOptions codecOptions: { videoGoogleStartBitrate: 1000 } + // encodings: [ + // { + // rid: 'r0', + // maxBitrate: 100000, + // scalabilityMode: 'S1T3', + // }, + // { + // rid: 'r1', + // maxBitrate: 300000, + // scalabilityMode: 'S1T3', + // }, + // { + // rid: 'r2', + // maxBitrate: 900000, + // scalabilityMode: 'S1T3', + // }, + // ], + // // https://mediasoup.org/documentation/v3/mediasoup-client/api/#ProducerCodecOptions + // codecOptions: { + // videoGoogleStartBitrate: 1000 + // } } -const streamSuccess = (stream) => { - console.log('[streamSuccess]'); - localVideo.srcObject = stream - const track = stream.getVideoTracks()[0] - params = { - track, - ...params +let audioParams = { + codecOptions : + { + opusStereo : true, + opusDtx : true } +} + + +const streamSuccess = (stream) => { + console.log('[streamSuccess] device', device); + localVideo.srcObject = stream + console.log('stream', stream); + const videoTrack = stream.getVideoTracks()[0] + const audioTrack = stream.getAudioTracks()[0] + + videoParams = { + track: videoTrack, + // codec : device.rtpCapabilities.codecs.find((codec) => codec.mimeType.toLowerCase() === 'video/vp9'), + // codec : 'video/vp9', + ...videoParams + } + + audioParams = { + track: audioTrack, + ...audioParams + } + + console.log('[streamSuccess] videoParams', videoParams, ' | audioParams', audioParams); goConnect() + // console.log('[streamSuccess]'); + // localVideo.srcObject = stream + // const track = stream.getVideoTracks()[0] + // videoParams = { + // track, + // ...videoParams + // } + // goConnect() } const getLocalStream = () => { @@ -137,16 +180,24 @@ const getLocalStream = () => { navigator.mediaDevices.getUserMedia({ audio: true, video: { - width: { - min: 640, - max: 1920, - }, - height: { - min: 400, - max: 1080, - } + qvga : { width: { ideal: 320 }, height: { ideal: 240 } }, + vga : { width: { ideal: 640 }, height: { ideal: 480 } }, + hd : { width: { ideal: 1280 }, height: { ideal: 720 } } } }) + // navigator.mediaDevices.getUserMedia({ + // audio: false, + // video: { + // width: { + // min: 640, + // max: 1920, + // }, + // height: { + // min: 400, + // max: 1080, + // } + // } + // }) .then(streamSuccess) .catch(error => { console.log(error.message) @@ -167,7 +218,7 @@ const goCreateTransport = () => { // server side to send/recive media const createDevice = async () => { try { - console.log('[createDevice]'); + console.log('[createDevice] 1 device', device); device = new mediasoupClient.Device() // https://mediasoup.org/documentation/v3/mediasoup-client/api/#device-load @@ -178,7 +229,8 @@ const createDevice = async () => { }) console.log('Device RTP Capabilities', device.rtpCapabilities) - + console.log('[createDevice] 2 device', device); + // once the device loads, create transport goCreateTransport() @@ -207,18 +259,20 @@ const getRtpCapabilities = () => { } const createSendTransport = () => { + console.log('[createSendTransport'); // see server's socket.on('createWebRtcTransport', sender?, ...) // this is a call from Producer, so sender = true - socket.emit('createWebRtcTransport', { sender: true, callId }, ({ params }) => { + socket.emit('createWebRtcTransport', { sender: true, callId }, (value) => { + + console.log(`[createWebRtcTransport] value: ${JSON.stringify(value)}`); + + const params = value.params; // The server sends back params needed // to create Send Transport on the client side if (params.error) { console.log(params.error) return } - - console.log(params) - // creates a new WebRTC Transport to send media // based on the server's producer transport params // https://mediasoup.org/documentation/v3/mediasoup-client/api/#TransportOptions @@ -244,7 +298,7 @@ const createSendTransport = () => { }) producerTransport.on('produce', async (parameters, callback, errback) => { - console.log(parameters) + console.log('[produce] parameters', parameters) try { // tell the server to create a Producer @@ -270,21 +324,45 @@ const createSendTransport = () => { } const connectSendTransport = async () => { + + console.log('[connectSendTransport] producerTransport'); + // we now call produce() to instruct the producer transport // to send media to the Router // https://mediasoup.org/documentation/v3/mediasoup-client/api/#transport-produce // this action will trigger the 'connect' and 'produce' events above - producer = await producerTransport.produce(params) - - producer.on('trackended', () => { + + console.log('videoParams', videoParams); + producerVideo = await producerTransport.produce(videoParams) + console.log('producerVideo', producerVideo); + producerVideo.on('trackended', () => { console.log('track ended') // close video track - }) + }) - producer.on('transportclose', () => { + producerVideo.on('transportclose', () => { console.log('transport ended') // close video track - }) + }) + + console.log('audioParams', audioParams); + producerAudio = await producerTransport.produce(audioParams) + console.log('producerAudio', producerAudio); + producerAudio.on('trackended', () => { + console.log('track ended') + // close video track + }) + + producerAudio.on('transportclose', () => { + console.log('transport ended') + + // close video track + }) + + + + + const answer = { origin_asset_id: ASSET_ID, @@ -320,7 +398,7 @@ const createRecvTransport = async () => { return } - console.log(params) + console.log('[createRecvTransport] params', params) // creates a new WebRTC Transport to receive media // based on server's consumer transport params @@ -353,7 +431,8 @@ const resetCallSettings = () => { localVideo.srcObject = null remoteVideo.srcObject = null consumer = null - producer = null + producerVideo = null + producerAudio = null producerTransport = null consumerTransport = null device = undefined