PageSourceSearch

https://www.levelsauto.com/js/goxee-voice.bundle.js

js levelsauto.com collected 2026-10-09 23:36:54 UTC 438,225 bytes, 10,975 lines download raw bytes

vendor: 4,171 bytes, lines 1-136
1(function () {
2	'use strict';
3
4	function _mergeNamespaces(n, m) {
5		m.forEach(function (e) {
6			e && typeof e !== 'string' && !Array.isArray(e) && Object.keys(e).forEach(function (k) {
7				if (k !== 'default' && !(k in n)) {
8					var d = Object.getOwnPropertyDescriptor(e, k);
9					Object.defineProperty(n, k, d.get ? d : {
10						enumerable: true,
11						get: function () { return e[k]; }
12					});
13				}
14			});
15		});
16		return Object.freeze(n);
17	}
18
19	function getDefaultExportFromCjs (x) {
20		return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
21	}
22
23	var events = {exports: {}};
24
25	var hasRequiredEvents;
26
27	function requireEvents () {
28		if (hasRequiredEvents) return events.exports;
29		hasRequiredEvents = 1;
30
31		var R = typeof Reflect === 'object' ? Reflect : null;
32		var ReflectApply = R && typeof R.apply === 'function'
33		  ? R.apply
34		  : function ReflectApply(target, receiver, args) {
35		    return Function.prototype.apply.call(target, receiver, args);
36		  };
37
38		var ReflectOwnKeys;
39		if (R && typeof R.ownKeys === 'function') {
40		  ReflectOwnKeys = R.ownKeys;
41		} else if (Object.getOwnPropertySymbols) {
42		  ReflectOwnKeys = function ReflectOwnKeys(target) {
43		    return Object.getOwnPropertyNames(target)
44		      .concat(Object.getOwnPropertySymbols(target));
45		  };
46		} else {
47		  ReflectOwnKeys = function ReflectOwnKeys(target) {
48		    return Object.getOwnPropertyNames(target);
49		  };
50		}
51
52		function ProcessEmitWarning(warning) {
53		  if (console && console.warn) console.warn(warning);
54		}
55
56		var NumberIsNaN = Number.isNaN || function NumberIsNaN(value) {
57		  return value !== value;
58		};
59
60		function EventEmitter() {
61		  EventEmitter.init.call(this);
62		}
63		events.exports = EventEmitter;
64		events.exports.once = once;
65
66		// Backwards-compat with node 0.10.x
67		EventEmitter.EventEmitter = EventEmitter;
68
69		EventEmitter.prototype._events = undefined;
70		EventEmitter.prototype._eventsCount = 0;
71		EventEmitter.prototype._maxListeners = undefined;
72
73		// By default EventEmitters will print a warning if more than 10 listeners are
74		// added to it. This is a useful default which helps finding memory leaks.
75		var defaultMaxListeners = 10;
76
77		function checkListener(listener) {
78		  if (typeof listener !== 'function') {
79		    throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener);
80		  }
81		}
82
83		Object.defineProperty(EventEmitter, 'defaultMaxListeners', {
84		  enumerable: true,
85		  get: function() {
86		    return defaultMaxListeners;
87		  },
88		  set: function(arg) {
89		    if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {
90		      throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' + arg + '.');
91		    }
92		    defaultMaxListeners = arg;
93		  }
94		});
95
96		EventEmitter.init = function() {
97
98		  if (this._events === undefined ||
99		      this._events === Object.getPrototypeOf(this)._events) {
100		    this._events = Object.create(null);
101		    this._eventsCount = 0;
102		  }
103
104		  this._maxListeners = this._maxListeners || undefined;
105		};
106
107		// Obviously not all Emitters should be limited to 10. This function allows
108		// that to be increased. Set to zero for unlimited.
109		EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
110		  if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {
111		    throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + '.');
112		  }
113		  this._maxListeners = n;
114		  return this;
115		};
116
117		function _getMaxListeners(that) {
118		  if (that._maxListeners === undefined)
119		    return EventEmitter.defaultMaxListeners;
120		  return that._maxListeners;
121		}
122
123		EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
124		  return _getMaxListeners(this);
125		};
126
127		EventEmitter.prototype.emit = function emit(type) {
128		  var args = [];
129		  for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);
130		  var doError = (type === 'error');
131
132		  var events = this._events;
133		  if (events !== undefined)
134		    doError = (doError && events.error === undefined);
135		  else if (!doError)
136		    return false;
vendor: 5,112 bytes, lines 137-295
137
138		  // If there is no 'error' event listener then throw.
139		  if (doError) {
140		    var er;
141		    if (args.length > 0)
142		      er = args[0];
143		    if (er instanceof Error) {
144		      // Note: The comments on the `throw` lines are intentional, they show
145		      // up in Node's output if this results in an unhandled exception.
146		      throw er; // Unhandled 'error' event
147		    }
148		    // At least give some kind of context to the user
149		    var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));
150		    err.context = er;
151		    throw err; // Unhandled 'error' event
152		  }
153
154		  var handler = events[type];
155
156		  if (handler === undefined)
157		    return false;
158
159		  if (typeof handler === 'function') {
160		    ReflectApply(handler, this, args);
161		  } else {
162		    var len = handler.length;
163		    var listeners = arrayClone(handler, len);
164		    for (var i = 0; i < len; ++i)
165		      ReflectApply(listeners[i], this, args);
166		  }
167
168		  return true;
169		};
170
171		function _addListener(target, type, listener, prepend) {
172		  var m;
173		  var events;
174		  var existing;
175
176		  checkListener(listener);
177
178		  events = target._events;
179		  if (events === undefined) {
180		    events = target._events = Object.create(null);
181		    target._eventsCount = 0;
182		  } else {
183		    // To avoid recursion in the case that type === "newListener"! Before
184		    // adding it to the listeners, first emit "newListener".
185		    if (events.newListener !== undefined) {
186		      target.emit('newListener', type,
187		                  listener.listener ? listener.listener : listener);
188
189		      // Re-assign `events` because a newListener handler could have caused the
190		      // this._events to be assigned to a new object
191		      events = target._events;
192		    }
193		    existing = events[type];
194		  }
195
196		  if (existing === undefined) {
197		    // Optimize the case of one listener. Don't need the extra array object.
198		    existing = events[type] = listener;
199		    ++target._eventsCount;
200		  } else {
201		    if (typeof existing === 'function') {
202		      // Adding the second element, need to change to array.
203		      existing = events[type] =
204		        prepend ? [listener, existing] : [existing, listener];
205		      // If we've already got an array, just append.
206		    } else if (prepend) {
207		      existing.unshift(listener);
208		    } else {
209		      existing.push(listener);
210		    }
211
212		    // Check for listener leak
213		    m = _getMaxListeners(target);
214		    if (m > 0 && existing.length > m && !existing.warned) {
215		      existing.warned = true;
216		      // No error code for this since it is a Warning
217		      // eslint-disable-next-line no-restricted-syntax
218		      var w = new Error('Possible EventEmitter memory leak detected. ' +
219		                          existing.length + ' ' + String(type) + ' listeners ' +
220		                          'added. Use emitter.setMaxListeners() to ' +
221		                          'increase limit');
222		      w.name = 'MaxListenersExceededWarning';
223		      w.emitter = target;
224		      w.type = type;
225		      w.count = existing.length;
226		      ProcessEmitWarning(w);
227		    }
228		  }
229
230		  return target;
231		}
232
233		EventEmitter.prototype.addListener = function addListener(type, listener) {
234		  return _addListener(this, type, listener, false);
235		};
236
237		EventEmitter.prototype.on = EventEmitter.prototype.addListener;
238
239		EventEmitter.prototype.prependListener =
240		    function prependListener(type, listener) {
241		      return _addListener(this, type, listener, true);
242		    };
243
244		function onceWrapper() {
245		  if (!this.fired) {
246		    this.target.removeListener(this.type, this.wrapFn);
247		    this.fired = true;
248		    if (arguments.length === 0)
249		      return this.listener.call(this.target);
250		    return this.listener.apply(this.target, arguments);
251		  }
252		}
253
254		function _onceWrap(target, type, listener) {
255		  var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };
256		  var wrapped = onceWrapper.bind(state);
257		  wrapped.listener = listener;
258		  state.wrapFn = wrapped;
259		  return wrapped;
260		}
261
262		EventEmitter.prototype.once = function once(type, listener) {
263		  checkListener(listener);
264		  this.on(type, _onceWrap(this, type, listener));
265		  return this;
266		};
267
268		EventEmitter.prototype.prependOnceListener =
269		    function prependOnceListener(type, listener) {
270		      checkListener(listener);
271		      this.prependListener(type, _onceWrap(this, type, listener));
272		      return this;
273		    };
274
275		// Emits a 'removeListener' event if and only if the listener was removed.
276		EventEmitter.prototype.removeListener =
277		    function removeListener(type, listener) {
278		      var list, events, position, i, originalListener;
279
280		      checkListener(listener);
281
282		      events = this._events;
283		      if (events === undefined)
284		        return this;
285
286		      list = events[type];
287		      if (list === undefined)
288		        return this;
289
290		      if (list === listener || list.listener === listener) {
291		        if (--this._eventsCount === 0)
292		          this._events = Object.create(null);
293		        else {
294		          delete events[type];
295		          if (events.removeListener)
vendor: 7,439 bytes, lines 296-538
296		            this.emit('removeListener', type, list.listener || listener);
297		        }
298		      } else if (typeof list !== 'function') {
299		        position = -1;
300
301		        for (i = list.length - 1; i >= 0; i--) {
302		          if (list[i] === listener || list[i].listener === listener) {
303		            originalListener = list[i].listener;
304		            position = i;
305		            break;
306		          }
307		        }
308
309		        if (position < 0)
310		          return this;
311
312		        if (position === 0)
313		          list.shift();
314		        else {
315		          spliceOne(list, position);
316		        }
317
318		        if (list.length === 1)
319		          events[type] = list[0];
320
321		        if (events.removeListener !== undefined)
322		          this.emit('removeListener', type, originalListener || listener);
323		      }
324
325		      return this;
326		    };
327
328		EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
329
330		EventEmitter.prototype.removeAllListeners =
331		    function removeAllListeners(type) {
332		      var listeners, events, i;
333
334		      events = this._events;
335		      if (events === undefined)
336		        return this;
337
338		      // not listening for removeListener, no need to emit
339		      if (events.removeListener === undefined) {
340		        if (arguments.length === 0) {
341		          this._events = Object.create(null);
342		          this._eventsCount = 0;
343		        } else if (events[type] !== undefined) {
344		          if (--this._eventsCount === 0)
345		            this._events = Object.create(null);
346		          else
347		            delete events[type];
348		        }
349		        return this;
350		      }
351
352		      // emit removeListener for all listeners on all events
353		      if (arguments.length === 0) {
354		        var keys = Object.keys(events);
355		        var key;
356		        for (i = 0; i < keys.length; ++i) {
357		          key = keys[i];
358		          if (key === 'removeListener') continue;
359		          this.removeAllListeners(key);
360		        }
361		        this.removeAllListeners('removeListener');
362		        this._events = Object.create(null);
363		        this._eventsCount = 0;
364		        return this;
365		      }
366
367		      listeners = events[type];
368
369		      if (typeof listeners === 'function') {
370		        this.removeListener(type, listeners);
371		      } else if (listeners !== undefined) {
372		        // LIFO order
373		        for (i = listeners.length - 1; i >= 0; i--) {
374		          this.removeListener(type, listeners[i]);
375		        }
376		      }
377
378		      return this;
379		    };
380
381		function _listeners(target, type, unwrap) {
382		  var events = target._events;
383
384		  if (events === undefined)
385		    return [];
386
387		  var evlistener = events[type];
388		  if (evlistener === undefined)
389		    return [];
390
391		  if (typeof evlistener === 'function')
392		    return unwrap ? [evlistener.listener || evlistener] : [evlistener];
393
394		  return unwrap ?
395		    unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);
396		}
397
398		EventEmitter.prototype.listeners = function listeners(type) {
399		  return _listeners(this, type, true);
400		};
401
402		EventEmitter.prototype.rawListeners = function rawListeners(type) {
403		  return _listeners(this, type, false);
404		};
405
406		EventEmitter.listenerCount = function(emitter, type) {
407		  if (typeof emitter.listenerCount === 'function') {
408		    return emitter.listenerCount(type);
409		  } else {
410		    return listenerCount.call(emitter, type);
411		  }
412		};
413
414		EventEmitter.prototype.listenerCount = listenerCount;
415		function listenerCount(type) {
416		  var events = this._events;
417
418		  if (events !== undefined) {
419		    var evlistener = events[type];
420
421		    if (typeof evlistener === 'function') {
422		      return 1;
423		    } else if (evlistener !== undefined) {
424		      return evlistener.length;
425		    }
426		  }
427
428		  return 0;
429		}
430
431		EventEmitter.prototype.eventNames = function eventNames() {
432		  return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];
433		};
434
435		function arrayClone(arr, n) {
436		  var copy = new Array(n);
437		  for (var i = 0; i < n; ++i)
438		    copy[i] = arr[i];
439		  return copy;
440		}
441
442		function spliceOne(list, index) {
443		  for (; index + 1 < list.length; index++)
444		    list[index] = list[index + 1];
445		  list.pop();
446		}
447
448		function unwrapListeners(arr) {
449		  var ret = new Array(arr.length);
450		  for (var i = 0; i < ret.length; ++i) {
451		    ret[i] = arr[i].listener || arr[i];
452		  }
453		  return ret;
454		}
455
456		function once(emitter, name) {
457		  return new Promise(function (resolve, reject) {
458		    function errorListener(err) {
459		      emitter.removeListener(name, resolver);
460		      reject(err);
461		    }
462
463		    function resolver() {
464		      if (typeof emitter.removeListener === 'function') {
465		        emitter.removeListener('error', errorListener);
466		      }
467		      resolve([].slice.call(arguments));
468		    }
469		    eventTargetAgnosticAddListener(emitter, name, resolver, { once: true });
470		    if (name !== 'error') {
471		      addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true });
472		    }
473		  });
474		}
475
476		function addErrorHandlerIfEventEmitter(emitter, handler, flags) {
477		  if (typeof emitter.on === 'function') {
478		    eventTargetAgnosticAddListener(emitter, 'error', handler, flags);
479		  }
480		}
481
482		function eventTargetAgnosticAddListener(emitter, name, listener, flags) {
483		  if (typeof emitter.on === 'function') {
484		    if (flags.once) {
485		      emitter.once(name, listener);
486		    } else {
487		      emitter.on(name, listener);
488		    }
489		  } else if (typeof emitter.addEventListener === 'function') {
490		    // EventTarget does not have `error` event semantics like Node
491		    // EventEmitters, we do not listen for `error` events here.
492		    emitter.addEventListener(name, function wrapListener(arg) {
493		      // IE does not have builtin `{ once: true }` support so we
494		      // have to do it manually.
495		      if (flags.once) {
496		        emitter.removeEventListener(name, wrapListener);
497		      }
498		      listener(arg);
499		    });
500		  } else {
501		    throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type ' + typeof emitter);
502		  }
503		}
504		return events.exports;
505	}
506
507	var eventsExports = requireEvents();
508
509	// @ts-nocheck
510	// NOTE (csantos): This file was taken directly from twilio-video and has been renamed from JS to TS only.
511	// It needs to be re-written as part of the overall updating of the files to TS.
512	class Backoff extends eventsExports.EventEmitter {
513	    /**
514	     * Construct a {@link Backoff}.
515	     * @param {object} options
516	     * @property {number} min - Initial timeout in milliseconds [100]
517	     * @property {number} max - Max timeout [10000]
518	     * @property {boolean} jitter - Apply jitter [0]
519	     * @property {number} factor - Multiplication factor for Backoff operation [2]
520	     */
521	    constructor(options) {
522	        super();
523	        Object.defineProperties(this, {
524	            _attempts: {
525	                value: 0,
526	                writable: true,
527	            },
528	            _duration: {
529	                enumerable: false,
530	                get() {
531	                    let ms = this._min * Math.pow(this._factor, this._attempts);
532	                    if (this._jitter) {
533	                        const rand = Math.random();
534	                        const deviation = Math.floor(rand * this._jitter * ms);
535	                        // tslint:disable-next-line
536	                        ms = (Math.floor(rand * 10) & 1) === 0 ? ms - deviation : ms + deviation;
537	                    }
538	                    // tslint:disable-next-line
539	                    return Math.min(ms, this._max) | 0;
540	                },
541	            },
542	            _factor: { value: options.factor || 2 },
543	            _jitter: { value: options.jitter > 0 && options.jitter <= 1 ? options.jitter : 0 },
544	            _max: { value: options.max || 10000 },
545	            _min: { value: options.min || 100 },
546	            _timeoutID: {
547	                value: null,
548	                writable: true,
549	            },
550	        });
551	    }
552	    backoff() {
553	        const duration = this._duration;
554	        if (this._timeoutID) {
555	            clearTimeout(this._timeoutID);
556	            this._timeoutID = null;
557	        }
558	        this.emit('backoff', this._attempts, duration);
559	        this._timeoutID = setTimeout(() => {
560	            this.emit('ready', this._attempts, duration);
561	            this._attempts++;
562	        }, duration);
563	    }
564	    reset() {
565	        this._attempts = 0;
566	        if (this._timeoutID) {
567	            clearTimeout(this._timeoutID);
568	            this._timeoutID = null;
569	        }
570	    }
571	}
572
573	/******************************************************************************
574	Copyright (c) Microsoft Corporation.
575
576	Permission to use, copy, modify, and/or distribute this software for any
577	purpose with or without fee is hereby granted.
578
579	THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
580	REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
581	AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
582	INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
583	LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
584	OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
585	PERFORMANCE OF THIS SOFTWARE.
586	***************************************************************************** */
587	/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
588
589
590	function __awaiter(thisArg, _arguments, P, generator) {
591	  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
592	  return new (P || (P = Promise))(function (resolve, reject) {
593	      function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
594	      function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
595	      function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
596	      step((generator = generator.apply(thisArg, _arguments || [])).next());
597	  });
598	}
599
600	typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
601	  var e = new Error(message);
602	  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
603	};
604
605	var loglevel$3 = {exports: {}};
606
607	/*
608	* loglevel - https://github.com/pimterry/loglevel
609	*
610	* Copyright (c) 2013 Tim Perry
611	* Licensed under the MIT license.
612	*/
613	var loglevel$2 = loglevel$3.exports;
614
615	var hasRequiredLoglevel;
616
617	function requireLoglevel () {
618		if (hasRequiredLoglevel) return loglevel$3.exports;
619		hasRequiredLoglevel = 1;
620		(function (module) {
621			(function (root, definition) {
622			    if (module.exports) {
623			        module.exports = definition();
624			    } else {
625			        root.log = definition();
626			    }
627			}(loglevel$2, function () {
628
629			    // Slightly dubious tricks to cut down minimized file size
630			    var noop = function() {};
631			    var undefinedType = "undefined";
632			    var isIE = (typeof window !== undefinedType) && (typeof window.navigator !== undefinedType) && (
633			        /Trident\/|MSIE /.test(window.navigator.userAgent)
634			    );
635
636			    var logMethods = [
637			        "trace",
638			        "debug",
639			        "info",
640			        "warn",
641			        "error"
642			    ];
643
644			    var _loggersByName = {};
645			    var defaultLogger = null;
646
647			    // Cross-browser bind equivalent that works at least back to IE6
648			    function bindMethod(obj, methodName) {
649			        var method = obj[methodName];
650			        if (typeof method.bind === 'function') {
651			            return method.bind(obj);
652			        } else {
653			            try {
654			                return Function.prototype.bind.call(method, obj);
655			            } catch (e) {
656			                // Missing bind shim or IE8 + Modernizr, fallback to wrapping
657			                return function() {
658			                    return Function.prototype.apply.apply(method, [obj, arguments]);
659			                };
660			            }
661			        }
662			    }
663
664			    // Trace() doesn't print the message in IE, so for that case we need to wrap it
665			    function traceForIE() {
666			        if (console.log) {
667			            if (console.log.apply) {
668			                console.log.apply(console, arguments);
669			            } else {
670			                // In old IE, native console methods themselves don't have apply().
671			                Function.prototype.apply.apply(console.log, [console, arguments]);
672			            }
673			        }
674			        if (console.trace) console.trace();
675			    }
676
677			    // Build the best logging method possible for this env
678			    // Wherever possible we want to bind, not wrap, to preserve stack traces
679			    function realMethod(methodName) {
680			        if (methodName === 'debug') {
681			            methodName = 'log';
682			        }
683
684			        if (typeof console === undefinedType) {
685			            return false; // No method possible, for now - fixed later by enableLoggingWhenConsoleArrives
686			        } else if (methodName === 'trace' && isIE) {
687			            return traceForIE;
688			        } else if (console[methodName] !== undefined) {
689			            return bindMethod(console, methodName);
690			        } else if (console.log !== undefined) {
691			            return bindMethod(console, 'log');
692			        } else {
693			            return noop;
694			        }
695			    }
696
697			    // These private functions always need `this` to be set properly
698
699			    function replaceLoggingMethods() {
700			        /*jshint validthis:true */
701			        var level = this.getLevel();
702
703			        // Replace the actual methods.
704			        for (var i = 0; i < logMethods.length; i++) {
705			            var methodName = logMethods[i];
706			            this[methodName] = (i < level) ?
707			                noop :
708			                this.methodFactory(methodName, level, this.name);
709			        }
710
711			        // Define log.log as an alias for log.debug
712			        this.log = this.debug;
713
714			        // Return any important warnings.
715			        if (typeof console === undefinedType && level < this.levels.SILENT) {
716			            return "No console available for logging";
717			        }
718			    }
719
720			    // In old IE versions, the console isn't present until you first open it.
721			    // We build realMethod() replacements here that regenerate logging methods
722			    function enableLoggingWhenConsoleArrives(methodName) {
723			        return function () {
724			            if (typeof console !== undefinedType) {
725			                replaceLoggingMethods.call(this);
726			                this[methodName].apply(this, arguments);
727			            }
728			        };
729			    }
730
731			    // By default, we use closely bound real methods wherever possible, and
732			    // otherwise we wait for a console to appear, and then try again.
733			    function defaultMethodFactory(methodName, _level, _loggerName) {
734			        /*jshint validthis:true */
735			        return realMethod(methodName) ||
736			               enableLoggingWhenConsoleArrives.apply(this, arguments);
737			    }
738
739			    function Logger(name, factory) {
740			      // Private instance variables.
741			      var self = this;
742			      /**
743			       * The level inherited from a parent logger (or a global default). We
744			       * cache this here rather than delegating to the parent so that it stays
745			       * in sync with the actual logging methods that we have installed (the
746			       * parent could change levels but we might not have rebuilt the loggers
747			       * in this child yet).
748			       * @type {number}
749			       */
750			      var inheritedLevel;
751			      /**
752			       * The default level for this logger, if any. If set, this overrides
753			       * `inheritedLevel`.
754			       * @type {number|null}
755			       */
756			      var defaultLevel;
757			      /**
758			       * A user-specific level for this logger. If set, this overrides
759			       * `defaultLevel`.
760			       * @type {number|null}
761			       */
762			      var userLevel;
763
764			      var storageKey = "loglevel";
765			      if (typeof name === "string") {
766			        storageKey += ":" + name;
767			      } else if (typeof name === "symbol") {
768			        storageKey = undefined;
769			      }
770
771			      function persistLevelIfPossible(levelNum) {
772			          var levelName = (logMethods[levelNum] || 'silent').toUpperCase();
773
774			          if (typeof window === undefinedType || !storageKey) return;
775
776			          // Use localStorage if available
777			          try {
778			              window.localStorage[storageKey] = levelName;
779			              return;
780			          } catch (ignore) {}
781
782			          // Use session cookie as fallback
783			          try {
784			              window.document.cookie =
785			                encodeURIComponent(storageKey) + "=" + levelName + ";";
786			          } catch (ignore) {}
787			      }
788
789			      function getPersistedLevel() {
790			          var storedLevel;
791
792			          if (typeof window === undefinedType || !storageKey) return;
793
794			          try {
795			              storedLevel = window.localStorage[storageKey];
796			          } catch (ignore) {}
797
798			          // Fallback to cookies if local storage gives us nothing
799			          if (typeof storedLevel === undefinedType) {
800			              try {
801			                  var cookie = window.document.cookie;
802			                  var cookieName = encodeURIComponent(storageKey);
803			                  var location = cookie.indexOf(cookieName + "=");
804			                  if (location !== -1) {
805			                      storedLevel = /^([^;]+)/.exec(
806			                          cookie.slice(location + cookieName.length + 1)
807			                      )[1];
808			                  }
809			              } catch (ignore) {}
810			          }
811
vendor: 5,319 bytes, lines 812-983
812			          // If the stored level is not valid, treat it as if nothing was stored.
813			          if (self.levels[storedLevel] === undefined) {
814			              storedLevel = undefined;
815			          }
816
817			          return storedLevel;
818			      }
819
820			      function clearPersistedLevel() {
821			          if (typeof window === undefinedType || !storageKey) return;
822
823			          // Use localStorage if available
824			          try {
825			              window.localStorage.removeItem(storageKey);
826			          } catch (ignore) {}
827
828			          // Use session cookie as fallback
829			          try {
830			              window.document.cookie =
831			                encodeURIComponent(storageKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC";
832			          } catch (ignore) {}
833			      }
834
835			      function normalizeLevel(input) {
836			          var level = input;
837			          if (typeof level === "string" && self.levels[level.toUpperCase()] !== undefined) {
838			              level = self.levels[level.toUpperCase()];
839			          }
840			          if (typeof level === "number" && level >= 0 && level <= self.levels.SILENT) {
841			              return level;
842			          } else {
843			              throw new TypeError("log.setLevel() called with invalid level: " + input);
844			          }
845			      }
846
847			      /*
848			       *
849			       * Public logger API - see https://github.com/pimterry/loglevel for details
850			       *
851			       */
852
853			      self.name = name;
854
855			      self.levels = { "TRACE": 0, "DEBUG": 1, "INFO": 2, "WARN": 3,
856			          "ERROR": 4, "SILENT": 5};
857
858			      self.methodFactory = factory || defaultMethodFactory;
859
860			      self.getLevel = function () {
861			          if (userLevel != null) {
862			            return userLevel;
863			          } else if (defaultLevel != null) {
864			            return defaultLevel;
865			          } else {
866			            return inheritedLevel;
867			          }
868			      };
869
870			      self.setLevel = function (level, persist) {
871			          userLevel = normalizeLevel(level);
872			          if (persist !== false) {  // defaults to true
873			              persistLevelIfPossible(userLevel);
874			          }
875
876			          // NOTE: in v2, this should call rebuild(), which updates children.
877			          return replaceLoggingMethods.call(self);
878			      };
879
880			      self.setDefaultLevel = function (level) {
881			          defaultLevel = normalizeLevel(level);
882			          if (!getPersistedLevel()) {
883			              self.setLevel(level, false);
884			          }
885			      };
886
887			      self.resetLevel = function () {
888			          userLevel = null;
889			          clearPersistedLevel();
890			          replaceLoggingMethods.call(self);
891			      };
892
893			      self.enableAll = function(persist) {
894			          self.setLevel(self.levels.TRACE, persist);
895			      };
896
897			      self.disableAll = function(persist) {
898			          self.setLevel(self.levels.SILENT, persist);
899			      };
900
901			      self.rebuild = function () {
902			          if (defaultLogger !== self) {
903			              inheritedLevel = normalizeLevel(defaultLogger.getLevel());
904			          }
905			          replaceLoggingMethods.call(self);
906
907			          if (defaultLogger === self) {
908			              for (var childName in _loggersByName) {
909			                _loggersByName[childName].rebuild();
910			              }
911			          }
912			      };
913
914			      // Initialize all the internal levels.
915			      inheritedLevel = normalizeLevel(
916			          defaultLogger ? defaultLogger.getLevel() : "WARN"
917			      );
918			      var initialLevel = getPersistedLevel();
919			      if (initialLevel != null) {
920			          userLevel = normalizeLevel(initialLevel);
921			      }
922			      replaceLoggingMethods.call(self);
923			    }
924
925			    /*
926			     *
927			     * Top-level API
928			     *
929			     */
930
931			    defaultLogger = new Logger();
932
933			    defaultLogger.getLogger = function getLogger(name) {
934			        if ((typeof name !== "symbol" && typeof name !== "string") || name === "") {
935			            throw new TypeError("You must supply a name when creating a logger.");
936			        }
937
938			        var logger = _loggersByName[name];
939			        if (!logger) {
940			            logger = _loggersByName[name] = new Logger(
941			                name,
942			                defaultLogger.methodFactory
943			            );
944			        }
945			        return logger;
946			    };
947
948			    // Grab the current global log variable in case of overwrite
949			    var _log = (typeof window !== undefinedType) ? window.log : undefined;
950			    defaultLogger.noConflict = function() {
951			        if (typeof window !== undefinedType &&
952			               window.log === defaultLogger) {
953			            window.log = _log;
954			        }
955
956			        return defaultLogger;
957			    };
958
959			    defaultLogger.getLoggers = function getLoggers() {
960			        return _loggersByName;
961			    };
962
963			    // ES6 default export, for compatibility
964			    defaultLogger['default'] = defaultLogger;
965
966			    return defaultLogger;
967			})); 
968		} (loglevel$3));
969		return loglevel$3.exports;
970	}
971
972	var loglevelExports = requireLoglevel();
973	var loglevel = /*@__PURE__*/getDefaultExportFromCjs(loglevelExports);
974
975	var loglevel$1 = /*#__PURE__*/_mergeNamespaces({
976		__proto__: null,
977		default: loglevel
978	}, [loglevelExports]);
979
980	/**
981	 * Base class for all possible errors that the library can receive from the
982	 * Twilio backend.
983	 */
984	class TwilioError extends Error {
985	    /**
986	     * @internal
987	     */
988	    constructor(messageOrError, error) {
989	        super();
990	        Object.setPrototypeOf(this, TwilioError.prototype);
991	        const message = typeof messageOrError === 'string'
992	            ? messageOrError
993	            : this.explanation;
994	        const originalError = typeof messageOrError === 'object'
995	            ? messageOrError
996	            : error;
997	        this.message = `${this.name} (${this.code}): ${message}`;
998	        this.originalError = originalError;
999	    }
1000	}
1001
1002	/* tslint:disable max-classes-per-file max-line-length */
1003	/**
1004	 * This is a generated file. Any modifications here will be overwritten. See scripts/errors.js.
1005	 */
1006	var AuthorizationErrors;
1007	(function (AuthorizationErrors) {
1008	    /**
1009	     * Error received from the Twilio backend.
1010	     */
1011	    class AccessTokenInvalid extends TwilioError {
1012	        /**
1013	         * @internal
1014	         */
1015	        constructor(messageOrError, error) {
1016	            super(messageOrError, error);
1017	            this.causes = [];
1018	            this.code = 20101;
1019	            this.description = 'Invalid access token';
1020	            this.explanation = 'Twilio was unable to validate your Access Token';
1021	            this.name = 'AccessTokenInvalid';
1022	            this.solutions = [];
1023	            Object.setPrototypeOf(this, AuthorizationErrors.AccessTokenInvalid.prototype);
1024	            const message = typeof messageOrError === 'string'
1025	                ? messageOrError
1026	                : this.explanation;
1027	            const originalError = typeof messageOrError === 'object'
1028	                ? messageOrError
1029	                : error;
1030	            this.message = `${this.name} (${this.code}): ${message}`;
1031	            this.originalError = originalError;
1032	        }
1033	    }
1034	    AuthorizationErrors.AccessTokenInvalid = AccessTokenInvalid;
1035	    /**
1036	     * Error received from the Twilio backend.
1037	     */
1038	    class AccessTokenExpired extends TwilioError {
1039	        /**
1040	         * @internal
1041	         */
1042	        constructor(messageOrError, error) {
1043	            super(messageOrError, error);
1044	            this.causes = [];
1045	            this.code = 20104;
1046	            this.description = 'Access token expired or expiration date invalid';
1047	            this.explanation = 'The Access Token provided to the Twilio API has expired, the expiration time specified in the token was invalid, or the expiration time specified was too far in the future';
1048	            this.name = 'AccessTokenExpired';
1049	            this.solutions = [];
1050	            Object.setPrototypeOf(this, AuthorizationErrors.AccessTokenExpired.prototype);
1051	            const message = typeof messageOrError === 'string'
1052	                ? messageOrError
1053	                : this.explanation;
1054	            const originalError = typeof messageOrError === 'object'
1055	                ? messageOrError
1056	                : error;
1057	            this.message = `${this.name} (${this.code}): ${message}`;
1058	            this.originalError = originalError;
1059	        }
1060	    }
1061	    AuthorizationErrors.AccessTokenExpired = AccessTokenExpired;
1062	    /**
1063	     * Error received from the Twilio backend.
1064	     */
1065	    class AuthenticationFailed extends TwilioError {
1066	        /**
1067	         * @internal
1068	         */
1069	        constructor(messageOrError, error) {
1070	            super(messageOrError, error);
1071	            this.causes = [];
1072	            this.code = 20151;
1073	            this.description = 'Authentication Failed';
1074	            this.explanation = 'The Authentication with the provided JWT failed';
1075	            this.name = 'AuthenticationFailed';
1076	            this.solutions = [];
1077	            Object.setPrototypeOf(this, AuthorizationErrors.AuthenticationFailed.prototype);
1078	            const message = typeof messageOrError === 'string'
1079	                ? messageOrError
1080	                : this.explanation;
1081	            const originalError = typeof messageOrError === 'object'
1082	                ? messageOrError
1083	                : error;
1084	            this.message = `${this.name} (${this.code}): ${message}`;
1085	            this.originalError = originalError;
1086	        }
1087	    }
1088	    AuthorizationErrors.AuthenticationFailed = AuthenticationFailed;
1089	})(AuthorizationErrors || (AuthorizationErrors = {}));
1090	var SignatureValidationErrors;
1091	(function (SignatureValidationErrors) {
1092	    /**
1093	     * Error received from the Twilio backend.
1094	     */
1095	    class AccessTokenSignatureValidationFailed extends TwilioError {
1096	        /**
1097	         * @internal
1098	         */
1099	        constructor(messageOrError, error) {
1100	            super(messageOrError, error);
1101	            this.causes = [
1102	                'The access token has an invalid Account SID, API Key, or API Key Secret.',
1103	            ];
1104	            this.code = 31202;
1105	            this.description = 'Signature validation failed.';
1106	            this.explanation = 'The provided access token failed signature validation.';
1107	            this.name = 'AccessTokenSignatureValidationFailed';
1108	            this.solutions = [
1109	                'Ensure the Account SID, API Key, and API Key Secret are valid when generating your access token.',
1110	            ];
1111	            Object.setPrototypeOf(this, SignatureValidationErrors.AccessTokenSignatureValidationFailed.prototype);
1112	            const message = typeof messageOrError === 'string'
1113	                ? messageOrError
1114	                : this.explanation;
1115	            const originalError = typeof messageOrError === 'object'
1116	                ? messageOrError
1117	                : error;
1118	            this.message = `${this.name} (${this.code}): ${message}`;
1119	            this.originalError = originalError;
1120	        }
1121	    }
1122	    SignatureValidationErrors.AccessTokenSignatureValidationFailed = AccessTokenSignatureValidationFailed;
1123	})(SignatureValidationErrors || (SignatureValidationErrors = {}));
1124	var ClientErrors;
1125	(function (ClientErrors) {
1126	    /**
1127	     * Error received from the Twilio backend.
1128	     */
1129	    class BadRequest extends TwilioError {
1130	        /**
1131	         * @internal
1132	         */
1133	        constructor(messageOrError, error) {
1134	            super(messageOrError, error);
1135	            this.causes = [];
1136	            this.code = 31400;
1137	            this.description = 'Bad Request (HTTP/SIP)';
1138	            this.explanation = 'The request could not be understood due to malformed syntax.';
1139	            this.name = 'BadRequest';
1140	            this.solutions = [];
1141	            Object.setPrototypeOf(this, ClientErrors.BadRequest.prototype);
1142	            const message = typeof messageOrError === 'string'
1143	                ? messageOrError
1144	                : this.explanation;
1145	            const originalError = typeof messageOrError === 'object'
1146	                ? messageOrError
1147	                : error;
1148	            this.message = `${this.name} (${this.code}): ${message}`;
1149	            this.originalError = originalError;
1150	        }
1151	    }
1152	    ClientErrors.BadRequest = BadRequest;
1153	    /**
1154	     * Error received from the Twilio backend.
1155	     */
1156	    class NotFound extends TwilioError {
1157	        /**
1158	         * @internal
1159	         */
1160	        constructor(messageOrError, error) {
1161	            super(messageOrError, error);
1162	            this.causes = [
1163	                'The outbound call was made to an invalid phone number.',
1164	                'The TwiML application sid is missing a Voice URL.',
1165	            ];
1166	            this.code = 31404;
1167	            this.description = 'Not Found (HTTP/SIP)';
1168	            this.explanation = 'The server has not found anything matching the request.';
1169	            this.name = 'NotFound';
1170	            this.solutions = [
1171	                'Ensure the phone number dialed is valid.',
1172	                'Ensure the TwiML application is configured correctly with a Voice URL link.',
1173	            ];
1174	            Object.setPrototypeOf(this, ClientErrors.NotFound.prototype);
1175	            const message = typeof messageOrError === 'string'
1176	                ? messageOrError
1177	                : this.explanation;
1178	            const originalError = typeof messageOrError === 'object'
1179	                ? messageOrError
1180	                : error;
1181	            this.message = `${this.name} (${this.code}): ${message}`;
1182	            this.originalError = originalError;
1183	        }
1184	    }
1185	    ClientErrors.NotFound = NotFound;
1186	    /**
1187	     * Error received from the Twilio backend.
1188	     */
1189	    class TemporarilyUnavailable extends TwilioError {
1190	        /**
1191	         * @internal
1192	         */
1193	        constructor(messageOrError, error) {
1194	            super(messageOrError, error);
1195	            this.causes = [];
1196	            this.code = 31480;
1197	            this.description = 'Temporarily Unavailable (SIP)';
1198	            this.explanation = 'The callee is currently unavailable.';
1199	            this.name = 'TemporarilyUnavailable';
1200	            this.solutions = [];
1201	            Object.setPrototypeOf(this, ClientErrors.TemporarilyUnavailable.prototype);
1202	            const message = typeof messageOrError === 'string'
1203	                ? messageOrError
1204	                : this.explanation;
1205	            const originalError = typeof messageOrError === 'object'
1206	                ? messageOrError
1207	                : error;
1208	            this.message = `${this.name} (${this.code}): ${message}`;
1209	            this.originalError = originalError;
1210	        }
1211	    }
1212	    ClientErrors.TemporarilyUnavailable = TemporarilyUnavailable;
1213	    /**
1214	     * Error received from the Twilio backend.
1215	     */
1216	    class BusyHere extends TwilioError {
1217	        /**
1218	         * @internal
1219	         */
1220	        constructor(messageOrError, error) {
1221	            super(messageOrError, error);
1222	            this.causes = [];
1223	            this.code = 31486;
1224	            this.description = 'Busy Here (SIP)';
1225	            this.explanation = 'The callee is busy.';
1226	            this.name = 'BusyHere';
1227	            this.solutions = [];
1228	            Object.setPrototypeOf(this, ClientErrors.BusyHere.prototype);
1229	            const message = typeof messageOrError === 'string'
1230	                ? messageOrError
1231	                : this.explanation;
1232	            const originalError = typeof messageOrError === 'object'
1233	                ? messageOrError
1234	                : error;
1235	            this.message = `${this.name} (${this.code}): ${message}`;
1236	            this.originalError = originalError;
1237	        }
1238	    }
1239	    ClientErrors.BusyHere = BusyHere;
1240	})(ClientErrors || (ClientErrors = {}));
1241	var SIPServerErrors;
1242	(function (SIPServerErrors) {
1243	    /**
1244	     * Error received from the Twilio backend.
1245	     */
1246	    class Decline extends TwilioError {
1247	        /**
1248	         * @internal
1249	         */
1250	        constructor(messageOrError, error) {
1251	            super(messageOrError, error);
1252	            this.causes = [];
1253	            this.code = 31603;
1254	            this.description = 'Decline (SIP)';
1255	            this.explanation = 'The callee does not wish to participate in the call.';
1256	            this.name = 'Decline';
1257	            this.solutions = [];
1258	            Object.setPrototypeOf(this, SIPServerErrors.Decline.prototype);
1259	            const message = typeof messageOrError === 'string'
1260	                ? messageOrError
1261	                : this.explanation;
1262	            const originalError = typeof messageOrError === 'object'
1263	                ? messageOrError
1264	                : error;
1265	            this.message = `${this.name} (${this.code}): ${message}`;
1266	            this.originalError = originalError;
1267	        }
1268	    }
1269	    SIPServerErrors.Decline = Decline;
1270	})(SIPServerErrors || (SIPServerErrors = {}));
1271	var GeneralErrors;
1272	(function (GeneralErrors) {
1273	    /**
1274	     * Error received from the Twilio backend.
1275	     */
1276	    class UnknownError extends TwilioError {
1277	        /**
1278	         * @internal
1279	         */
1280	        constructor(messageOrError, error) {
1281	            super(messageOrError, error);
1282	            this.causes = [];
1283	            this.code = 31000;
1284	            this.description = 'Unknown Error';
1285	            this.explanation = 'An unknown error has occurred. See error details for more information.';
1286	            this.name = 'UnknownError';
1287	            this.solutions = [];
1288	            Object.setPrototypeOf(this, GeneralErrors.UnknownError.prototype);
1289	            const message = typeof messageOrError === 'string'
1290	                ? messageOrError
1291	                : this.explanation;
1292	            const originalError = typeof messageOrError === 'object'
1293	                ? messageOrError
1294	                : error;
1295	            this.message = `${this.name} (${this.code}): ${message}`;
1296	            this.originalError = originalError;
1297	        }
1298	    }
1299	    GeneralErrors.UnknownError = UnknownError;
1300	    /**
1301	     * Error received from the Twilio backend.
1302	     */
1303	    class ApplicationNotFoundError extends TwilioError {
1304	        /**
1305	         * @internal
1306	         */
1307	        constructor(messageOrError, error) {
1308	            super(messageOrError, error);
1309	            this.causes = [];
1310	            this.code = 31001;
1311	            this.description = 'Application Not Found';
1312	            this.explanation = '';
1313	            this.name = 'ApplicationNotFoundError';
1314	            this.solutions = [];
1315	            Object.setPrototypeOf(this, GeneralErrors.ApplicationNotFoundError.prototype);
1316	            const message = typeof messageOrError === 'string'
1317	                ? messageOrError
1318	                : this.explanation;
1319	            const originalError = typeof messageOrError === 'object'
1320	                ? messageOrError
1321	                : error;
1322	            this.message = `${this.name} (${this.code}): ${message}`;
1323	            this.originalError = originalError;
1324	        }
1325	    }
1326	    GeneralErrors.ApplicationNotFoundError = ApplicationNotFoundError;
1327	    /**
1328	     * Error received from the Twilio backend.
1329	     */
1330	    class ConnectionDeclinedError extends TwilioError {
1331	        /**
1332	         * @internal
1333	         */
1334	        constructor(messageOrError, error) {
1335	            super(messageOrError, error);
1336	            this.causes = [];
1337	            this.code = 31002;
1338	            this.description = 'Connection Declined';
1339	            this.explanation = '';
1340	            this.name = 'ConnectionDeclinedError';
1341	            this.solutions = [];
1342	            Object.setPrototypeOf(this, GeneralErrors.ConnectionDeclinedError.prototype);
1343	            const message = typeof messageOrError === 'string'
1344	                ? messageOrError
1345	                : this.explanation;
1346	            const originalError = typeof messageOrError === 'object'
1347	                ? messageOrError
1348	                : error;
1349	            this.message = `${this.name} (${this.code}): ${message}`;
1350	            this.originalError = originalError;
1351	        }
1352	    }
1353	    GeneralErrors.ConnectionDeclinedError = ConnectionDeclinedError;
1354	    /**
1355	     * Error received from the Twilio backend.
1356	     */
1357	    class ConnectionTimeoutError extends TwilioError {
1358	        /**
1359	         * @internal
1360	         */
1361	        constructor(messageOrError, error) {
1362	            super(messageOrError, error);
1363	            this.causes = [];
1364	            this.code = 31003;
1365	            this.description = 'Connection Timeout';
1366	            this.explanation = 'The server could not produce a response within a suitable amount of time.';
1367	            this.name = 'ConnectionTimeoutError';
1368	            this.solutions = [];
1369	            Object.setPrototypeOf(this, GeneralErrors.ConnectionTimeoutError.prototype);
1370	            const message = typeof messageOrError === 'string'
1371	                ? messageOrError
1372	                : this.explanation;
1373	            const originalError = typeof messageOrError === 'object'
1374	                ? messageOrError
1375	                : error;
1376	            this.message = `${this.name} (${this.code}): ${message}`;
1377	            this.originalError = originalError;
1378	        }
1379	    }
1380	    GeneralErrors.ConnectionTimeoutError = ConnectionTimeoutError;
1381	    /**
1382	     * Error received from the Twilio backend.
1383	     */
1384	    class ConnectionError extends TwilioError {
1385	        /**
1386	         * @internal
1387	         */
1388	        constructor(messageOrError, error) {
1389	            super(messageOrError, error);
1390	            this.causes = [];
1391	            this.code = 31005;
1392	            this.description = 'Connection error';
1393	            this.explanation = 'A connection error occurred during the call';
1394	            this.name = 'ConnectionError';
1395	            this.solutions = [];
1396	            Object.setPrototypeOf(this, GeneralErrors.ConnectionError.prototype);
1397	            const message = typeof messageOrError === 'string'
1398	                ? messageOrError
1399	                : this.explanation;
1400	            const originalError = typeof messageOrError === 'object'
1401	                ? messageOrError
1402	                : error;
1403	            this.message = `${this.name} (${this.code}): ${message}`;
1404	            this.originalError = originalError;
1405	        }
1406	    }
1407	    GeneralErrors.ConnectionError = ConnectionError;
1408	    /**
1409	     * Error received from the Twilio backend.
1410	     */
1411	    class CallCancelledError extends TwilioError {
1412	        /**
1413	         * @internal
1414	         */
1415	        constructor(messageOrError, error) {
1416	            super(messageOrError, error);
1417	            this.causes = [
1418	                'The incoming call was cancelled because it was not answered in time or it was accepted/rejected by another application instance registered with the same identity.',
1419	            ];
1420	            this.code = 31008;
1421	            this.description = 'Call cancelled';
1422	            this.explanation = 'Unable to answer because the call has ended';
1423	            this.name = 'CallCancelledError';
1424	            this.solutions = [];
1425	            Object.setPrototypeOf(this, GeneralErrors.CallCancelledError.prototype);
1426	            const message = typeof messageOrError === 'string'
1427	                ? messageOrError
1428	                : this.explanation;
1429	            const originalError = typeof messageOrError === 'object'
1430	                ? messageOrError
1431	                : error;
1432	            this.message = `${this.name} (${this.code}): ${message}`;
1433	            this.originalError = originalError;
1434	        }
1435	    }
1436	    GeneralErrors.CallCancelledError = CallCancelledError;
1437	    /**
1438	     * Error received from the Twilio backend.
1439	     */
1440	    class TransportError extends TwilioError {
1441	        /**
1442	         * @internal
1443	         */
1444	        constructor(messageOrError, error) {
1445	            super(messageOrError, error);
1446	            this.causes = [];
1447	            this.code = 31009;
1448	            this.description = 'Transport error';
1449	            this.explanation = 'No transport available to send or receive messages';
1450	            this.name = 'TransportError';
1451	            this.solutions = [];
1452	            Object.setPrototypeOf(this, GeneralErrors.TransportError.prototype);
1453	            const message = typeof messageOrError === 'string'
1454	                ? messageOrError
1455	                : this.explanation;
1456	            const originalError = typeof messageOrError === 'object'
1457	                ? messageOrError
1458	                : error;
1459	            this.message = `${this.name} (${this.code}): ${message}`;
1460	            this.originalError = originalError;
1461	        }
1462	    }
1463	    GeneralErrors.TransportError = TransportError;
1464	})(GeneralErrors || (GeneralErrors = {}));
1465	var MalformedRequestErrors;
1466	(function (MalformedRequestErrors) {
1467	    /**
1468	     * Error received from the Twilio backend.
1469	     */
1470	    class MalformedRequestError extends TwilioError {
1471	        /**
1472	         * @internal
1473	         */
1474	        constructor(messageOrError, error) {
1475	            super(messageOrError, error);
1476	            this.causes = [
1477	                'Invalid content or MessageType passed to sendMessage method.',
1478	            ];
1479	            this.code = 31100;
1480	            this.description = 'The request had malformed syntax.';
1481	            this.explanation = 'The request could not be understood due to malformed syntax.';
1482	            this.name = 'MalformedRequestError';
1483	            this.solutions = [
1484	                'Ensure content and MessageType passed to sendMessage method are valid.',
1485	            ];
1486	            Object.setPrototypeOf(this, MalformedRequestErrors.MalformedRequestError.prototype);
1487	            const message = typeof messageOrError === 'string'
1488	                ? messageOrError
1489	                : this.explanation;
1490	            const originalError = typeof messageOrError === 'object'
1491	                ? messageOrError
1492	                : error;
1493	            this.message = `${this.name} (${this.code}): ${message}`;
1494	            this.originalError = originalError;
1495	        }
1496	    }
1497	    MalformedRequestErrors.MalformedRequestError = MalformedRequestError;
1498	    /**
1499	     * Error received from the Twilio backend.
1500	     */
1501	    class MissingParameterArrayError extends TwilioError {
1502	        /**
1503	         * @internal
1504	         */
1505	        constructor(messageOrError, error) {
1506	            super(messageOrError, error);
1507	            this.causes = [];
1508	            this.code = 31101;
1509	            this.description = 'Missing parameter array in request';
1510	            this.explanation = '';
1511	            this.name = 'MissingParameterArrayError';
1512	            this.solutions = [];
1513	            Object.setPrototypeOf(this, MalformedRequestErrors.MissingParameterArrayError.prototype);
1514	            const message = typeof messageOrError === 'string'
1515	                ? messageOrError
1516	                : this.explanation;
1517	            const originalError = typeof messageOrError === 'object'
1518	                ? messageOrError
1519	                : error;
1520	            this.message = `${this.name} (${this.code}): ${message}`;
1521	            this.originalError = originalError;
1522	        }
1523	    }
1524	    MalformedRequestErrors.MissingParameterArrayError = MissingParameterArrayError;
1525	    /**
1526	     * Error received from the Twilio backend.
1527	     */
1528	    class AuthorizationTokenMissingError extends TwilioError {
1529	        /**
1530	         * @internal
1531	         */
1532	        constructor(messageOrError, error) {
1533	            super(messageOrError, error);
1534	            this.causes = [];
1535	            this.code = 31102;
1536	            this.description = 'Authorization token missing in request.';
1537	            this.explanation = '';
1538	            this.name = 'AuthorizationTokenMissingError';
1539	            this.solutions = [];
1540	            Object.setPrototypeOf(this, MalformedRequestErrors.AuthorizationTokenMissingError.prototype);
1541	            const message = typeof messageOrError === 'string'
1542	                ? messageOrError
1543	                : this.explanation;
1544	            const originalError = typeof messageOrError === 'object'
1545	                ? messageOrError
1546	                : error;
1547	            this.message = `${this.name} (${this.code}): ${message}`;
1548	            this.originalError = originalError;
1549	        }
1550	    }
1551	    MalformedRequestErrors.AuthorizationTokenMissingError = AuthorizationTokenMissingError;
1552	    /**
1553	     * Error received from the Twilio backend.
1554	     */
1555	    class MaxParameterLengthExceededError extends TwilioError {
1556	        /**
1557	         * @internal
1558	         */
1559	        constructor(messageOrError, error) {
1560	            super(messageOrError, error);
1561	            this.causes = [];
1562	            this.code = 31103;
1563	            this.description = 'Maximum parameter length has been exceeded.';
1564	            this.explanation = 'Length of parameters cannot exceed MAX_PARAM_LENGTH.';
1565	            this.name = 'MaxParameterLengthExceededError';
1566	            this.solutions = [];
1567	            Object.setPrototypeOf(this, MalformedRequestErrors.MaxParameterLengthExceededError.prototype);
1568	            const message = typeof messageOrError === 'string'
1569	                ? messageOrError
1570	                : this.explanation;
1571	            const originalError = typeof messageOrError === 'object'
1572	                ? messageOrError
1573	                : error;
1574	            this.message = `${this.name} (${this.code}): ${message}`;
1575	            this.originalError = originalError;
1576	        }
1577	    }
1578	    MalformedRequestErrors.MaxParameterLengthExceededError = MaxParameterLengthExceededError;
1579	    /**
1580	     * Error received from the Twilio backend.
1581	     */
1582	    class InvalidBridgeTokenError extends TwilioError {
1583	        /**
1584	         * @internal
1585	         */
1586	        constructor(messageOrError, error) {
1587	            super(messageOrError, error);
1588	            this.causes = [];
1589	            this.code = 31104;
1590	            this.description = 'Invalid bridge token';
1591	            this.explanation = '';
1592	            this.name = 'InvalidBridgeTokenError';
1593	            this.solutions = [];
1594	            Object.setPrototypeOf(this, MalformedRequestErrors.InvalidBridgeTokenError.prototype);
1595	            const message = typeof messageOrError === 'string'
1596	                ? messageOrError
1597	                : this.explanation;
1598	            const originalError = typeof messageOrError === 'object'
1599	                ? messageOrError
1600	                : error;
1601	            this.message = `${this.name} (${this.code}): ${message}`;
1602	            this.originalError = originalError;
1603	        }
1604	    }
1605	    MalformedRequestErrors.InvalidBridgeTokenError = InvalidBridgeTokenError;
1606	    /**
1607	     * Error received from the Twilio backend.
1608	     */
1609	    class InvalidClientNameError extends TwilioError {
1610	        /**
1611	         * @internal
1612	         */
1613	        constructor(messageOrError, error) {
1614	            super(messageOrError, error);
1615	            this.causes = [
1616	                'Client name contains invalid characters.',
1617	            ];
1618	            this.code = 31105;
1619	            this.description = 'Invalid client name';
1620	            this.explanation = 'Client name should not contain control, space, delims, or unwise characters.';
1621	            this.name = 'InvalidClientNameError';
1622	            this.solutions = [
1623	                'Make sure that client name does not contain any of the invalid characters.',
1624	            ];
1625	            Object.setPrototypeOf(this, MalformedRequestErrors.InvalidClientNameError.prototype);
1626	            const message = typeof messageOrError === 'string'
1627	                ? messageOrError
1628	                : this.explanation;
1629	            const originalError = typeof messageOrError === 'object'
1630	                ? messageOrError
1631	                : error;
1632	            this.message = `${this.name} (${this.code}): ${message}`;
1633	            this.originalError = originalError;
1634	        }
1635	    }
1636	    MalformedRequestErrors.InvalidClientNameError = InvalidClientNameError;
1637	    /**
1638	     * Error received from the Twilio backend.
1639	     */
1640	    class ReconnectParameterInvalidError extends TwilioError {
1641	        /**
1642	         * @internal
1643	         */
1644	        constructor(messageOrError, error) {
1645	            super(messageOrError, error);
1646	            this.causes = [];
1647	            this.code = 31107;
1648	            this.description = 'The reconnect parameter is invalid';
1649	            this.explanation = '';
1650	            this.name = 'ReconnectParameterInvalidError';
1651	            this.solutions = [];
1652	            Object.setPrototypeOf(this, MalformedRequestErrors.ReconnectParameterInvalidError.prototype);
1653	            const message = typeof messageOrError === 'string'
1654	                ? messageOrError
1655	                : this.explanation;
1656	            const originalError = typeof messageOrError === 'object'
1657	                ? messageOrError
1658	                : error;
1659	            this.message = `${this.name} (${this.code}): ${message}`;
1660	            this.originalError = originalError;
1661	        }
1662	    }
1663	    MalformedRequestErrors.ReconnectParameterInvalidError = ReconnectParameterInvalidError;
1664	})(MalformedRequestErrors || (MalformedRequestErrors = {}));
1665	(function (AuthorizationErrors) {
1666	    /**
1667	     * Error received from the Twilio backend.
1668	     */
1669	    class AuthorizationError extends TwilioError {
1670	        /**
1671	         * @internal
1672	         */
1673	        constructor(messageOrError, error) {
1674	            super(messageOrError, error);
1675	            this.causes = [];
1676	            this.code = 31201;
1677	            this.description = 'Authorization error';
1678	            this.explanation = 'The request requires user authentication. The server understood the request, but is refusing to fulfill it.';
1679	            this.name = 'AuthorizationError';
1680	            this.solutions = [];
1681	            Object.setPrototypeOf(this, AuthorizationErrors.AuthorizationError.prototype);
1682	            const message = typeof messageOrError === 'string'
1683	                ? messageOrError
1684	                : this.explanation;
1685	            const originalError = typeof messageOrError === 'object'
1686	                ? messageOrError
1687	                : error;
1688	            this.message = `${this.name} (${this.code}): ${message}`;
1689	            this.originalError = originalError;
1690	        }
1691	    }
1692	    AuthorizationErrors.AuthorizationError = AuthorizationError;
1693	    /**
1694	     * Error received from the Twilio backend.
1695	     */
1696	    class NoValidAccountError extends TwilioError {
1697	        /**
1698	         * @internal
1699	         */
1700	        constructor(messageOrError, error) {
1701	            super(messageOrError, error);
1702	            this.causes = [];
1703	            this.code = 31203;
1704	            this.description = 'No valid account';
1705	            this.explanation = '';
1706	            this.name = 'NoValidAccountError';
1707	            this.solutions = [];
1708	            Object.setPrototypeOf(this, AuthorizationErrors.NoValidAccountError.prototype);
1709	            const message = typeof messageOrError === 'string'
1710	                ? messageOrError
1711	                : this.explanation;
1712	            const originalError = typeof messageOrError === 'object'
1713	                ? messageOrError
1714	                : error;
1715	            this.message = `${this.name} (${this.code}): ${message}`;
1716	            this.originalError = originalError;
1717	        }
1718	    }
1719	    AuthorizationErrors.NoValidAccountError = NoValidAccountError;
1720	    /**
1721	     * Error received from the Twilio backend.
1722	     */
1723	    class InvalidJWTTokenError extends TwilioError {
1724	        /**
1725	         * @internal
1726	         */
1727	        constructor(messageOrError, error) {
1728	            super(messageOrError, error);
1729	            this.causes = [];
1730	            this.code = 31204;
1731	            this.description = 'Invalid JWT token';
1732	            this.explanation = '';
1733	            this.name = 'InvalidJWTTokenError';
1734	            this.solutions = [];
1735	            Object.setPrototypeOf(this, AuthorizationErrors.InvalidJWTTokenError.prototype);
1736	            const message = typeof messageOrError === 'string'
1737	                ? messageOrError
1738	                : this.explanation;
1739	            const originalError = typeof messageOrError === 'object'
1740	                ? messageOrError
1741	                : error;
1742	            this.message = `${this.name} (${this.code}): ${message}`;
1743	            this.originalError = originalError;
1744	        }
1745	    }
1746	    AuthorizationErrors.InvalidJWTTokenError = InvalidJWTTokenError;
1747	    /**
1748	     * Error received from the Twilio backend.
1749	     */
1750	    class JWTTokenExpiredError extends TwilioError {
1751	        /**
1752	         * @internal
1753	         */
1754	        constructor(messageOrError, error) {
1755	            super(messageOrError, error);
1756	            this.causes = [];
1757	            this.code = 31205;
1758	            this.description = 'JWT token expired';
1759	            this.explanation = '';
1760	            this.name = 'JWTTokenExpiredError';
1761	            this.solutions = [];
1762	            Object.setPrototypeOf(this, AuthorizationErrors.JWTTokenExpiredError.prototype);
1763	            const message = typeof messageOrError === 'string'
1764	                ? messageOrError
1765	                : this.explanation;
1766	            const originalError = typeof messageOrError === 'object'
1767	                ? messageOrError
1768	                : error;
1769	            this.message = `${this.name} (${this.code}): ${message}`;
1770	            this.originalError = originalError;
1771	        }
1772	    }
1773	    AuthorizationErrors.JWTTokenExpiredError = JWTTokenExpiredError;
1774	    /**
1775	     * Error received from the Twilio backend.
1776	     */
1777	    class RateExceededError extends TwilioError {
1778	        /**
1779	         * @internal
1780	         */
1781	        constructor(messageOrError, error) {
1782	            super(messageOrError, error);
1783	            this.causes = [
1784	                'Rate limit exceeded.',
1785	            ];
1786	            this.code = 31206;
1787	            this.description = 'Rate exceeded authorized limit.';
1788	            this.explanation = 'The request performed exceeds the authorized limit.';
1789	            this.name = 'RateExceededError';
1790	            this.solutions = [
1791	                'Ensure message send rate does not exceed authorized limits.',
1792	            ];
1793	            Object.setPrototypeOf(this, AuthorizationErrors.RateExceededError.prototype);
1794	            const message = typeof messageOrError === 'string'
1795	                ? messageOrError
1796	                : this.explanation;
1797	            const originalError = typeof messageOrError === 'object'
1798	                ? messageOrError
1799	                : error;
1800	            this.message = `${this.name} (${this.code}): ${message}`;
1801	            this.originalError = originalError;
1802	        }
1803	    }
1804	    AuthorizationErrors.RateExceededError = RateExceededError;
1805	    /**
1806	     * Error received from the Twilio backend.
1807	     */
1808	    class JWTTokenExpirationTooLongError extends TwilioError {
1809	        /**
1810	         * @internal
1811	         */
1812	        constructor(messageOrError, error) {
1813	            super(messageOrError, error);
1814	            this.causes = [];
1815	            this.code = 31207;
1816	            this.description = 'JWT token expiration too long';
1817	            this.explanation = '';
1818	            this.name = 'JWTTokenExpirationTooLongError';
1819	            this.solutions = [];
1820	            Object.setPrototypeOf(this, AuthorizationErrors.JWTTokenExpirationTooLongError.prototype);
1821	            const message = typeof messageOrError === 'string'
1822	                ? messageOrError
1823	                : this.explanation;
1824	            const originalError = typeof messageOrError === 'object'
1825	                ? messageOrError
1826	                : error;
1827	            this.message = `${this.name} (${this.code}): ${message}`;
1828	            this.originalError = originalError;
1829	        }
1830	    }
1831	    AuthorizationErrors.JWTTokenExpirationTooLongError = JWTTokenExpirationTooLongError;
1832	    /**
1833	     * Error received from the Twilio backend.
1834	     */
1835	    class ReconnectAttemptError extends TwilioError {
1836	        /**
1837	         * @internal
1838	         */
1839	        constructor(messageOrError, error) {
1840	            super(messageOrError, error);
1841	            this.causes = [];
1842	            this.code = 31209;
1843	            this.description = 'Reconnect attempt is not authorized.';
1844	            this.explanation = '';
1845	            this.name = 'ReconnectAttemptError';
1846	            this.solutions = [];
1847	            Object.setPrototypeOf(this, AuthorizationErrors.ReconnectAttemptError.prototype);
1848	            const message = typeof messageOrError === 'string'
1849	                ? messageOrError
1850	                : this.explanation;
1851	            const originalError = typeof messageOrError === 'object'
1852	                ? messageOrError
1853	                : error;
1854	            this.message = `${this.name} (${this.code}): ${message}`;
1855	            this.originalError = originalError;
1856	        }
1857	    }
1858	    AuthorizationErrors.ReconnectAttemptError = ReconnectAttemptError;
1859	    /**
1860	     * Error received from the Twilio backend.
1861	     */
1862	    class CallMessageEventTypeInvalidError extends TwilioError {
1863	        /**
1864	         * @internal
1865	         */
1866	        constructor(messageOrError, error) {
1867	            super(messageOrError, error);
1868	            this.causes = [
1869	                'The Call Message Event Type is invalid and is not understood by Twilio Voice.',
1870	            ];
1871	            this.code = 31210;
1872	            this.description = 'Call Message Event Type is invalid.';
1873	            this.explanation = 'The Call Message Event Type is invalid and is not understood by Twilio Voice.';
1874	            this.name = 'CallMessageEventTypeInvalidError';
1875	            this.solutions = [
1876	                'Ensure the Call Message Event Type is Valid and understood by Twilio Voice and try again.',
1877	            ];
1878	            Object.setPrototypeOf(this, AuthorizationErrors.CallMessageEventTypeInvalidError.prototype);
1879	            const message = typeof messageOrError === 'string'
1880	                ? messageOrError
1881	                : this.explanation;
1882	            const originalError = typeof messageOrError === 'object'
1883	                ? messageOrError
1884	                : error;
1885	            this.message = `${this.name} (${this.code}): ${message}`;
1886	            this.originalError = originalError;
1887	        }
1888	    }
1889	    AuthorizationErrors.CallMessageEventTypeInvalidError = CallMessageEventTypeInvalidError;
1890	    /**
1891	     * Error received from the Twilio backend.
1892	     */
1893	    class PayloadSizeExceededError extends TwilioError {
1894	        /**
1895	         * @internal
1896	         */
1897	        constructor(messageOrError, error) {
1898	            super(messageOrError, error);
1899	            this.causes = [
1900	                'The payload size of Call Message Event exceeds the authorized limit.',
1901	            ];
1902	            this.code = 31212;
1903	            this.description = 'Call Message Event Payload size exceeded authorized limit.';
1904	            this.explanation = 'The request performed to send a Call Message Event exceeds the payload size authorized limit';
1905	            this.name = 'PayloadSizeExceededError';
1906	            this.solutions = [
1907	                'Reduce payload size of Call Message Event to be within the authorized limit and try again.',
1908	            ];
1909	            Object.setPrototypeOf(this, AuthorizationErrors.PayloadSizeExceededError.prototype);
1910	            const message = typeof messageOrError === 'string'
1911	                ? messageOrError
1912	                : this.explanation;
1913	            const originalError = typeof messageOrError === 'object'
1914	                ? messageOrError
1915	                : error;
1916	            this.message = `${this.name} (${this.code}): ${message}`;
1917	            this.originalError = originalError;
1918	        }
1919	    }
1920	    AuthorizationErrors.PayloadSizeExceededError = PayloadSizeExceededError;
1921	})(AuthorizationErrors || (AuthorizationErrors = {}));
1922	var UserMediaErrors;
1923	(function (UserMediaErrors) {
1924	    /**
1925	     * Error received from the Twilio backend.
1926	     */
1927	    class PermissionDeniedError extends TwilioError {
1928	        /**
1929	         * @internal
1930	         */
1931	        constructor(messageOrError, error) {
1932	            super(messageOrError, error);
1933	            this.causes = [
1934	                'The user denied the getUserMedia request.',
1935	                'The browser denied the getUserMedia request.',
1936	            ];
1937	            this.code = 31401;
1938	            this.description = 'UserMedia Permission Denied Error';
1939	            this.explanation = 'The browser or end-user denied permissions to user media. Therefore we were unable to acquire input audio.';
1940	            this.name = 'PermissionDeniedError';
1941	            this.solutions = [
1942	                'The user should accept the request next time prompted. If the browser saved the deny, the user should change that permission in their browser.',
1943	                'The user should to verify that the browser has permission to access the microphone at this address.',
1944	            ];
1945	            Object.setPrototypeOf(this, UserMediaErrors.PermissionDeniedError.prototype);
1946	            const message = typeof messageOrError === 'string'
1947	                ? messageOrError
1948	                : this.explanation;
1949	            const originalError = typeof messageOrError === 'object'
1950	                ? messageOrError
1951	                : error;
1952	            this.message = `${this.name} (${this.code}): ${message}`;
1953	            this.originalError = originalError;
1954	        }
1955	    }
1956	    UserMediaErrors.PermissionDeniedError = PermissionDeniedError;
1957	    /**
1958	     * Error received from the Twilio backend.
1959	     */
1960	    class AcquisitionFailedError extends TwilioError {
1961	        /**
1962	         * @internal
1963	         */
1964	        constructor(messageOrError, error) {
1965	            super(messageOrError, error);
1966	            this.causes = [
1967	                'NotFoundError - The deviceID specified was not found.',
1968	                'The getUserMedia constraints were overconstrained and no devices matched.',
1969	            ];
1970	            this.code = 31402;
1971	            this.description = 'UserMedia Acquisition Failed Error';
1972	            this.explanation = 'The browser and end-user allowed permissions, however getting the media failed. Usually this is due to bad constraints, but can sometimes fail due to browser, OS or hardware issues.';
1973	            this.name = 'AcquisitionFailedError';
1974	            this.solutions = [
1975	                'Ensure the deviceID being specified exists.',
1976	                'Try acquiring media with fewer constraints.',
1977	            ];
1978	            Object.setPrototypeOf(this, UserMediaErrors.AcquisitionFailedError.prototype);
1979	            const message = typeof messageOrError === 'string'
1980	                ? messageOrError
1981	                : this.explanation;
1982	            const originalError = typeof messageOrError === 'object'
1983	                ? messageOrError
1984	                : error;
1985	            this.message = `${this.name} (${this.code}): ${message}`;
1986	            this.originalError = originalError;
1987	        }
1988	    }
1989	    UserMediaErrors.AcquisitionFailedError = AcquisitionFailedError;
1990	})(UserMediaErrors || (UserMediaErrors = {}));
1991	var SignalingErrors;
1992	(function (SignalingErrors) {
1993	    /**
1994	     * Error received from the Twilio backend.
1995	     */
1996	    class ConnectionError extends TwilioError {
1997	        /**
1998	         * @internal
1999	         */
2000	        constructor(messageOrError, error) {
2001	            super(messageOrError, error);
2002	            this.causes = [];
2003	            this.code = 53000;
2004	            this.description = 'Signaling connection error';
2005	            this.explanation = 'Raised whenever a signaling connection error occurs that is not covered by a more specific error code.';
2006	            this.name = 'ConnectionError';
2007	            this.solutions = [];
2008	            Object.setPrototypeOf(this, SignalingErrors.ConnectionError.prototype);
2009	            const message = typeof messageOrError === 'string'
2010	                ? messageOrError
2011	                : this.explanation;
2012	            const originalError = typeof messageOrError === 'object'
2013	                ? messageOrError
2014	                : error;
2015	            this.message = `${this.name} (${this.code}): ${message}`;
2016	            this.originalError = originalError;
2017	        }
2018	    }
2019	    SignalingErrors.ConnectionError = ConnectionError;
2020	    /**
2021	     * Error received from the Twilio backend.
2022	     */
2023	    class ConnectionDisconnected extends TwilioError {
2024	        /**
2025	         * @internal
2026	         */
2027	        constructor(messageOrError, error) {
2028	            super(messageOrError, error);
2029	            this.causes = [
2030	                'The device running your application lost its Internet connection.',
2031	            ];
2032	            this.code = 53001;
2033	            this.description = 'Signaling connection disconnected';
2034	            this.explanation = 'Raised whenever the signaling connection is unexpectedly disconnected.';
2035	            this.name = 'ConnectionDisconnected';
2036	            this.solutions = [
2037	                'Ensure the device running your application has access to a stable Internet connection.',
2038	            ];
2039	            Object.setPrototypeOf(this, SignalingErrors.ConnectionDisconnected.prototype);
2040	            const message = typeof messageOrError === 'string'
2041	                ? messageOrError
2042	                : this.explanation;
2043	            const originalError = typeof messageOrError === 'object'
2044	                ? messageOrError
2045	                : error;
2046	            this.message = `${this.name} (${this.code}): ${message}`;
2047	            this.originalError = originalError;
2048	        }
2049	    }
2050	    SignalingErrors.ConnectionDisconnected = ConnectionDisconnected;
2051	})(SignalingErrors || (SignalingErrors = {}));
2052	var MediaErrors;
2053	(function (MediaErrors) {
2054	    /**
2055	     * Error received from the Twilio backend.
2056	     */
2057	    class ClientLocalDescFailed extends TwilioError {
2058	        /**
2059	         * @internal
2060	         */
2061	        constructor(messageOrError, error) {
2062	            super(messageOrError, error);
2063	            this.causes = [
2064	                'The Client may not be using a supported WebRTC implementation.',
2065	                'The Client may not have the necessary resources to create or apply a new media description.',
2066	            ];
2067	            this.code = 53400;
2068	            this.description = 'Client is unable to create or apply a local media description';
2069	            this.explanation = 'Raised whenever a Client is unable to create or apply a local media description.';
2070	            this.name = 'ClientLocalDescFailed';
2071	            this.solutions = [
2072	                'If you are experiencing this error using the JavaScript SDK, ensure you are running it with a supported WebRTC implementation.',
2073	            ];
2074	            Object.setPrototypeOf(this, MediaErrors.ClientLocalDescFailed.prototype);
2075	            const message = typeof messageOrError === 'string'
2076	                ? messageOrError
2077	                : this.explanation;
2078	            const originalError = typeof messageOrError === 'object'
2079	                ? messageOrError
2080	                : error;
2081	            this.message = `${this.name} (${this.code}): ${message}`;
2082	            this.originalError = originalError;
2083	        }
2084	    }
2085	    MediaErrors.ClientLocalDescFailed = ClientLocalDescFailed;
2086	    /**
2087	     * Error received from the Twilio backend.
2088	     */
2089	    class ClientRemoteDescFailed extends TwilioError {
2090	        /**
2091	         * @internal
2092	         */
2093	        constructor(messageOrError, error) {
2094	            super(messageOrError, error);
2095	            this.causes = [
2096	                'The Client may not be using a supported WebRTC implementation.',
2097	                'The Client may be connecting peer-to-peer with another Participant that is not using a supported WebRTC implementation.',
2098	                'The Client may not have the necessary resources to apply a new media description.',
2099	            ];
2100	            this.code = 53402;
2101	            this.description = 'Client is unable to apply a remote media description';
2102	            this.explanation = 'Raised whenever the Client receives a remote media description but is unable to apply it.';
2103	            this.name = 'ClientRemoteDescFailed';
2104	            this.solutions = [
2105	                'If you are experiencing this error using the JavaScript SDK, ensure you are running it with a supported WebRTC implementation.',
2106	            ];
2107	            Object.setPrototypeOf(this, MediaErrors.ClientRemoteDescFailed.prototype);
2108	            const message = typeof messageOrError === 'string'
2109	                ? messageOrError
2110	                : this.explanation;
2111	            const originalError = typeof messageOrError === 'object'
2112	                ? messageOrError
2113	                : error;
2114	            this.message = `${this.name} (${this.code}): ${message}`;
2115	            this.originalError = originalError;
2116	        }
2117	    }
2118	    MediaErrors.ClientRemoteDescFailed = ClientRemoteDescFailed;
2119	    /**
2120	     * Error received from the Twilio backend.
2121	     */
2122	    class ConnectionError extends TwilioError {
2123	        /**
2124	         * @internal
2125	         */
2126	        constructor(messageOrError, error) {
2127	            super(messageOrError, error);
2128	            this.causes = [
2129	                'The Client was unable to establish a media connection.',
2130	                'A media connection which was active failed liveliness checks.',
2131	            ];
2132	            this.code = 53405;
2133	            this.description = 'Media connection failed';
2134	            this.explanation = 'Raised by the Client or Server whenever a media connection fails.';
2135	            this.name = 'ConnectionError';
2136	            this.solutions = [
2137	                'If the problem persists, try connecting to another region.',
2138	                'Check your Client\'s network connectivity.',
2139	                'If you\'ve provided custom ICE Servers then ensure that the URLs and credentials are valid.',
2140	            ];
2141	            Object.setPrototypeOf(this, MediaErrors.ConnectionError.prototype);
2142	            const message = typeof messageOrError === 'string'
2143	                ? messageOrError
2144	                : this.explanation;
2145	            const originalError = typeof messageOrError === 'object'
2146	                ? messageOrError
2147	                : error;
2148	            this.message = `${this.name} (${this.code}): ${message}`;
2149	            this.originalError = originalError;
2150	        }
2151	    }
2152	    MediaErrors.ConnectionError = ConnectionError;
2153	})(MediaErrors || (MediaErrors = {}));
2154	/**
2155	 * @private
2156	 */
2157	const errorsByCode = new Map([
2158	    [20101, AuthorizationErrors.AccessTokenInvalid],
2159	    [20104, AuthorizationErrors.AccessTokenExpired],
2160	    [20151, AuthorizationErrors.AuthenticationFailed],
2161	    [31202, SignatureValidationErrors.AccessTokenSignatureValidationFailed],
2162	    [31400, ClientErrors.BadRequest],
2163	    [31404, ClientErrors.NotFound],
2164	    [31480, ClientErrors.TemporarilyUnavailable],
2165	    [31486, ClientErrors.BusyHere],
2166	    [31603, SIPServerErrors.Decline],
2167	    [31000, GeneralErrors.UnknownError],
2168	    [31001, GeneralErrors.ApplicationNotFoundError],
2169	    [31002, GeneralErrors.ConnectionDeclinedError],
2170	    [31003, GeneralErrors.ConnectionTimeoutError],
2171	    [31005, GeneralErrors.ConnectionError],
2172	    [31008, GeneralErrors.CallCancelledError],
2173	    [31009, GeneralErrors.TransportError],
2174	    [31100, MalformedRequestErrors.MalformedRequestError],
2175	    [31101, MalformedRequestErrors.MissingParameterArrayError],
2176	    [31102, MalformedRequestErrors.AuthorizationTokenMissingError],
2177	    [31103, MalformedRequestErrors.MaxParameterLengthExceededError],
2178	    [31104, MalformedRequestErrors.InvalidBridgeTokenError],
2179	    [31105, MalformedRequestErrors.InvalidClientNameError],
2180	    [31107, MalformedRequestErrors.ReconnectParameterInvalidError],
2181	    [31201, AuthorizationErrors.AuthorizationError],
2182	    [31203, AuthorizationErrors.NoValidAccountError],
2183	    [31204, AuthorizationErrors.InvalidJWTTokenError],
2184	    [31205, AuthorizationErrors.JWTTokenExpiredError],
2185	    [31206, AuthorizationErrors.RateExceededError],
2186	    [31207, AuthorizationErrors.JWTTokenExpirationTooLongError],
2187	    [31209, AuthorizationErrors.ReconnectAttemptError],
2188	    [31210, AuthorizationErrors.CallMessageEventTypeInvalidError],
2189	    [31212, AuthorizationErrors.PayloadSizeExceededError],
2190	    [31401, UserMediaErrors.PermissionDeniedError],
2191	    [31402, UserMediaErrors.AcquisitionFailedError],
2192	    [53000, SignalingErrors.ConnectionError],
2193	    [53001, SignalingErrors.ConnectionDisconnected],
2194	    [53400, MediaErrors.ClientLocalDescFailed],
2195	    [53402, MediaErrors.ClientRemoteDescFailed],
2196	    [53405, MediaErrors.ConnectionError],
2197	]);
2198	Object.freeze(errorsByCode);
2199
2200	/* tslint:disable max-classes-per-file */
2201	// TODO: Consider refactoring this export (VBLOCKS-4589)
2202	/**
2203	 * NOTE(mhuynh): Replacing generic error codes with new (more specific) codes,
2204	 * is a breaking change. If an error code is found in this set, we only perform
2205	 * the transformation if the feature flag is enabled.
2206	 *
2207	 * With every major version bump, such that we are allowed to introduce breaking
2208	 * changes as per semver specification, this array should be cleared.
2209	 *
2210	 * TODO: [VBLOCKS-2295] Remove this in 3.x
2211	 */
2212	const PRECISE_SIGNALING_ERROR_CODES = new Set([
2213	    /**
2214	     * 310XX Errors
2215	     */
2216	    31001,
2217	    31002,
2218	    31003,
2219	    /**
2220	     * 311XX Errors
2221	     */
2222	    31101,
2223	    31102,
2224	    31103,
2225	    31104,
2226	    31105,
2227	    31107,
2228	    /**
2229	     * 312XX Errors
2230	     */
2231	    31201,
2232	    31202,
2233	    31203,
2234	    31204,
2235	    31205,
2236	    31207,
2237	    /**
2238	     * 314XX Errors
2239	     */
2240	    31404,
2241	    31480,
2242	    31486,
2243	    /**
2244	     * 316XX Errors
2245	     */
2246	    31603,
2247	]);
2248	/**
2249	 * Get an error constructor using the [[PRECISE_SIGNALING_ERROR_CODES]] set.
2250	 * @internal
2251	 * @param enableImprovedSignalingErrorPrecision - A boolean representing the
2252	 * optional flag whether or not to use more precise error codes.
2253	 * @param errorCode - The error code.
2254	 * @returns This function returns `undefined` if the passed error code does not
2255	 * correlate to an error or should not be constructed with a more precise error
2256	 * constructor. A sub-class of {@link TwilioError} if the code does correlate to
2257	 * an error.
2258	 */
2259	function getPreciseSignalingErrorByCode(enableImprovedSignalingErrorPrecision, errorCode) {
2260	    if (typeof errorCode !== 'number') {
2261	        return;
2262	    }
2263	    if (!hasErrorByCode(errorCode)) {
2264	        return;
2265	    }
2266	    const shouldTransform = enableImprovedSignalingErrorPrecision
2267	        ? true
2268	        : !PRECISE_SIGNALING_ERROR_CODES.has(errorCode);
2269	    if (!shouldTransform) {
2270	        return;
2271	    }
2272	    return getErrorByCode(errorCode);
2273	}
2274	/**
2275	 * The error that is thrown when an invalid argument is passed to a library API.
2276	 */
2277	class InvalidArgumentError extends Error {
2278	    /**
2279	     * @internal
2280	     */
2281	    constructor(message) {
2282	        super(message);
2283	        this.name = 'InvalidArgumentError';
2284	    }
2285	}
2286	/**
2287	 * The error that is thrown when the library has entered an invalid state.
2288	 */
2289	class InvalidStateError extends Error {
2290	    /**
2291	     * @internal
2292	     */
2293	    constructor(message) {
2294	        super(message);
2295	        this.name = 'InvalidStateError';
2296	    }
2297	}
2298	/**
2299	 * The error that is thrown when an attempt is made to use an API that is not
2300	 * supported on the current platform.
2301	 */
2302	class NotSupportedError extends Error {
2303	    /**
2304	     * @internal
2305	     */
2306	    constructor(message) {
2307	        super(message);
2308	        this.name = 'NotSupportedError';
2309	    }
2310	}
2311	/**
2312	 * This should only be used to look up error codes returned by a server
2313	 * using the same repo of error codes.
2314	 * @internal
2315	 */
2316	function getErrorByCode(code) {
2317	    const error = errorsByCode.get(code);
2318	    if (!error) {
2319	        throw new InvalidArgumentError(`Error code ${code} not found`);
2320	    }
2321	    return error;
2322	}
2323	/**
2324	 * This should only be used to look up error codes returned by a server
2325	 * using the same repo of error codes.
2326	 * @internal
2327	 */
2328	function hasErrorByCode(code) {
2329	    return errorsByCode.has(code);
2330	}
2331
2332	/**
2333	 * This file is generated on build. To make changes, see /templates/constants.ts
2334	 */
2335	const PACKAGE_NAME = '@twilio/voice-sdk';
2336	const RELEASE_VERSION = '2.16.0';
2337	const SOUNDS_BASE_URL = 'https://sdk.twilio.com/js/client/sounds/releases/1.0.0';
2338	const COWBELL_AUDIO_URL = `${SOUNDS_BASE_URL}/cowbell.mp3?cache=${RELEASE_VERSION}`;
2339	const ECHO_TEST_DURATION = 20000;
2340
2341	/**
2342	 * {@link Log} provides logging features throughout the sdk using loglevel module
2343	 * See https://github.com/pimterry/loglevel for documentation
2344	 * @private
2345	 */
2346	class Log {
2347	    /**
2348	     * Return the `loglevel` instance maintained internally.
2349	     * @param [options] - Optional settings
2350	     * @returns The `loglevel` instance.
2351	     */
2352	    static getLogLevelInstance(options) {
2353	        if (!Log.loglevelInstance) {
2354	            try {
2355	                Log.loglevelInstance = (options && options.LogLevelModule ? options.LogLevelModule : loglevel$1).getLogger(PACKAGE_NAME);
2356	            }
2357	            catch (_a) {
2358	                // tslint:disable-next-line
2359	                console.warn('Cannot create custom logger');
2360	                Log.loglevelInstance = console;
2361	            }
2362	        }
2363	        return Log.loglevelInstance;
2364	    }
2365	    /**
2366	     * @constructor
2367	     * @param [tag] - tag name for the logs
2368	     * @param [options] - Optional settings
2369	     */
2370	    constructor(tag, options) {
2371	        this._log = Log.getLogLevelInstance(options);
2372	        this._prefix = `[TwilioVoice][${tag}]`;
2373	    }
2374	    /**
2375	     * Log a debug message
2376	     * @param args - Any number of arguments to be passed to loglevel.debug
2377	     */
2378	    debug(...args) {
2379	        this._log.debug(this._prefix, ...args);
2380	    }
2381	    /**
2382	     * Log an error message
2383	     * @param args - Any number of arguments to be passed to loglevel.error
2384	     */
2385	    error(...args) {
2386	        this._log.error(this._prefix, ...args);
2387	    }
2388	    /**
2389	     * Log an info message
2390	     * @param args - Any number of arguments to be passed to loglevel.info
2391	     */
2392	    info(...args) {
2393	        this._log.info(this._prefix, ...args);
2394	    }
2395	    /**
2396	     * Set a default log level to disable all logging below the given level
2397	     */
2398	    setDefaultLevel(level) {
2399	        if (this._log.setDefaultLevel) {
2400	            this._log.setDefaultLevel(level);
2401	        }
2402	        else {
2403	            // tslint:disable-next-line
2404	            console.warn('Logger cannot setDefaultLevel');
2405	        }
2406	    }
2407	    /**
2408	     * Log a warning message
2409	     * @param args - Any number of arguments to be passed to loglevel.warn
2410	     */
2411	    warn(...args) {
2412	        this._log.warn(this._prefix, ...args);
2413	    }
2414	}
2415	/**
2416	 * Log levels
2417	 */
2418	Log.levels = loglevelExports.levels;
2419	Log.getLogLevelInstance();
2420
2421	const DEFAULT_TEST_SOUND_URL = `${SOUNDS_BASE_URL}/outgoing.mp3`;
2422	/**
2423	 * A smart collection containing a Set of active output devices.
2424	 */
2425	class OutputDeviceCollection {
2426	    /**
2427	     * @internal
2428	     */
2429	    constructor(_name, _availableDevices, _beforeChange, _isSupported) {
2430	        this._name = _name;
2431	        this._availableDevices = _availableDevices;
2432	        this._beforeChange = _beforeChange;
2433	        this._isSupported = _isSupported;
2434	        /**
2435	         * The currently active output devices.
2436	         */
2437	        this._activeDevices = new Set();
2438	        /**
2439	         * An instance of Logger to use.
2440	         */
2441	        this._log = new Log('OutputDeviceCollection');
2442	    }
2443	    /**
2444	     * Delete a device from the collection. If no devices remain, the 'default'
2445	     * device will be added as the sole device. If no `default` device exists,
2446	     * the first available device will be used.
2447	     * @param device - The device to delete from the collection
2448	     * @returns whether the device was present before it was deleted
2449	     */
2450	    delete(device) {
2451	        this._log.debug('.delete', device);
2452	        const wasDeleted = !!(this._activeDevices.delete(device));
2453	        const defaultDevice = this._availableDevices.get('default')
2454	            || Array.from(this._availableDevices.values())[0];
2455	        if (!this._activeDevices.size && defaultDevice) {
2456	            this._activeDevices.add(defaultDevice);
2457	        }
2458	        // Call _beforeChange so that the implementation can react when a device is
2459	        // removed or lost.
2460	        const deviceIds = Array.from(this._activeDevices.values()).map(deviceInfo => deviceInfo.deviceId);
2461	        this._beforeChange(this._name, deviceIds);
2462	        return !!wasDeleted;
2463	    }
2464	    /**
2465	     * Get the current set of devices.
2466	     */
2467	    get() {
2468	        return this._activeDevices;
2469	    }
2470	    /**
2471	     * Replace the current set of devices with a new set of devices.
2472	     * @param deviceIdOrIds - An ID or array of IDs of devices to replace the existing devices with.
2473	     * @returns Rejects if this feature is not supported, any of the supplied IDs are not found,
2474	     * or no IDs are passed.
2475	     */
2476	    set(deviceIdOrIds) {
2477	        this._log.debug('.set', deviceIdOrIds);
2478	        if (!this._isSupported) {
2479	            return Promise.reject(new NotSupportedError('This browser does not support audio output selection'));
2480	        }
2481	        const deviceIds = Array.isArray(deviceIdOrIds) ? deviceIdOrIds : [deviceIdOrIds];
2482	        if (!deviceIds.length) {
2483	            return Promise.reject(new InvalidArgumentError('Must specify at least one device to set'));
2484	        }
2485	        const missingIds = [];
2486	        const devices = deviceIds.map((id) => {
2487	            const device = this._availableDevices.get(id);
2488	            if (!device) {
2489	                missingIds.push(id);
2490	            }
2491	            return device;
2492	        });
2493	        if (missingIds.length) {
2494	            return Promise.reject(new InvalidArgumentError(`Devices not found: ${missingIds.join(', ')}`));
2495	        }
2496	        return new Promise(resolve => {
2497	            resolve(this._beforeChange(this._name, deviceIds));
2498	        }).then(() => {
2499	            this._activeDevices.clear();
2500	            devices.forEach(this._activeDevices.add, this._activeDevices);
2501	        });
2502	    }
2503	    /**
2504	     * Test the devices by playing audio through them.
2505	     * @param [soundUrl] - An optional URL. If none is specified, we will
2506	     *   play a default test tone.
2507	     * @returns Resolves with the result of the underlying HTMLAudioElements' play() calls.
2508	     */
2509	    test(soundUrl = DEFAULT_TEST_SOUND_URL) {
2510	        if (!this._isSupported) {
2511	            return Promise.reject(new NotSupportedError('This browser does not support audio output selection'));
2512	        }
2513	        if (!this._activeDevices.size) {
2514	            return Promise.reject(new InvalidStateError('No active output devices to test'));
2515	        }
2516	        return Promise.all(Array.from(this._activeDevices).map((device) => {
2517	            let el;
2518	            // (rrowland) We need to wait for the oncanplay event because of a regression introduced
2519	            // in Chrome M72: https://bugs.chromium.org/p/chromium/issues/detail?id=930876
2520	            return new Promise((resolve) => {
2521	                el = new Audio(soundUrl);
2522	                el.oncanplay = resolve;
2523	            }).then(() => el.setSinkId(device.deviceId).then(() => el.play()));
2524	        }));
2525	    }
2526	}
2527
2528	// @ts-nocheck
2529	class MediaDeviceInfoShim {
2530	    constructor(options) {
2531	        Object.defineProperties(this, {
2532	            deviceId: { get() { return options.deviceId; } },
2533	            groupId: { get() { return options.groupId; } },
2534	            kind: { get() { return options.kind; } },
2535	            label: { get() { return options.label; } },
2536	        });
2537	    }
2538	}
2539
2540	// @ts-nocheck
2541	/**
2542	 * Exception class.
2543	 * @class
2544	 * @name Exception
2545	 * @exports Exception as Twilio.Exception
2546	 * @memberOf Twilio
2547	 * @param {string} message The exception message
2548	 */
2549	function TwilioException(message) {
2550	    if (!(this instanceof TwilioException)) {
2551	        return new TwilioException(message);
2552	    }
2553	    this.message = message;
2554	}
2555	/**
2556	 * Returns the exception message.
2557	 *
2558	 * @return {string} The exception message.
2559	 */
2560	TwilioException.prototype.toString = function () {
2561	    return `Twilio.Exception: ${this.message}`;
2562	};
2563	function average(values) {
2564	    return values && values.length ? values.reduce((t, v) => t + v) / values.length : 0;
2565	}
2566	function difference(lefts, rights, getKey) {
2567	    getKey = getKey || (a => a);
2568	    const rightKeys = new Set(rights.map(getKey));
2569	    return lefts.filter(left => !rightKeys.has(getKey(left)));
2570	}
2571	function isElectron(navigator) {
2572	    return !!navigator.userAgent.match('Electron');
2573	}
2574	function isChrome(window, navigator) {
2575	    const isCriOS = !!navigator.userAgent.match('CriOS');
2576	    const isHeadlessChrome = !!navigator.userAgent.match('HeadlessChrome');
2577	    const isGoogle = typeof window.chrome !== 'undefined'
2578	        && navigator.vendor === 'Google Inc.'
2579	        && navigator.userAgent.indexOf('OPR') === -1
2580	        && navigator.userAgent.indexOf('Edge') === -1;
2581	    return isCriOS || isElectron(navigator) || isGoogle || isHeadlessChrome;
2582	}
2583	function isFirefox(navigator) {
2584	    navigator = navigator || (typeof window === 'undefined'
2585	        ? global.navigator : window.navigator);
2586	    return !!(navigator) && typeof navigator.userAgent === 'string'
2587	        && /firefox|fxios/i.test(navigator.userAgent);
2588	}
2589	/**
2590	 * Chromium-based Edge has a user-agent of "Edg/" where legacy Edge has a
2591	 * user-agent of "Edge/".
2592	 */
2593	function isLegacyEdge(navigator) {
2594	    navigator = navigator || (typeof window === 'undefined'
2595	        ? global.navigator : window.navigator);
2596	    return !!(navigator) && typeof navigator.userAgent === 'string'
2597	        && /edge\/\d+/i.test(navigator.userAgent);
2598	}
2599	function isSafari(navigator) {
2600	    return !!(navigator.vendor) && navigator.vendor.indexOf('Apple') !== -1
2601	        && navigator.userAgent
2602	        && navigator.userAgent.indexOf('CriOS') === -1
2603	        && navigator.userAgent.indexOf('FxiOS') === -1;
2604	}
2605	function queryToJson(params) {
2606	    if (!params) {
2607	        return '';
2608	    }
2609	    return params.split('&').reduce((output, pair) => {
2610	        const parts = pair.split('=');
2611	        const key = parts[0];
2612	        const value = decodeURIComponent((parts[1] || '').replace(/\+/g, '%20'));
2613	        if (key) {
2614	            output[key] = value;
2615	        }
2616	        return output;
2617	    }, {});
2618	}
2619	/**
2620	 * Map a list to an array of arrays, and return the flattened result.
2621	 * @param {Array<*>|Set<*>|Map<*>} list
2622	 * @param {function(*): Array<*>} [mapFn]
2623	 * @returns Array<*>
2624	 */
2625	function flatMap(list, mapFn) {
2626	    const listArray = list instanceof Map || list instanceof Set
2627	        ? Array.from(list.values())
2628	        : list;
2629	    mapFn = mapFn || (item => item);
2630	    return listArray.reduce((flattened, item) => {
2631	        const mapped = mapFn(item);
2632	        return flattened.concat(mapped);
2633	    }, []);
2634	}
2635	/**
2636	 * Converts an EventEmitter's events into a promise and automatically
2637	 * cleans up handlers once the promise is resolved or rejected.
2638	 */
2639	function promisifyEvents(emitter, resolveEventName, rejectEventName) {
2640	    return new Promise((resolve, reject) => {
2641	        function resolveHandler() {
2642	            emitter.removeListener(rejectEventName, rejectHandler);
2643	            resolve();
2644	        }
2645	        function rejectHandler() {
2646	            emitter.removeListener(resolveEventName, resolveHandler);
2647	            reject();
2648	        }
2649	        emitter.once(resolveEventName, resolveHandler);
2650	        emitter.once(rejectEventName, rejectHandler);
2651	    });
2652	}
2653	function sortByMimeTypes(codecs, preferredOrder) {
2654	    const preferredCodecs = preferredOrder.map(codec => 'audio/' + codec.toLowerCase());
2655	    return codecs.sort((a, b) => {
2656	        const indexA = preferredCodecs.indexOf(a.mimeType.toLowerCase());
2657	        const indexB = preferredCodecs.indexOf(b.mimeType.toLowerCase());
2658	        const orderA = indexA >= 0 ? indexA : Number.MAX_VALUE;
2659	        const orderB = indexB >= 0 ? indexB : Number.MAX_VALUE;
2660	        return orderA - orderB;
2661	    });
2662	}
2663	const Exception = TwilioException;
2664
2665	var util = /*#__PURE__*/Object.freeze({
2666		__proto__: null,
2667		Exception: Exception,
2668		average: average,
2669		difference: difference,
2670		flatMap: flatMap,
2671		isChrome: isChrome,
2672		isElectron: isElectron,
2673		isFirefox: isFirefox,
2674		isLegacyEdge: isLegacyEdge,
2675		isSafari: isSafari,
2676		promisifyEvents: promisifyEvents,
2677		queryToJson: queryToJson,
2678		sortByMimeTypes: sortByMimeTypes
2679	});
2680
2681	/**
2682	 * Aliases for audio kinds, used for labelling.
2683	 */
2684	const kindAliases = {
2685	    audioinput: 'Audio Input',
2686	    audiooutput: 'Audio Output',
2687	};
2688	/**
2689	 * Provides input and output audio-based functionality in one convenient class.
2690	 */
2691	class AudioHelper extends eventsExports.EventEmitter {
2692	    /**
2693	     * The currently set audio constraints set by setAudioConstraints(). Starts as null.
2694	     */
2695	    get audioConstraints() { return this._audioConstraints; }
2696	    /**
2697	     * The active input device. Having no inputDevice specified by `setInputDevice()`
2698	     * will disable input selection related functionality.
2699	     */
2700	    get inputDevice() { return this._inputDevice; }
2701	    /**
2702	     * The current input stream coming from the microphone device or
2703	     * the processed audio stream if there is an {@link AudioProcessor}.
2704	     */
2705	    get inputStream() { return this._processedStream || this._selectedInputDeviceStream; }
2706	    /**
2707	     * The processed stream if an {@link AudioProcessor} was previously added.
2708	     */
2709	    get processedStream() { return this._processedStream; }
2710	    /**
2711	     * @internal
2712	     * @param onActiveOutputsChanged - A callback to be called when the user changes the active output devices.
2713	     * @param onActiveInputChanged - A callback to be called when the user changes the active input device.
2714	     * @param [options]
2715	     */
2716	    constructor(onActiveOutputsChanged, onActiveInputChanged, options) {
2717	        super();
2718	        /**
2719	         * A Map of all audio input devices currently available to the browser by their device ID.
2720	         */
2721	        this.availableInputDevices = new Map();
2722	        /**
2723	         * A Map of all audio output devices currently available to the browser by their device ID.
2724	         */
2725	        this.availableOutputDevices = new Map();
2726	        /**
2727	         * The currently set audio constraints set by setAudioConstraints().
2728	         */
2729	        this._audioConstraints = null;
2730	        /**
2731	         * The audio stream of the default device.
2732	         * This is populated when _openDefaultDeviceWithConstraints is called,
2733	         * See _selectedInputDeviceStream for differences.
2734	         * TODO: Combine these two workflows (3.x?)
2735	         */
2736	        this._defaultInputDeviceStream = null;
2737	        /**
2738	         * Whether each sound is enabled.
2739	         */
2740	        this._enabledSounds = {
2741	            [Device.SoundName.Disconnect]: true,
2742	            [Device.SoundName.Incoming]: true,
2743	            [Device.SoundName.Outgoing]: true,
2744	        };
2745	        /**
2746	         * The current input device.
2747	         */
2748	        this._inputDevice = null;
2749	        /**
2750	         * The internal promise created when calling setInputDevice
2751	         */
2752	        this._inputDevicePromise = null;
2753	        /**
2754	         * Whether the {@link AudioHelper} is currently polling the input stream's volume.
2755	         */
2756	        this._isPollingInputVolume = false;
2757	        /**
2758	         * An instance of Logger to use.
2759	         */
2760	        this._log = new Log('AudioHelper');
2761	        /**
2762	         * Internal reference to the processed stream
2763	         */
2764	        this._processedStream = null;
2765	        /**
2766	         * The selected input stream coming from the microphone device.
2767	         * This is populated when the setInputDevice is called, meaning,
2768	         * the end user manually selected it, which is different than
2769	         * the defaultInputDeviceStream.
2770	         * TODO: Combine these two workflows (3.x?)
2771	         */
2772	        this._selectedInputDeviceStream = null;
2773	        /**
2774	         * A record of unknown devices (Devices without labels)
2775	         */
2776	        this._unknownDeviceIndexes = {
2777	            audioinput: {},
2778	            audiooutput: {},
2779	        };
2780	        /**
2781	         * Update the available input and output devices
2782	         * @internal
2783	         */
2784	        this._updateAvailableDevices = () => {
2785	            if (!this._mediaDevices || !this._enumerateDevices) {
2786	                return Promise.reject('Enumeration not supported');
2787	            }
2788	            return this._enumerateDevices().then((devices) => {
2789	                this._updateDevices(devices.filter((d) => d.kind === 'audiooutput'), this.availableOutputDevices, this._removeLostOutput);
2790	                this._updateDevices(devices.filter((d) => d.kind === 'audioinput'), this.availableInputDevices, this._removeLostInput);
2791	                const defaultDevice = this.availableOutputDevices.get('default')
2792	                    || Array.from(this.availableOutputDevices.values())[0];
2793	                [this.speakerDevices, this.ringtoneDevices].forEach(outputDevices => {
2794	                    if (!outputDevices.get().size && this.availableOutputDevices.size && this.isOutputSelectionSupported) {
2795	                        outputDevices.set(defaultDevice.deviceId)
2796	                            .catch((reason) => {
2797	                            this._log.warn(`Unable to set audio output devices. ${reason}`);
2798	                        });
2799	                    }
2800	                });
2801	            });
2802	        };
2803	        /**
2804	         * Remove an input device from inputs
2805	         * @param lostDevice
2806	         * @returns Whether the device was active
2807	         */
2808	        this._removeLostInput = (lostDevice) => {
2809	            if (!this.inputDevice || this.inputDevice.deviceId !== lostDevice.deviceId) {
2810	                return false;
2811	            }
2812	            this._destroyProcessedStream();
2813	            this._replaceStream(null);
2814	            this._inputDevice = null;
2815	            this._maybeStopPollingVolume();
2816	            const defaultDevice = this.availableInputDevices.get('default')
2817	                || Array.from(this.availableInputDevices.values())[0];
2818	            if (defaultDevice) {
2819	                this.setInputDevice(defaultDevice.deviceId);
2820	            }
2821	            return true;
2822	        };
2823	        /**
2824	         * Remove an input device from outputs
2825	         * @param lostDevice
2826	         * @returns Whether the device was active
2827	         */
2828	        this._removeLostOutput = (lostDevice) => {
2829	            const wasSpeakerLost = this.speakerDevices.delete(lostDevice);
2830	            const wasRingtoneLost = this.ringtoneDevices.delete(lostDevice);
2831	            return wasSpeakerLost || wasRingtoneLost;
2832	        };
2833	        options = Object.assign({
2834	            AudioContext: typeof AudioContext !== 'undefined' && AudioContext,
2835	            setSinkId: typeof HTMLAudioElement !== 'undefined' && HTMLAudioElement.prototype.setSinkId,
2836	        }, options);
2837	        this._beforeSetInputDevice = options.beforeSetInputDevice || (() => Promise.resolve());
2838	        this._updateUserOptions(options);
2839	        this._audioProcessorEventObserver = options.audioProcessorEventObserver;
2840	        this._mediaDevices = options.mediaDevices || navigator.mediaDevices;
2841	        this._onActiveInputChanged = onActiveInputChanged;
2842	        this._enumerateDevices = typeof options.enumerateDevices === 'function'
2843	            ? options.enumerateDevices
2844	            : this._mediaDevices && this._mediaDevices.enumerateDevices.bind(this._mediaDevices);
2845	        const isAudioContextSupported = !!(options.AudioContext || options.audioContext);
2846	        const isEnumerationSupported = !!this._enumerateDevices;
2847	        if (options.enabledSounds) {
2848	            this._enabledSounds = options.enabledSounds;
2849	        }
2850	        const isSetSinkSupported = typeof options.setSinkId === 'function';
2851	        this.isOutputSelectionSupported = isEnumerationSupported && isSetSinkSupported;
2852	        this.isVolumeSupported = isAudioContextSupported;
2853	        if (this.isVolumeSupported) {
2854	            this._audioContext = options.audioContext || options.AudioContext && new options.AudioContext();
2855	            if (this._audioContext) {
2856	                this._inputVolumeAnalyser = this._audioContext.createAnalyser();
2857	                this._inputVolumeAnalyser.fftSize = 32;
2858	                this._inputVolumeAnalyser.smoothingTimeConstant = 0.3;
2859	            }
2860	        }
2861	        this.ringtoneDevices = new OutputDeviceCollection('ringtone', this.availableOutputDevices, onActiveOutputsChanged, this.isOutputSelectionSupported);
2862	        this.speakerDevices = new OutputDeviceCollection('speaker', this.availableOutputDevices, onActiveOutputsChanged, this.isOutputSelectionSupported);
2863	        this.addListener('newListener', (eventName) => {
2864	            if (eventName === 'inputVolume') {
2865	                this._maybeStartPollingVolume();
2866	            }
2867	        });
2868	        this.addListener('removeListener', (eventName) => {
2869	            if (eventName === 'inputVolume') {
2870	                this._maybeStopPollingVolume();
2871	            }
2872	        });
2873	        this.once('newListener', () => {
2874	            // NOTE (rrowland): Ideally we would only check isEnumerationSupported here, but
2875	            //   in at least one browser version (Tested in FF48) enumerateDevices actually
2876	            //   returns bad data for the listed devices. Instead, we check for
2877	            //   isOutputSelectionSupported to avoid these quirks that may negatively affect customers.
2878	            if (!this.isOutputSelectionSupported) {
2879	                this._log.warn('Warning: This browser does not support audio output selection.');
2880	            }
2881	            if (!this.isVolumeSupported) {
2882	                this._log.warn(`Warning: This browser does not support Twilio's volume indicator feature.`);
2883	            }
2884	        });
2885	        if (isEnumerationSupported) {
2886	            this._initializeEnumeration();
2887	        }
2888	        // NOTE (kchoy): Currently microphone permissions are not supported in firefox, and Safari V15 and older.
2889	        // https://github.com/mozilla/standards-positions/issues/19#issuecomment-370158947
2890	        // https://caniuse.com/permissions-api
2891	        if (navigator && navigator.permissions && typeof navigator.permissions.query === 'function') {
2892	            navigator.permissions.query({ name: 'microphone' }).then((microphonePermissionStatus) => {
2893	                if (microphonePermissionStatus.state !== 'granted') {
2894	                    const handleStateChange = () => {
2895	                        this._updateAvailableDevices();
2896	                        this._stopMicrophonePermissionListener();
2897	                    };
2898	                    microphonePermissionStatus.addEventListener('change', handleStateChange);
2899	                    this._microphonePermissionStatus = microphonePermissionStatus;
2900	                    this._onMicrophonePermissionStatusChanged = handleStateChange;
2901	                }
2902	            }).catch((reason) => this._log.warn(`Warning: unable to listen for microphone permission changes. ${reason}`));
2903	        }
2904	        else {
2905	            this._log.warn('Warning: current browser does not support permissions API.');
2906	        }
2907	    }
2908	    /**
2909	     * Destroy this AudioHelper instance
2910	     * @internal
2911	     */
2912	    _destroy() {
2913	        this._stopDefaultInputDeviceStream();
2914	        this._stopSelectedInputDeviceStream();
2915	        this._destroyProcessedStream();
2916	        this._maybeStopPollingVolume();
2917	        this.removeAllListeners();
2918	        this._stopMicrophonePermissionListener();
2919	        this._unbind();
2920	    }
2921	    /**
2922	     * Promise to wait for the input device, if setInputDevice is called outside of the SDK
2923	     * @internal
2924	     */
2925	    _getInputDevicePromise() {
2926	        return this._inputDevicePromise;
2927	    }
2928	    /**
2929	     * Start polling volume if it's supported and there's an input stream to poll.
2930	     * @internal
2931	     */
2932	    _maybeStartPollingVolume() {
2933	        if (!this.isVolumeSupported || !this.inputStream) {
2934	            return;
2935	        }
2936	        this._updateVolumeSource();
2937	        if (this._isPollingInputVolume || !this._inputVolumeAnalyser) {
2938	            return;
2939	        }
2940	        const bufferLength = this._inputVolumeAnalyser.frequencyBinCount;
2941	        const buffer = new Uint8Array(bufferLength);
2942	        this._isPollingInputVolume = true;
2943	        const emitVolume = () => {
2944	            if (!this._isPollingInputVolume) {
2945	                return;
2946	            }
2947	            if (this._inputVolumeAnalyser) {
2948	                this._inputVolumeAnalyser.getByteFrequencyData(buffer);
2949	                const inputVolume = average(buffer);
2950	                this.emit('inputVolume', inputVolume / 255);
2951	            }
2952	            requestAnimationFrame(emitVolume);
2953	        };
2954	        requestAnimationFrame(emitVolume);
2955	    }
2956	    /**
2957	     * Stop polling volume if it's currently polling and there are no listeners.
2958	     * @internal
2959	     */
2960	    _maybeStopPollingVolume() {
2961	        if (!this.isVolumeSupported) {
2962	            return;
2963	        }
2964	        if (!this._isPollingInputVolume || (this.inputStream && this.listenerCount('inputVolume'))) {
2965	            return;
2966	        }
2967	        if (this._inputVolumeSource) {
2968	            this._inputVolumeSource.disconnect();
2969	            delete this._inputVolumeSource;
2970	        }
2971	        this._isPollingInputVolume = false;
2972	    }
2973	    /**
2974	     * Call getUserMedia with specified constraints
2975	     * @internal
2976	     */
2977	    _openDefaultDeviceWithConstraints(constraints) {
2978	        this._log.info('Opening default device with constraints', constraints);
2979	        return this._getUserMedia(constraints).then((stream) => {
2980	            this._log.info('Opened default device. Updating available devices.');
2981	            // Ensures deviceId's and labels are populated after the gUM call
2982	            // by calling enumerateDevices
2983	            this._updateAvailableDevices().catch(error => {
2984	                // Ignore error, we don't want to break the call flow
2985	                this._log.warn('Unable to updateAvailableDevices after gUM call', error);
2986	            });
2987	            this._defaultInputDeviceStream = stream;
2988	            return this._maybeCreateProcessedStream(stream);
2989	        });
2990	    }
2991	    /**
2992	     * Stop the default audio stream
2993	     * @internal
2994	     */
2995	    _stopDefaultInputDeviceStream() {
2996	        if (this._defaultInputDeviceStream) {
2997	            this._log.info('stopping default device stream');
2998	            this._defaultInputDeviceStream.getTracks().forEach(track => track.stop());
2999	            this._defaultInputDeviceStream = null;
3000	            this._destroyProcessedStream();
3001	        }
3002	    }
3003	    /**
3004	     * Unbind the listeners from mediaDevices.
3005	     * @internal
3006	     */
3007	    _unbind() {
3008	        var _a;
3009	        if ((_a = this._mediaDevices) === null || _a === void 0 ? void 0 : _a.removeEventListener) {
3010	            this._mediaDevices.removeEventListener('devicechange', this._updateAvailableDevices);
3011	        }
3012	    }
3013	    /**
3014	     * Update AudioHelper options that can be changed by the user
3015	     * @internal
3016	     */
3017	    _updateUserOptions(options) {
3018	        if (typeof options.enumerateDevices === 'function') {
3019	            this._enumerateDevices = options.enumerateDevices;
3020	        }
3021	        if (typeof options.getUserMedia === 'function') {
3022	            this._getUserMedia = options.getUserMedia;
3023	        }
3024	    }
3025	    /**
3026	     * Adds an {@link AudioProcessor} object. Once added, the AudioHelper will route
3027	     * the input audio stream through the processor before sending the audio
3028	     * stream to Twilio. Only one AudioProcessor can be added at this time.
3029	     *
3030	     * See the {@link AudioProcessor} interface for an example.
3031	     *
3032	     * @param processor The AudioProcessor to add.
3033	     * @returns
3034	     */
3035	    addProcessor(processor) {
3036	        this._log.debug('.addProcessor');
3037	        if (this._processor) {
3038	            throw new NotSupportedError('Adding multiple AudioProcessors is not supported at this time.');
3039	        }
3040	        if (typeof processor !== 'object' || processor === null) {
3041	            throw new InvalidArgumentError('Missing AudioProcessor argument.');
3042	        }
3043	        if (typeof processor.createProcessedStream !== 'function') {
3044	            throw new InvalidArgumentError('Missing createProcessedStream() method.');
3045	        }
3046	        if (typeof processor.destroyProcessedStream !== 'function') {
3047	            throw new InvalidArgumentError('Missing destroyProcessedStream() method.');
3048	        }
3049	        this._processor = processor;
3050	        this._audioProcessorEventObserver.emit('add');
3051	        return this._restartStreams();
3052	    }
3053	    /**
3054	     * Enable or disable the disconnect sound.
3055	     * @param doEnable Passing `true` will enable the sound and `false` will disable the sound.
3056	     * Not passing this parameter will not alter the enable-status of the sound.
3057	     * @returns The enable-status of the sound.
3058	     */
3059	    disconnect(doEnable) {
3060	        this._log.debug('.disconnect', doEnable);
3061	        return this._maybeEnableSound(Device.SoundName.Disconnect, doEnable);
3062	    }
3063	    /**
3064	     * Enable or disable the incoming sound.
3065	     * @param doEnable Passing `true` will enable the sound and `false` will disable the sound.
3066	     * Not passing this parameter will not alter the enable-status of the sound.
3067	     * @returns The enable-status of the sound.
3068	     */
3069	    incoming(doEnable) {
3070	        this._log.debug('.incoming', doEnable);
3071	        return this._maybeEnableSound(Device.SoundName.Incoming, doEnable);
3072	    }
3073	    /**
3074	     * Enable or disable the outgoing sound.
3075	     * @param doEnable Passing `true` will enable the sound and `false` will disable the sound.
3076	     * Not passing this parameter will not alter the enable-status of the sound.
3077	     * @returns The enable-status of the sound.
3078	     */
3079	    outgoing(doEnable) {
3080	        this._log.debug('.outgoing', doEnable);
3081	        return this._maybeEnableSound(Device.SoundName.Outgoing, doEnable);
3082	    }
3083	    /**
3084	     * Removes an {@link AudioProcessor}. Once removed, the AudioHelper will start using
3085	     * the audio stream from the selected input device for existing or future calls.
3086	     *
3087	     * @param processor The AudioProcessor to remove.
3088	     * @returns
3089	     */
3090	    removeProcessor(processor) {
3091	        this._log.debug('.removeProcessor');
3092	        if (typeof processor !== 'object' || processor === null) {
3093	            throw new InvalidArgumentError('Missing AudioProcessor argument.');
3094	        }
3095	        if (this._processor !== processor) {
3096	            throw new InvalidArgumentError('Cannot remove an AudioProcessor that has not been previously added.');
3097	        }
3098	        this._destroyProcessedStream();
3099	        this._processor = null;
3100	        this._audioProcessorEventObserver.emit('remove');
3101	        return this._restartStreams();
3102	    }
3103	    /**
3104	     * Set the MediaTrackConstraints to be applied on every getUserMedia call for new input
3105	     * device audio. Any deviceId specified here will be ignored. Instead, device IDs should
3106	     * be specified using {@link AudioHelper#setInputDevice}. The returned Promise resolves
3107	     * when the media is successfully reacquired, or immediately if no input device is set.
3108	     * @param audioConstraints - The MediaTrackConstraints to apply.
3109	     */
3110	    setAudioConstraints(audioConstraints) {
3111	        this._log.debug('.setAudioConstraints', audioConstraints);
3112	        this._audioConstraints = Object.assign({}, audioConstraints);
3113	        delete this._audioConstraints.deviceId;
3114	        return this.inputDevice
3115	            ? this._setInputDevice(this.inputDevice.deviceId, true)
3116	            : Promise.resolve();
3117	    }
3118	    /**
3119	     * Replace the current input device with a new device by ID.
3120	     *
3121	     * Calling `setInputDevice` sets the stream for current and future calls and
3122	     * will not release it automatically.
3123	     *
3124	     * While this behavior is not an issue, it will result in the application
3125	     * holding onto the input device, and the application may show a red
3126	     * "recording" symbol in the browser tab.
3127	     *
3128	     * To remove the red "recording" symbol, the device must be released. To
3129	     * release it, call `unsetInputDevice` after the call disconnects. Note that
3130	     * after calling `unsetInputDevice` future calls will then use the default
3131	     * input device.
3132	     *
3133	     * Consider application logic that keeps track of the user-selected device
3134	     * and call `setInputDevice` before calling `device.connect()` for outgoing
3135	     * calls and `call.accept()` for incoming calls. Furthermore, consider
3136	     * calling `unsetInputDevice` once a call is disconnected. Below is an
3137	     * example:
3138	     *
3139	     * ```ts
3140	     * import { Device } from '@twilio/voice-sdk';
3141	     * let inputDeviceId = ...;
3142	     * const device = new Device(...);
3143	     *
3144	     * async function makeOutgoingCall() {
3145	     *   await device.audio.setInputDevice(inputDeviceId);
3146	     *   const call = await device.connect(...);
3147	     *
3148	     *   call.on('disconnect', async () => {
3149	     *     inputDeviceId = ... // save the current input device id
3150	     *     await device.audio.unsetInputDevice();
3151	     *   });
3152	     * }
3153	     *
3154	     * async function acceptIncomingCall(incomingCall) {
3155	     *   await device.audio.setInputDevice(inputDeviceId);
3156	     *   await incomingCall.accept();
3157	     *
3158	     *   incomingCall.on('disconnect', async () => {
3159	     *     inputDeviceId = ... // save the current input device id
3160	     *     await device.audio.unsetInputDevice();
3161	     *   });
3162	     * }
3163	     * ```
3164	     *
3165	     * @param deviceId - An ID of a device to replace the existing
3166	     *   input device with.
3167	     */
3168	    setInputDevice(deviceId) {
3169	        this._log.debug('.setInputDevice', deviceId);
3170	        return this._setInputDevice(deviceId, false);
3171	    }
3172	    /**
3173	     * Unset the MediaTrackConstraints to be applied on every getUserMedia call for new input
3174	     * device audio. The returned Promise resolves when the media is successfully reacquired,
3175	     * or immediately if no input device is set.
3176	     */
3177	    unsetAudioConstraints() {
3178	        this._log.debug('.unsetAudioConstraints');
3179	        this._audioConstraints = null;
3180	        return this.inputDevice
3181	            ? this._setInputDevice(this.inputDevice.deviceId, true)
3182	            : Promise.resolve();
3183	    }
3184	    /**
3185	     * Unset the input device, stopping the tracks. This should only be called when not in a connection, and
3186	     *   will not allow removal of the input device during a live call.
3187	     */
3188	    unsetInputDevice() {
3189	        this._log.debug('.unsetInputDevice', this.inputDevice);
3190	        if (!this.inputDevice) {
3191	            return Promise.resolve();
3192	        }
3193	        this._destroyProcessedStream();
3194	        return this._onActiveInputChanged(null).then(() => {
3195	            this._replaceStream(null);
3196	            this._inputDevice = null;
3197	            this._maybeStopPollingVolume();
3198	        });
3199	    }
3200	    /**
3201	     * Destroys processed stream and update references
3202	     */
3203	    _destroyProcessedStream() {
3204	        if (this._processor && this._processedStream) {
3205	            this._log.info('destroying processed stream');
3206	            const processedStream = this._processedStream;
3207	            this._processedStream.getTracks().forEach(track => track.stop());
3208	            this._processedStream = null;
3209	            this._processor.destroyProcessedStream(processedStream);
3210	            this._audioProcessorEventObserver.emit('destroy');
3211	        }
3212	    }
3213	    /**
3214	     * Get the index of an un-labeled Device.
3215	     * @param mediaDeviceInfo
3216	     * @returns The index of the passed MediaDeviceInfo
3217	     */
3218	    _getUnknownDeviceIndex(mediaDeviceInfo) {
3219	        const id = mediaDeviceInfo.deviceId;
3220	        const kind = mediaDeviceInfo.kind;
3221	        let index = this._unknownDeviceIndexes[kind][id];
3222	        if (!index) {
3223	            index = Object.keys(this._unknownDeviceIndexes[kind]).length + 1;
3224	            this._unknownDeviceIndexes[kind][id] = index;
3225	        }
3226	        return index;
3227	    }
3228	    /**
3229	     * Initialize output device enumeration.
3230	     */
3231	    _initializeEnumeration() {
3232	        if (!this._mediaDevices || !this._enumerateDevices) {
3233	            throw new NotSupportedError('Enumeration is not supported');
3234	        }
3235	        if (this._mediaDevices.addEventListener) {
3236	            this._mediaDevices.addEventListener('devicechange', this._updateAvailableDevices);
3237	        }
3238	        this._updateAvailableDevices().then(() => {
3239	            if (!this.isOutputSelectionSupported) {
3240	                return;
3241	            }
3242	            Promise.all([
3243	                this.speakerDevices.set('default'),
3244	                this.ringtoneDevices.set('default'),
3245	            ]).catch(reason => {
3246	                this._log.warn(`Warning: Unable to set audio output devices. ${reason}`);
3247	            });
3248	        });
3249	    }
3250	    /**
3251	     * Route input stream to the processor if it exists
3252	     */
3253	    _maybeCreateProcessedStream(stream) {
3254	        if (this._processor) {
3255	            this._log.info('Creating processed stream');
3256	            return this._processor.createProcessedStream(stream).then((processedStream) 
3256=> {
3257	                this._processedStream = processedStream;
3258	                this._audioProcessorEventObserver.emit('create');
3259	                return this._processedStream;
3260	            });
3261	        }
3262	        return Promise.resolve(stream);
3263	    }
3264	    /**
3265	     * Set whether the sound is enabled or not
3266	     * @param soundName
3267	     * @param doEnable
3268	     * @returns Whether the sound is enabled or not
3269	     */
3270	    _maybeEnableSound(soundName, doEnable) {
3271	        if (typeof doEnable !== 'undefined') {
3272	            this._enabledSounds[soundName] = doEnable;
3273	        }
3274	        return this._enabledSounds[soundName];
3275	    }
3276	    /**
3277	     * Stop the tracks on the current input stream before replacing it with the passed stream.
3278	     * @param stream - The new stream
3279	     */
3280	    _replaceStream(stream) {
3281	        this._log.info('Replacing with new stream.');
3282	        if (this._selectedInputDeviceStream) {
3283	            this._log.info('Old stream detected. Stopping tracks.');
3284	            this._stopSelectedInputDeviceStream();
3285	        }
3286	        this._selectedInputDeviceStream = stream;
3287	    }
3288	    /**
3289	     * Restart the active streams
3290	     */
3291	    _restartStreams() {
3292	        if (this.inputDevice && this._selectedInputDeviceStream) {
3293	            this._log.info('Restarting selected input device');
3294	            return this._setInputDevice(this.inputDevice.deviceId, true);
3295	        }
3296	        if (this._defaultInputDeviceStream) {
3297	            const defaultDevice = this.availableInputDevices.get('default')
3298	                || Array.from(this.availableInputDevices.values())[0];
3299	            this._log.info('Restarting default input device, now becoming selected.');
3300	            return this._setInputDevice(defaultDevice.deviceId, true);
3301	        }
3302	        return Promise.resolve();
3303	    }
3304	    /**
3305	     * Replace the current input device with a new device by ID.
3306	     * @param deviceId - An ID of a device to replace the existing
3307	     *   input device with.
3308	     * @param forceGetUserMedia - If true, getUserMedia will be called even if
3309	     *   the specified device is already active.
3310	     */
3311	    _setInputDevice(deviceId, forceGetUserMedia) {
3312	        return __awaiter(this, void 0, void 0, function* () {
3313	            const setInputDevice = () => __awaiter(this, void 0, void 0, function* () {
3314	                yield this._beforeSetInputDevice();
3315	                if (typeof deviceId !== 'string') {
3316	                    return Promise.reject(new InvalidArgumentError('Must specify the device to set'));
3317	                }
3318	                const device = this.availableInputDevices.get(deviceId);
3319	                if (!device) {
3320	                    return Promise.reject(new InvalidArgumentError(`Device not found: ${deviceId}`));
3321	                }
3322	                this._log.info('Setting input device. ID: ' + deviceId);
3323	                if (this._inputDevice && this._inputDevice.deviceId === deviceId && this._selectedInputDeviceStream) {
3324	                    if (!forceGetUserMedia) {
3325	                        return Promise.resolve();
3326	                    }
3327	                    // If the currently active track is still in readyState `live`, gUM may return the same track
3328	                    // rather than returning a fresh track.
3329	                    this._log.info('Same track detected on setInputDevice, stopping old tracks.');
3330	                    this._stopSelectedInputDeviceStream();
3331	                }
3332	                // Release the default device in case it was created previously
3333	                this._stopDefaultInputDeviceStream();
3334	                const constraints = { audio: Object.assign({ deviceId: { exact: deviceId } }, this.audioConstraints) };
3335	                this._log.info('setInputDevice: getting new tracks.');
3336	                return this._getUserMedia(constraints).then((originalStream) => {
3337	                    this._destroyProcessedStream();
3338	                    return this._maybeCreateProcessedStream(originalStream).then((newStream) => {
3339	                        this._log.info('setInputDevice: invoking _onActiveInputChanged.');
3340	                        return this._onActiveInputChanged(newStream).then(() => {
3341	                            this._replaceStream(originalStream);
3342	                            this._inputDevice = device;
3343	                            this._maybeStartPollingVolume();
3344	                        });
3345	                    });
3346	                });
3347	            });
3348	            return this._inputDevicePromise = setInputDevice().finally(() => {
3349	                this._inputDevicePromise = null;
3350	            });
3351	        });
3352	    }
3353	    /**
3354	     * Remove event listener for microphone permissions
3355	     */
3356	    _stopMicrophonePermissionListener() {
3357	        var _a;
3358	        if ((_a = this._microphonePermissionStatus) === null || _a === void 0 ? void 0 : _a.removeEventListener) {
3359	            this._microphonePermissionStatus.removeEventListener('change', this._onMicrophonePermissionStatusChanged);
3360	        }
3361	    }
3362	    /**
3363	     * Stop the selected audio stream
3364	     */
3365	    _stopSelectedInputDeviceStream() {
3366	        if (this._selectedInputDeviceStream) {
3367	            this._log.info('Stopping selected device stream');
3368	            this._selectedInputDeviceStream.getTracks().forEach(track => track.stop());
3369	        }
3370	    }
3371	    /**
3372	     * Update a set of devices.
3373	     * @param updatedDevices - An updated list of available Devices
3374	     * @param availableDevices - The previous list of available Devices
3375	     * @param removeLostDevice - The method to call if a previously available Device is
3376	     *   no longer available.
3377	     */
3378	    _updateDevices(updatedDevices, availableDevices, removeLostDevice) {
3379	        const updatedDeviceIds = updatedDevices.map(d => d.deviceId);
3380	        const knownDeviceIds = Array.from(availableDevices.values()).map(d => d.deviceId);
3381	        const lostActiveDevices = [];
3382	        // Remove lost devices
3383	        const lostDeviceIds = difference(knownDeviceIds, updatedDeviceIds);
3384	        lostDeviceIds.forEach((lostDeviceId) => {
3385	            const lostDevice = availableDevices.get(lostDeviceId);
3386	            if (lostDevice) {
3387	                availableDevices.delete(lostDeviceId);
3388	                if (removeLostDevice(lostDevice)) {
3389	                    lostActiveDevices.push(lostDevice);
3390	                }
3391	            }
3392	        });
3393	        // Add any new devices, or devices with updated labels
3394	        let deviceChanged = false;
3395	        updatedDevices.forEach(newDevice => {
3396	            const existingDevice = availableDevices.get(newDevice.deviceId);
3397	            const newMediaDeviceInfo = this._wrapMediaDeviceInfo(newDevice);
3398	            if (!existingDevice || existingDevice.label !== newMediaDeviceInfo.label) {
3399	                availableDevices.set(newDevice.deviceId, newMediaDeviceInfo);
3400	                deviceChanged = true;
3401	            }
3402	        });
3403	        if (deviceChanged || lostDeviceIds.length) {
3404	            // Force a new gUM in case the underlying tracks of the active stream have changed. One
3405	            //   reason this might happen is when `default` is selected and set to a USB device,
3406	            //   then that device is unplugged or plugged back in. We can't check for the 'ended'
3407	            //   event or readyState because it is asynchronous and may take upwards of 5 seconds,
3408	            //   in my testing. (rrowland)
3409	            const defaultId = 'default';
3410	            // this.inputDevice is not null if audio.setInputDevice() was explicitly called
3411	            const isInputDeviceSet = this.inputDevice && this.inputDevice.deviceId === defaultId;
3412	            // If this.inputDevice is null, and default stream is not null, it means
3413	            // the user is using the default stream and did not explicitly call audio.setInputDevice()
3414	            const isDefaultDeviceSet = this._defaultInputDeviceStream && this.availableInputDevices.get(defaultId);
3415	            if (isInputDeviceSet || isDefaultDeviceSet) {
3416	                this._log.warn(`Calling getUserMedia after device change to ensure that the \
3417          tracks of the active device (default) have not gone stale.`);
3418	                // NOTE(csantos): Updating the stream in the same execution context as the devicechange event
3419	                // causes the new gUM call to fail silently. Meaning, the gUM call may succeed,
3420	                // but it won't actually update the stream. We need to update the stream in a different
3421	                // execution context (setTimeout) to properly update the stream.
3422	                setTimeout(() => {
3423	                    this._setInputDevice(defaultId, true);
3424	                }, 0);
3425	            }
3426	            this._log.debug('#deviceChange', lostActiveDevices);
3427	            this.emit('deviceChange', lostActiveDevices);
3428	        }
3429	    }
3430	    /**
3431	     * Disconnect the old input volume source, and create and connect a new one with the current
3432	     * input stream.
3433	     */
3434	    _updateVolumeSource() {
3435	        if (!this.inputStream || !this._audioContext || !this._inputVolumeAnalyser) {
3436	            return;
3437	        }
3438	        if (this._inputVolumeSource) {
3439	            this._inputVolumeSource.disconnect();
3440	        }
3441	        try {
3442	            this._inputVolumeSource = this._audioContext.createMediaStreamSource(this.inputStream);
3443	            this._inputVolumeSource.connect(this._inputVolumeAnalyser);
3444	        }
3445	        catch (ex) {
3446	            this._log.warn('Unable to update volume source', ex);
3447	            delete this._inputVolumeSource;
3448	        }
3449	    }
3450	    /**
3451	     * Convert a MediaDeviceInfo to a IMediaDeviceInfoShim.
3452	     * @param mediaDeviceInfo - The info to convert
3453	     * @returns The converted shim
3454	     */
3455	    _wrapMediaDeviceInfo(mediaDeviceInfo) {
3456	        const options = {
3457	            deviceId: mediaDeviceInfo.deviceId,
3458	            groupId: mediaDeviceInfo.groupId,
3459	            kind: mediaDeviceInfo.kind,
3460	            label: mediaDeviceInfo.label,
3461	        };
3462	        if (!options.label) {
3463	            if (options.deviceId === 'default') {
3464	                options.label = 'Default';
3465	            }
3466	            else {
3467	                const index = this._getUnknownDeviceIndex(mediaDeviceInfo);
3468	                options.label = `Unknown ${kindAliases[options.kind]} Device ${index}`;
3469	            }
3470	        }
3471	        return new MediaDeviceInfoShim(options);
3472	    }
3473	}
3474	/**
3475	 * @mergeModuleWith AudioHelper
3476	 */
3477	(function (AudioHelper) {
3478	})(AudioHelper || (AudioHelper = {}));
3479	var AudioHelper$1 = AudioHelper;
3480
3481	/**
3482	 * AudioProcessorEventObserver observes {@link AudioProcessor}
3483	 * related operations and re-emits them as generic events.
3484	 * @internal
3485	 */
3486	class AudioProcessorEventObserver extends eventsExports.EventEmitter {
3487	    constructor() {
3488	        super();
3489	        this._log = new Log('AudioProcessorEventObserver');
3490	        this._log.info('Creating AudioProcessorEventObserver instance');
3491	        this.on('enabled', () => this._reEmitEvent('enabled'));
3492	        this.on('add', () => this._reEmitEvent('add'));
3493	        this.on('remove', () => this._reEmitEvent('remove'));
3494	        this.on('create', () => this._reEmitEvent('create-processed-stream'));
3495	        this.on('destroy', () => this._reEmitEvent('destroy-processed-stream'));
3496	    }
3497	    destroy() {
3498	        this.removeAllListeners();
3499	    }
3500	    _reEmitEvent(name) {
3501	        this._log.info(`AudioProcessor:${name}`);
3502	        this.emit('event', { name, group: 'audio-processor' });
3503	    }
3504	}
3505
3506	/**
3507	 * A Map of DTMF Sound Names to their mock frequency pairs.
3508	 */
3509	const bandFrequencies = {
3510	    dtmf0: [1360, 960],
3511	    dtmf1: [1230, 720],
3512	    dtmf2: [1360, 720],
3513	    dtmf3: [1480, 720],
3514	    dtmf4: [1230, 790],
3515	    dtmf5: [1360, 790],
3516	    dtmf6: [1480, 790],
3517	    dtmf7: [1230, 870],
3518	    dtmf8: [1360, 870],
3519	    dtmf9: [1480, 870],
3520	    dtmfh: [1480, 960],
3521	    dtmfs: [1230, 960],
3522	};
3523	class DialtonePlayer {
3524	    constructor(_context) {
3525	        this._context = _context;
3526	        /**
3527	         * Gain nodes, reducing the frequency.
3528	         */
3529	        this._gainNodes = [];
3530	        this._gainNodes = [
3531	            this._context.createGain(),
3532	            this._context.createGain(),
3533	        ];
3534	        this._gainNodes.forEach((gainNode) => {
3535	            gainNode.connect(this._context.destination);
3536	            gainNode.gain.value = 0.1;
3537	            this._gainNodes.push(gainNode);
3538	        });
3539	    }
3540	    cleanup() {
3541	        this._gainNodes.forEach((gainNode) => {
3542	            gainNode.disconnect();
3543	        });
3544	    }
3545	    /**
3546	     * Play the dual frequency tone for the passed DTMF name.
3547	     * @param sound
3548	     */
3549	    play(sound) {
3550	        const frequencies = bandFrequencies[sound];
3551	        if (!frequencies) {
3552	            throw new InvalidArgumentError('Invalid DTMF sound name');
3553	        }
3554	        const oscillators = [
3555	            this._context.createOscillator(),
3556	            this._context.createOscillator(),
3557	        ];
3558	        oscillators.forEach((oscillator, i) => {
3559	            oscillator.type = 'sine';
3560	            oscillator.frequency.value = frequencies[i];
3561	            oscillator.connect(this._gainNodes[i]);
3562	            oscillator.start();
3563	            oscillator.stop(this._context.currentTime + 0.1);
3564	            oscillator.addEventListener('ended', () => oscillator.disconnect());
3565	        });
3566	    }
3567	}
3568
3569	// @ts-nocheck
3570	function request(method, params, callback) {
3571	    const body = JSON.stringify(params.body || {});
3572	    const headers = new Headers();
3573	    params.headers = params.headers || [];
3574	    Object.entries(params.headers).forEach(([headerName, headerBody]) => headers.append(headerName, headerBody));
3575	    fetch(params.url, { body, headers, method })
3576	        .then(response => response.text(), callback)
3577	        .then(responseText => callback(null, responseText), callback);
3578	}
3579	/**
3580	 * Use XMLHttpRequest to get a network resource.
3581	 * @param {String} method - HTTP Method
3582	 * @param {Object} params - Request parameters
3583	 * @param {String} params.url - URL of the resource
3584	 * @param {Array}  params.headers - An array of headers to pass [{ headerName : headerBody }]
3585	 * @param {Object} params.body - A JSON body to send to the resource
3586	 * @returns {response}
3587	 */
3588	const Request = request;
3589	/**
3590	 * Sugar function for request('GET', params, callback);
3591	 * @param {Object} params - Request parameters
3592	 * @param {Request~get} callback - The callback that handles the response.
3593	 */
3594	Request.get = function get(params, callback) {
3595	    return new this('GET', params, callback);
3596	};
3597	/**
3598	 * Sugar function for request('POST', params, callback);
3599	 * @param {Object} params - Request parameters
3600	 * @param {Request~post} callback - The callback that handles the response.
3601	 */
3602	Request.post = function post(params, callback) {
3603	    return new this('POST', params, callback);
3604	};
3605
3606	// @ts-nocheck
3607	/**
3608	 * Builds Endpoint Analytics (EA) event payloads and sends them to
3609	 *   the EA server.
3610	 * @constructor
3611	 * @param {String} productName - Name of the product publishing events.
3612	 * @param {String} token - The JWT token to use to authenticate with
3613	 *   the EA server.
3614	 * @param {EventPublisher.Options} options
3615	 * @property {Boolean} isEnabled - Whether or not this publisher is publishing
3616	 *   to the server. Currently ignores the request altogether, in the future this
3617	 *   may store them in case publishing is re-enabled later. Defaults to true.
3618	 */
3619	/**
3620	 * @typedef {Object} EventPublisher.Options
3621	 * @property {Object} [metadata=undefined] - A publisher_metadata object to send
3622	 *   with each payload.
3623	 * @property {String} [host='eventgw.twilio.com'] - The host address of the EA
3624	 *   server to publish to.
3625	 * @property {Object|Function} [defaultPayload] - A default payload to extend
3626	 *   when creating and sending event payloads. Also takes a function that
3627	 *   should return an object representing the default payload. This is
3628	 *   useful for fields that should always be present when they are
3629	 *   available, but are not always available.
3630	 */
3631	class EventPublisher extends eventsExports.EventEmitter {
3632	    constructor(productName, token, options) {
3633	        super();
3634	        if (!(this instanceof EventPublisher)) {
3635	            return new EventPublisher(productName, token, options);
3636	        }
3637	        // Apply default options
3638	        options = Object.assign({ defaultPayload() { return {}; } }, options);
3639	        let defaultPayload = options.defaultPayload;
3640	        if (typeof defaultPayload !== 'function') {
3641	            defaultPayload = () => Object.assign({}, options.defaultPayload);
3642	        }
3643	        let isEnabled = true;
3644	        const metadata = Object.assign({ app_name: undefined, app_version: undefined }, options.metadata);
3645	        Object.defineProperties(this, {
3646	            _defaultPayload: { value: defaultPayload },
3647	            _host: { value: options.host, writable: true },
3648	            _isEnabled: {
3649	                get() { return isEnabled; },
3650	                set(_isEnabled) { isEnabled = _isEnabled; },
3651	            },
3652	            _log: { value: new Log('EventPublisher') },
3653	            _request: { value: options.request || Request, writable: true },
3654	            _token: { value: token, writable: true },
3655	            isEnabled: {
3656	                enumerable: true,
3657	                get() { return isEnabled; },
3658	            },
3659	            metadata: {
3660	                enumerable: true,
3661	                get() { return metadata; },
3662	            },
3663	            productName: { enumerable: true, value: productName },
3664	            token: {
3665	                enumerable: true,
3666	                get() { return this._token; },
3667	            },
3668	        });
3669	    }
3670	}
3671	/**
3672	 * Post to an EA server.
3673	 * @private
3674	 * @param {String} endpointName - Endpoint to post the event to
3675	 * @param {String} level - ['debug', 'info', 'warning', 'error']
3676	 * @param {String} group - The name of the group the event belongs to.
3677	 * @param {String} name - The designated event name.
3678	 * @param {?Object} [payload=null] - The payload to pass. This will be extended
3679	 *    onto the default payload object, if one exists.
3680	 * @param {?Connection} [connection=null] - The {@link Connection} which is posting this payload.
3681	 * @param {?Boolean} [force=false] - Whether or not to send this even if
3682	 *    publishing is disabled.
3683	 * @returns {Promise}
3683 Fulfilled if the HTTP response is 20x.
3684	 */
3685	EventPublisher.prototype._post = function _post(endpointName, level, group, name, payload, connection, force) {
3686	    if ((!this.isEnabled && !force) || !this._host) {
3687	        this._log.debug('Publishing cancelled', JSON.stringify({ isEnabled: this.isEnabled, force, host: this._host }));
3688	        return Promise.resolve();
3689	    }
3690	    if (!connection || ((!connection.parameters || !connection.parameters.CallSid) && !connection.outboundConnectionId)) {
3691	        if (!connection) {
3692	            this._log.debug('Publishing cancelled. Missing connection object');
3693	        }
3694	        else {
3695	            this._log.debug('Publishing cancelled. Missing connection info', JSON.stringify({
3696	                outboundConnectionId: connection.outboundConnectionId, parameters: connection.parameters,
3697	            }));
3698	        }
3699	        return Promise.resolve();
3700	    }
3701	    const event = {
3702	        group,
3703	        level: level.toUpperCase(),
3704	        name,
3705	        payload: (payload && payload.forEach) ?
3706	            payload.slice(0) : Object.assign(this._defaultPayload(connection), payload),
3707	        payload_type: 'application/json',
3708	        private: false,
3709	        publisher: this.productName,
3710	        timestamp: (new Date()).toISOString(),
3711	    };
3712	    if (this.metadata) {
3713	        event.publisher_metadata = this.metadata;
3714	    }
3715	    if (endpointName === 'EndpointEvents') {
3716	        this._log.debug('Publishing insights', JSON.stringify({ endpointName, event, force, host: this._host }));
3717	    }
3718	    const requestParams = {
3719	        body: event,
3720	        headers: {
3721	            'Content-Type': 'application/json',
3722	            'X-Twilio-Token': this.token,
3723	        },
3724	        url: `https://${this._host}/v4/${endpointName}`,
3725	    };
3726	    return new Promise((resolve, reject) => {
3727	        this._request.post(requestParams, err => {
3728	            if (err) {
3729	                this.emit('error', err);
3730	                reject(err);
3731	            }
3732	            else {
3733	                resolve();
3734	            }
3735	        });
3736	    }).catch(e => {
3737	        this._log.error(`Unable to post ${group} ${name} event to Insights. Received error: ${e}`);
3738	    });
3739	};
3740	/**
3741	 * Post an event to the EA server. Use this method when the level
3742	 *  is dynamic. Otherwise, it's better practice to use the sugar
3743	 *  methods named for the specific level.
3744	 * @param {String} level - ['debug', 'info', 'warning', 'error']
3745	 * @param {String} group - The name of the group the event belongs to.
3746	 * @param {String} name - The designated event name.
3747	 * @param {?Object} [payload=null] - The payload to pass. This will be extended
3748	 *    onto the default payload object, if one exists.
3749	 * @param {?Connection} [connection=null] - The {@link Connection} which is posting this payload.
3750	 * @returns {Promise}
3750 Fulfilled if the HTTP response is 20x.
3751	 */
3752	EventPublisher.prototype.post = function post(level, group, name, payload, connection, force) {
3753	    return this._post('EndpointEvents', level, group, name, payload, connection, force);
3754	};
3755	/**
3756	 * Post a debug-level event to the EA server.
3757	 * @param {String} group - The name of the group the event belongs to.
3758	 * @param {String} name - The designated event name.
3759	 * @param {?Object} [payload=null] - The payload to pass. This will be extended
3760	 *    onto the default payload object, if one exists.
3761	 * @param {?Connection} [connection=null] - The {@link Connection} which is posting this payload.
3762	 * @returns {Promise} Fulfilled if the HTTP response is 20x.
3763	 */
3764	EventPublisher.prototype.debug = function debug(group, name, payload, connection) {
3765	    return this.post('debug', group, name, payload, connection);
3766	};
3767	/**
3768	 * Post an info-level event to the EA server.
3769	 * @param {String} group - The name of the group the event belongs to.
3770	 * @param {String} name - The designated event name.
3771	 * @param {?Object} [payload=null] - The payload to pass. This will be extended
3772	 *    onto the default payload object, if one exists.
3773	 * @param {?Connection} [connection=null] - The {@link Connection} which is posting this payload.
3774	 * @returns {Promise}
3774 Fulfilled if the HTTP response is 20x.
3775	 */
3776	EventPublisher.prototype.info = function info(group, name, payload, connection) {
3777	    return this.post('info', group, name, payload, connection);
3778	};
3779	/**
3780	 * Post a warning-level event to the EA server.
3781	 * @param {String} group - The name of the group the event belongs to.
3782	 * @param {String} name - The designated event name.
3783	 * @param {?Object} [payload=null] - The payload to pass. This will be extended
3784	 *    onto the default payload object, if one exists.
3785	 * @param {?Connection} [connection=null] - The {@link Connection} which is posting this payload.
3786	 * @returns {Promise} Fulfilled if the HTTP response is 20x.
3787	 */
3788	EventPublisher.prototype.warn = function warn(group, name, payload, connection) {
3789	    return this.post('warning', group, name, payload, connection);
3790	};
3791	/**
3792	 * Post an error-level event to the EA server.
3793	 * @param {String} group - The name of the group the event belongs to.
3794	 * @param {String} name - The designated event name.
3795	 * @param {?Object} [payload=null] - The payload to pass. This will be extended
3796	 *    onto the default payload object, if one exists.
3797	 * @param {?Connection} [connection=null] - The {@link Connection} which is posting this payload.
3798	 * @returns {Promise}
3798 Fulfilled if the HTTP response is 20x.
3799	 */
3800	EventPublisher.prototype.error = function error(group, name, payload, connection) {
3801	    return this.post('error', group, name, payload, connection);
3802	};
3803	/**
3804	 * Post a metrics event to the EA server.
3805	 * @param {String} group - The name of the group the event belongs to.
3806	 * @param {String} name - The designated event name.
3807	 * @param {Array<Object>} metrics - The metrics to post.
3808	 * @param {?Object} [customFields] - Custom fields to append to each payload.
3809	 * @returns {Promise} Fulfilled if the HTTP response is 20x.
3810	 */
3811	EventPublisher.prototype.postMetrics = function postMetrics(group, name, metrics, customFields, connection) {
3812	    return new Promise(resolve => {
3813	        const samples = metrics
3814	            .map(formatMetric)
3815	            .map(sample => Object.assign(sample, customFields));
3816	        resolve(this._post('EndpointMetrics', 'info', group, name, samples, connection));
3817	    });
3818	};
3819	/**
3820	 * Update the host address of the insights server to publish to.
3821	 * @param {String} host - The new host address of the insights server.
3822	 */
3823	EventPublisher.prototype.setHost = function setHost(host) {
3824	    this._host = host;
3825	};
3826	/**
3827	 * Update the token to use to authenticate requests.
3828	 * @param {string} token
3829	 * @returns {void}
3830	 */
3831	EventPublisher.prototype.setToken = function setToken(token) {
3832	    this._token = token;
3833	};
3834	/**
3835	 * Enable the publishing of events.
3836	 */
3837	EventPublisher.prototype.enable = function enable() {
3838	    this._isEnabled = true;
3839	};
3840	/**
3841	 * Disable the publishing of events.
3842	 */
3843	EventPublisher.prototype.disable = function disable() {
3844	    this._isEnabled = false;
3845	};
3846	function formatMetric(sample) {
3847	    return {
3848	        audio_codec: sample.codecName,
3849	        audio_level_in: sample.audioInputLevel,
3850	        audio_level_out: sample.audioOutputLevel,
3851	        bytes_received: sample.bytesReceived,
3852	        bytes_sent: sample.bytesSent,
3853	        call_volume_input: sample.inputVolume,
3854	        call_volume_output: sample.outputVolume,
3855	        jitter: sample.jitter,
3856	        mos: sample.mos && (Math.round(sample.mos * 100) / 100),
3857	        packets_lost: sample.packetsLost,
3858	        packets_lost_fraction: sample.packetsLostFraction &&
3859	            (Math.round(sample.packetsLostFraction * 100) / 100),
3860	        packets_received: sample.packetsReceived,
3861	        rtt: sample.rtt,
3862	        timestamp: (new Date(sample.timestamp)).toISOString(),
3863	        total_bytes_received: sample.totals.bytesReceived,
3864	        total_bytes_sent: sample.totals.bytesSent,
3865	        total_packets_lost: sample.totals.packetsLost,
3866	        total_packets_received: sample.totals.packetsReceived,
3867	        total_packets_sent: sample.totals.packetsSent,
3868	    };
3869	}
3870
3871	// @ts-nocheck
3872	/**
3873	 * This file was imported from another project. If making changes to this file, please don't
3874	 * make them here. Make them on the linked repo below, then copy back:
3875	 * https://code.hq.twilio.com/client/MockRTCStatsReport
3876	 */
3877	// The legacy max volume, which is the positive half of a signed short integer.
3878	const OLD_MAX_VOLUME = 32767;
3879	const NativeRTCStatsReport = typeof window !== 'undefined'
3880	    ? window.RTCStatsReport : undefined;
3881	/**
3882	 * Create a MockRTCStatsReport wrapper around a Map of RTCStats objects. If RTCStatsReport is available
3883	 *   natively, it will be inherited so that instanceof checks pass.
3884	 * @constructor
3885	 * @extends RTCStatsReport
3886	 * @param {Map<string, RTCStats>} statsMap - A Map of RTCStats objects to wrap
3887	 *   with a MockRTCStatsReport object.
3888	 */
3889	function MockRTCStatsReport(statsMap) {
3890	    if (!(this instanceof MockRTCStatsReport)) {
3891	        return new MockRTCStatsReport(statsMap);
3892	    }
3893	    const self = this;
3894	    Object.defineProperties(this, {
3895	        _map: { value: statsMap },
3896	        size: {
3897	            enumerable: true,
3898	            get() {
3899	                return self._map.size;
3900	            },
3901	        },
3902	    });
3903	    this[Symbol.iterator] = statsMap[Symbol.iterator];
3904	}
3905	// If RTCStatsReport is available natively, inherit it. Keep our constructor.
3906	if (NativeRTCStatsReport) {
3907	    MockRTCStatsReport.prototype = Object.create(NativeRTCStatsReport.prototype);
3908	    MockRTCStatsReport.prototype.constructor = MockRTCStatsReport;
3909	}
3910	// Map the Map-like read methods to the underlying Map
3911	['entries', 'forEach', 'get', 'has', 'keys', 'values'].forEach(key => {
3912	    MockRTCStatsReport.prototype[key] = function (...args) {
3913	        return this._map[key](...args);
3914	    };
3915	});
3916	/**
3917	 * Convert an array of RTCStats objects into a mock RTCStatsReport object.
3918	 * @param {Array<RTCStats>}
3919	 * @return {MockRTCStatsReport}
3920	 */
3921	MockRTCStatsReport.fromArray = function fromArray(array) {
3922	    return new MockRTCStatsReport(array.reduce((map, rtcStats) => {
3923	        map.set(rtcStats.id, rtcStats);
3924	        return map;
3925	    }, new Map()));
3926	};
3927	/**
3928	 * Convert a legacy RTCStatsResponse object into a mock RTCStatsReport object.
3929	 * @param {RTCStatsResponse} statsResponse - An RTCStatsResponse object returned by the
3930	 *   legacy getStats(callback) method in Chrome.
3931	 * @return {MockRTCStatsReport} A mock RTCStatsReport object.
3932	 */
3933	MockRTCStatsReport.fromRTCStatsResponse = function fromRTCStatsResponse(statsResponse) {
3934	    let activeCandidatePairId;
3935	    const transportIds = new Map();
3936	    const statsMap = statsResponse.result().reduce((map, report) => {
3937	        const id = report.id;
3938	        switch (report.type) {
3939	            case 'googCertificate':
3940	                map.set(id, createRTCCertificateStats(report));
3941	                break;
3942	            case 'datachannel':
3943	                map.set(id, createRTCDataChannelStats(report));
3944	                break;
3945	            case 'googCandidatePair':
3946	                if (getBoolean(report, 'googActiveConnection')) {
3947	                    activeCandidatePairId = id;
3948	                }
3949	                map.set(id, createRTCIceCandidatePairStats(report));
3950	                break;
3951	            case 'localcandidate':
3952	                map.set(id, createRTCIceCandidateStats(report, false));
3953	                break;
3954	            case 'remotecandidate':
3955	                map.set(id, createRTCIceCandidateStats(report, true));
3956	                break;
3957	            case 'ssrc':
3958	                if (isPresent(report, 'packetsReceived')) {
3959	                    map.set(`rtp-${id}`, createRTCInboundRTPStreamStats(report));
3960	                }
3961	                else {
3962	                    map.set(`rtp-${id}`, createRTCOutboundRTPStreamStats(report));
3963	                }
3964	                map.set(`track-${id}`, createRTCMediaStreamTrackStats(report));
3965	                map.set(`codec-${id}`, createRTCCodecStats(report));
3966	                break;
3967	            case 'googComponent':
3968	                const transportReport = createRTCTransportStats(report);
3969	                transportIds.set(transportReport.selectedCandidatePairId, id);
3970	                map.set(id, createRTCTransportStats(report));
3971	                break;
3972	        }
3973	        return map;
3974	    }, new Map());
3975	    if (activeCandidatePairId) {
3976	        const activeTransportId = transportIds.get(activeCandidatePairId);
3977	        if (activeTransportId) {
3978	            statsMap.get(activeTransportId).dtlsState = 'connected';
3979	        }
3980	    }
3981	    return new MockRTCStatsReport(statsMap);
3982	};
3983	/**
3984	 * @param {RTCLegacyStatsReport} report
3985	 * @returns {RTCTransportStats}
3986	 */
3987	function createRTCTransportStats(report) {
3988	    return {
3989	        bytesReceived: undefined,
3990	        bytesSent: undefined,
3991	        dtlsState: undefined,
3992	        id: report.id,
3993	        localCertificateId: report.stat('localCertificateId'),
3994	        remoteCertificateId: report.stat('remoteCertificateId'),
3995	        rtcpTransportStatsId: undefined,
3996	        selectedCandidatePairId: report.stat('selectedCandidatePairId'),
3997	        timestamp: Date.parse(report.timestamp),
3998	        type: 'transport',
3999	    };
4000	}
4001	/**
4002	 * @param {RTCLegacyStatsReport} report
4003	 * @returns {RTCCodecStats}
4004	 */
4005	function createRTCCodecStats(report) {
4006	    return {
4007	        channels: undefined,
4008	        clockRate: undefined,
4009	        id: report.id,
4010	        implementation: undefined,
4011	        mimeType: `${report.stat('mediaType')}/${report.stat('googCodecName')}`,
4012	        payloadType: undefined,
4013	        sdpFmtpLine: undefined,
4014	        timestamp: Date.parse(report.timestamp),
4015	        type: 'codec',
4016	    };
4017	}
4018	/**
4019	 * @param {RTCLegacyStatsReport} report
4020	 * @returns {RTCMediaStreamTrackStats}
4021	 */
4022	function createRTCMediaStreamTrackStats(report) {
4023	    return {
4024	        audioLevel: isPresent(report, 'audioOutputLevel')
4025	            ? getInt(report, 'audioOutputLevel') / OLD_MAX_VOLUME
4026	            : (getInt(report, 'audioInputLevel') || 0) / OLD_MAX_VOLUME,
4027	        detached: undefined,
4028	        echoReturnLoss: getFloat(report, 'googEchoCancellationReturnLoss'),
4029	        echoReturnLossEnhancement: getFloat(report, 'googEchoCancellationReturnLossEnhancement'),
4030	        ended: undefined,
4031	        frameHeight: isPresent(report, 'googFrameHeightReceived')
4032	            ? getInt(report, 'googFrameHeightReceived')
4033	            : getInt(report, 'googFrameHeightSent'),
4034	        frameWidth: isPresent(report, 'googFrameWidthReceived')
4035	            ? getInt(report, 'googFrameWidthReceived')
4036	            : getInt(report, 'googFrameWidthSent'),
4037	        framesCorrupted: undefined,
4038	        framesDecoded: getInt(report, 'framesDecoded'),
4039	        framesDropped: undefined,
4040	        framesPerSecond: undefined,
4041	        framesReceived: undefined,
4042	        framesSent: getInt(report, 'framesEncoded'),
4043	        fullFramesLost: undefined,
4044	        id: report.id,
4045	        kind: report.stat('mediaType'),
4046	        partialFramesLost: undefined,
4047	        remoteSource: undefined,
4048	        ssrcIds: undefined,
4049	        timestamp: Date.parse(report.timestamp),
4050	        trackIdentifier: report.stat('googTrackId'),
4051	        type: 'track',
4052	    };
4053	}
4054	/**
4055	 * @param {RTCLegacyStatsReport} report
4056	 * @param {boolean}
4056 isInbound - Whether to create an inbound stats object, or outbound.
4057	 * @returns {RTCRTPStreamStats}
4058	 */
4059	function createRTCRTPStreamStats(report, isInbound) {
4060	    return {
4061	        associateStatsId: undefined,
4062	        codecId: `codec-${report.id}`,
4063	        firCount: isInbound
4064	            ? getInt(report, 'googFirsSent')
4065	            : undefined,
4066	        id: report.id,
4067	        isRemote: undefined,
4068	        mediaType: report.stat('mediaType'),
4069	        nackCount: isInbound
4070	            ? getInt(report, 'googNacksSent')
4071	            : getInt(report, 'googNacksReceived'),
4072	        pliCount: isInbound
4073	            ? getInt(report, 'googPlisSent')
4074	            : getInt(report, 'googPlisReceived'),
4075	        qpSum: getInt(report, 'qpSum'),
4076	        sliCount: undefined,
4077	        ssrc: report.stat('ssrc'),
4078	        timestamp: Date.parse(report.timestamp),
4079	        trackId: `track-${report.id}`,
4080	        transportId: report.stat('transportId'),
4081	    };
4082	}
4083	/**
4084	 * @param {RTCLegacyStatsReport} report
4085	 * @returns {RTCInboundRTPStreamStats}
4086	 */
4087	function createRTCInboundRTPStreamStats(report) {
4088	    const rtp = createRTCRTPStreamStats(report, true);
4089	    Object.assign(rtp, {
4090	        burstDiscardCount: undefined,
4091	        burstDiscardRate: undefined,
4092	        burstLossCount: undefined,
4093	        burstLossRate: undefined,
4094	        burstPacketsDiscarded: undefined,
4095	        burstPacketsLost: undefined,
4096	        bytesReceived: getInt(report, 'bytesReceived'),
4097	        fractionLost: undefined,
4098	        framesDecoded: getInt(report, 'framesDecoded'),
4099	        gapDiscardRate: undefined,
4100	        gapLossRate: undefined,
4101	        jitter: convertMsToSeconds(report.stat('googJitterReceived')),
4102	        packetsDiscarded: undefined,
4103	        packetsLost: getInt(report, 'packetsLost'),
4104	        packetsReceived: getInt(report, 'packetsReceived'),
4105	        packetsRepaired: undefined,
4106	        roundTripTime: convertMsToSeconds(report.stat('googRtt')),
4107	        type: 'inbound-rtp',
4108	    });
4109	    return rtp;
4110	}
4111	/**
4112	 * @param {RTCLegacyStatsReport} report
4113	 * @returns {RTCOutboundRTPStreamStats}
4114	 */
4115	function createRTCOutboundRTPStreamStats(report) {
4116	    const rtp = createRTCRTPStreamStats(report, false);
4117	    Object.assign(rtp, {
4118	        bytesSent: getInt(report, 'bytesSent'),
4119	        framesEncoded: getInt(report, 'framesEncoded'),
4120	        packetsSent: getInt(report, 'packetsSent'),
4121	        remoteTimestamp: undefined,
4122	        targetBitrate: undefined,
4123	        type: 'outbound-rtp',
4124	    });
4125	    return rtp;
4126	}
4127	/**
4128	 * @param {RTCLegacyStatsReport} report
4129	 * @param {boolean} isRemote - Whether to create for a remote candidate, or local candidate.
4130	 * @returns {RTCIceCandidateStats}
4131	 */
4132	function createRTCIceCandidateStats(report, isRemote) {
4133	    return {
4134	        candidateType: translateCandidateType(report.stat('candidateType')),
4135	        deleted: undefined,
4136	        id: report.id,
4137	        ip: report.stat('ipAddress'),
4138	        isRemote,
4139	        port: getInt(report, 'portNumber'),
4140	        priority: getFloat(report, 'priority'),
4141	        protocol: report.stat('transport'),
4142	        relayProtocol: undefined,
4143	        timestamp: Date.parse(report.timestamp),
4144	        transportId: undefined,
4145	        type: isRemote
4146	            ? 'remote-candidate'
4147	            : 'local-candidate',
4148	        url: undefined,
4149	    };
4150	}
4151	/**
4152	 * @param {RTCLegacyStatsReport} report
4153	 * @returns {RTCIceCandidatePairStats}
4154	 */
4155	function createRTCIceCandidatePairStats(report) {
4156	    return {
4157	        availableIncomingBitrate: undefined,
4158	        availableOutgoingBitrate: undefined,
4159	        bytesReceived: getInt(report, 'bytesReceived'),
4160	        bytesSent: getInt(report, 'bytesSent'),
4161	        consentRequestsSent: getInt(report, 'consentRequestsSent'),
4162	        currentRoundTripTime: convertMsToSeconds(report.stat('googRtt')),
4163	        id: report.id,
4164	        lastPacketReceivedTimestamp: undefined,
4165	        lastPacketSentTimestamp: undefined,
4166	        localCandidateId: report.stat('localCandidateId'),
4167	        nominated: undefined,
4168	        priority: undefined,
4169	        readable: undefined,
4170	        remoteCandidateId: report.stat('remoteCandidateId'),
4171	        requestsReceived: getInt(report, 'requestsReceived'),
4172	        requestsSent: getInt(report, 'requestsSent'),
4173	        responsesReceived: getInt(report, 'responsesReceived'),
4174	        responsesSent: getInt(report, 'responsesSent'),
4175	        retransmissionsReceived: undefined,
4176	        retransmissionsSent: undefined,
4177	        state: undefined,
4178	        timestamp: Date.parse(report.timestamp),
4179	        totalRoundTripTime: undefined,
4180	        transportId: report.stat('googChannelId'),
4181	        type: 'candidate-pair',
4182	        writable: getBoolean(report, 'googWritable'),
4183	    };
4184	}
4185	/**
4186	 * @param {RTCLegacyStatsReport} report
4187	 * @returns {RTCIceCertificateStats}
4188	 */
4189	function createRTCCertificateStats(report) {
4190	    return {
4191	        base64Certificate: report.stat('googDerBase64'),
4192	        fingerprint: report.stat('googFingerprint'),
4193	        fingerprintAlgorithm: report.stat('googFingerprintAlgorithm'),
4194	        id: report.id,
4195	        issuerCertificateId: report.stat('googIssuerId'),
4196	        timestamp: Date.parse(report.timestamp),
4197	        type: 'certificate',
4198	    };
4199	}
4200	/**
4201	 * @param {RTCLegacyStatsReport} report
4202	 * @returns {RTCDataChannelStats}
4203	 */
4204	function createRTCDataChannelStats(report) {
4205	    return {
4206	        bytesReceived: undefined,
4207	        bytesSent: undefined,
4208	        datachannelid: report.stat('datachannelid'),
4209	        id: report.id,
4210	        label: report.stat('label'),
4211	        messagesReceived: undefined,
4212	        messagesSent: undefined,
4213	        protocol: report.stat('protocol'),
4214	        state: report.stat('state'),
4215	        timestamp: Date.parse(report.timestamp),
4216	        transportId: report.stat('transportId'),
4217	        type: 'data-channel',
4218	    };
4219	}
4220	/**
4221	 * @param {number} inMs - A time in milliseconds
4222	 * @returns {number} The time in seconds
4223	 */
4224	function convertMsToSeconds(inMs) {
4225	    return isNaN(inMs) || inMs === ''
4226	        ? undefined
4227	        : parseInt(inMs, 10) / 1000;
4228	}
4229	/**
4230	 * @param {string} type - A type in the legacy format
4231	 * @returns {string} The type adjusted to new standards for known naming changes
4232	 */
4233	function translateCandidateType(type) {
4234	    switch (type) {
4235	        case 'peerreflexive':
4236	            return 'prflx';
4237	        case 'serverreflexive':
4238	            return 'srflx';
4239	        case 'host':
4240	        case 'relay':
4241	        default:
4242	            return type;
4243	    }
4244	}
4245	function getInt(report, statName) {
4246	    const stat = report.stat(statName);
4247	    return isPresent(report, statName)
4248	        ? parseInt(stat, 10)
4249	        : undefined;
4250	}
4251	function getFloat(report, statName) {
4252	    const stat = report.stat(statName);
4253	    return isPresent(report, statName)
4254	        ? parseFloat(stat)
4255	        : undefined;
4256	}
4257	function getBoolean(report, statName) {
4258	    const stat = report.stat(statName);
4259	    return isPresent(report, statName)
4260	        ? (stat === 'true' || stat === true)
4261	        : undefined;
4262	}
4263	function isPresent(report, statName) {
4264	    const stat = report.stat(statName);
4265	    return typeof stat !== 'undefined' && stat !== '';
4266	}
4267
4268	// @ts-nocheck
4269	// tslint:disable no-empty
4270	const ERROR_PEER_CONNECTION_NULL = 'PeerConnection is null';
4271	const ERROR_WEB_RTC_UNSUPPORTED = 'WebRTC statistics are unsupported';
4272	/**
4273	 * Helper function to find a specific stat from a report.
4274	 * Some environment provide the stats report as a map (regular browsers)
4275	 * but some provide stats report as an array (citrix vdi)
4276	 * @private
4277	 */
4278	function findStatById(report, id) {
4279	    if (typeof report.get === 'function') {
4280	        return report.get(id);
4281	    }
4282	    return report.find(s => s.id === id);
4283	}
4284	/**
4285	 * Generate WebRTC statistics report for the given {@link PeerConnection}
4286	 * @param {PeerConnection} peerConnection - Target connection.
4287	 * @return {Promise<RTCStatsReport>} WebRTC RTCStatsReport object
4288	 */
4289	function getRTCStatsReport(peerConnection) {
4290	    if (!peerConnection) {
4291	        return Promise.reject(new InvalidArgumentError(ERROR_PEER_CONNECTION_NULL));
4292	    }
4293	    if (typeof peerConnection.getStats !== 'function') {
4294	        return Promise.reject(new NotSupportedError(ERROR_WEB_RTC_UNSUPPORTED));
4295	    }
4296	    let promise;
4297	    try {
4298	        promise = peerConnection.getStats();
4299	    }
4300	    catch (e) {
4301	        promise = new Promise(resolve => peerConnection.getStats(resolve)).then(MockRTCStatsReport.fromRTCStatsResponse);
4302	    }
4303	    return promise;
4304	}
4305	/**
4306	 * @typedef {Object} StatsOptions
4307	 * Used for testing to inject and extract methods.
4308	 * @property {function} [createRTCSample] - Method for parsing an RTCStatsReport
4309	 */
4310	/**
4311	 * Collects any WebRTC statistics for the given {@link PeerConnection}
4312	 * @param {PeerConnection} peerConnection - Target connection.
4313	 * @param {StatsOptions} options - List of custom options.
4314	 * @return {Promise<RTCSample>} Universally-formatted version of RTC stats.
4315	 */
4316	function getRTCStats(peerConnection, options) {
4317	    options = Object.assign({ createRTCSample }, options);
4318	    return getRTCStatsReport(peerConnection).then(options.createRTCSample);
4319	}
4320	/**
4321	 * Generate WebRTC stats report containing relevant information about ICE candidates for the given {@link PeerConnection}
4322	 * @param {PeerConnection} peerConnection - Target connection.
4323	 * @return {Promise<RTCIceCandidateStatsReport>} RTCIceCandidateStatsReport object
4324	 */
4325	function getRTCIceCandidateStatsReport(peerConnection) {
4326	    return getRTCStatsReport(peerConnection).then((report) => {
4327	        // Find the relevant information needed to determine selected candidates later
4328	        const { candidatePairs, localCandidates, remoteCandidates, transport, } = Array.from(report.values()).reduce((rval, stat) => {
4329	            ['candidatePairs', 'localCandidates', 'remoteCandidates'].forEach((prop) => {
4330	                if (!rval[prop]) {
4331	                    rval[prop] = [];
4332	                }
4333	            });
4334	            switch (stat.type) {
4335	                case 'candidate-pair':
4336	                    rval.candidatePairs.push(stat);
4337	                    break;
4338	                case 'local-candidate':
4339	                    rval.localCandidates.push(stat);
4340	                    break;
4341	                case 'remote-candidate':
4342	                    rval.remoteCandidates.push(stat);
4343	                    break;
4344	                case 'transport':
4345	                    // This transport is the one being used if selectedCandidatePairId is populated
4346	                    if (stat.selectedCandidatePairId) {
4347	                        rval.transport = stat;
4348	                    }
4349	                    break;
4350	            }
4351	            return rval;
4352	        }, {});
4353	        // This is a report containing information about the selected candidates, such as IDs
4354	        // This is coming from WebRTC stats directly and doesn't contain the actual ICE Candidates info
4355	        const selectedCandidatePairReport = candidatePairs.find(pair => 
4356	        // Firefox
4357	        pair.selected ||
4358	            // Spec-compliant way
4359	            (transport && pair.id === transport.selectedCandidatePairId));
4360	        let selectedIceCandidatePairStats;
4361	        if (selectedCandidatePairReport) {
4362	            selectedIceCandidatePairStats = {
4363	                localCandidate: localCandidates.find(candidate => candidate.id === selectedCandidatePairReport.localCandidateId),
4364	                remoteCandidate: remoteCandidates.find(candidate => candidate.id === selectedCandidatePairReport.remoteCandidateId),
4365	            };
4366	        }
4367	        // Build the return object
4368	        return {
4369	            iceCandidateStats: [...localCandidates, ...remoteCandidates],
4370	            selectedIceCandidatePairStats,
4371	        };
4372	    });
4373	}
4374	/**
4375	 * @typedef {Object} RTCSample - A sample containing relevant WebRTC stats information.
4376	 * @property {Number} [timestamp]
4377	 * @property {String} [codecName] - MimeType name of the codec being used by the outbound audio stream
4378	 * @property {Number} [rtt] - Round trip time
4379	 * @property {Number} [jitter]
4380	 * @property {Number} [packetsSent]
4381	 * @property {Number} [packetsLost]
4382	 * @property {Number} [packetsReceived]
4383	 * @property {Number} [bytesReceived]
4384	 * @property {Number} [bytesSent]
4385	 * @property {Number} [localAddress]
4386	 * @property {Number} [remoteAddress]
4387	 */
4388	function RTCSample() { }
4389	/**
4390	 * Create an RTCSample object from an RTCStatsReport
4391	 * @private
4392	 * @param {RTCStatsReport} statsReport
4393	 * @returns {RTCSample}
4394	 */
4395	function createRTCSample(statsReport) {
4396	    let activeTransportId = null;
4397	    const sample = new RTCSample();
4398	    let fallbackTimestamp;
4399	    Array.from(statsReport.values()).forEach(stats => {
4400	        // Skip isRemote tracks which will be phased out completely and break in FF66.
4401	        if (stats.isRemote) {
4402	            return;
4403	        }
4404	        // Firefox hack -- Older firefox doesn't have dashes in type names
4405	        const type = stats.type.replace('-', '');
4406	        fallbackTimestamp = fallbackTimestamp || stats.timestamp;
4407	        // (rrowland) As I understand it, this is supposed to come in on remote-inbound-rtp but it's
4408	        // currently coming in on remote-outbound-rtp, so I'm leaving this outside the switch until
4409	        // the appropriate place to look is cleared up.
4410	        if (stats.remoteId) {
4411	            const remote = findStatById(statsReport, stats.remoteId);
4412	            if (remote && remote.roundTripTime) {
4413	                sample.rtt = remote.roundTripTime * 1000;
4414	            }
4415	        }
4416	        switch (type) {
4417	            case 'inboundrtp':
4418	                sample.timestamp = sample.timestamp || stats.timestamp;
4419	                sample.jitter = stats.jitter * 1000;
4420	                sample.packetsLost = stats.packetsLost;
4421	                sample.packetsReceived = stats.packetsReceived;
4422	                sample.bytesReceived = stats.bytesReceived;
4423	                break;
4424	            case 'outboundrtp':
4425	                sample.timestamp = stats.timestamp;
4426	                sample.packetsSent = stats.packetsSent;
4427	                sample.bytesSent = stats.bytesSent;
4428	                if (stats.codecId) {
4429	                    const codec = findStatById(statsReport, stats.codecId);
4430	                    sample.codecName = codec
4431	                        ? codec.mimeType && codec.mimeType.match(/(.*\/)?(.*)/)[2]
4432	                        : stats.codecId;
4433	                }
4434	                break;
4435	            case 'transport':
4436	                activeTransportId = stats.id;
4437	                break;
4438	        }
4439	    });
4440	    if (!sample.timestamp) {
4441	        sample.timestamp = fallbackTimestamp;
4442	    }
4443	    const activeTransport = findStatById(statsReport, activeTransportId);
4444	    if (!activeTransport) {
4445	        return sample;
4446	    }
4447	    const selectedCandidatePair = findStatById(statsReport, activeTransport.selectedCandidatePairId);
4448	    if (!selectedCandidatePair) {
4449	        return sample;
4450	    }
4451	    const localCandidate = findStatById(statsReport, selectedCandidatePair.localCandidateId);
4452	    const remoteCandidate = findStatById(statsReport, selectedCandidatePair.remoteCandidateId);
4453	    if (!sample.rtt) {
4454	        sample.rtt = selectedCandidatePair &&
4455	            (selectedCandidatePair.currentRoundTripTime * 1000);
4456	    }
4457	    Object.assign(sample, {
4458	        // ip is deprecated. use address first then ip if on older versions of browser
4459	        localAddress: localCandidate && (localCandidate.address || localCandidate.ip),
4460	        remoteAddress: remoteCandidate && (remoteCandidate.address || remoteCandidate.ip),
4461	    });
4462	    return sample;
4463	}
4464
4465	/**
4466	 * Runs some tests to identify issues, if any, prohibiting successful calling.
4467	 */
4468	class PreflightTest extends eventsExports.EventEmitter {
4469	    /**
4470	     * Construct a {@link PreflightTest} instance.
4471	     * @param token - A Twilio JWT token string.
4472	     * @param options
4473	     */
4474	    constructor(token, options) {
4475	        super();
4476	        /**
4477	         * Whether this test has already logged an insights-connection-warning.
4478	         */
4479	        this._hasInsightsErrored = false;
4480	        /**
4481	         * An instance of Logger to use.
4482	         */
4483	        this._log = new Log('PreflightTest');
4484	        /**
4485	         * Network related timing measurements for this test
4486	         */
4487	        this._networkTiming = {};
4488	        /**
4489	         * The options passed to {@link PreflightTest} constructor
4490	         */
4491	        this._options = {
4492	            codecPreferences: [Call.Codec.PCMU, Call.Codec.Opus],
4493	            edge: 'roaming',
4494	            fakeMicInput: false,
4495	            logLevel: 'error',
4496	            signalingTimeoutMs: 10000,
4497	        };
4498	        /**
4499	         * Current status of this test
4500	         */
4501	        this._status = PreflightTest.Status.Connecting;
4502	        Object.assign(this._options, options);
4503	        this._samples = [];
4504	        this._warnings = [];
4505	        this._startTime = Date.now();
4506	        this._initDevice(token, Object.assign(Object.assign({}, this._options), { fileInputStream: this._options.fakeMicInput ?
4507	                this._getStreamFromFile() : undefined }));
4508	        // Device sets the loglevel so start logging after initializing the device.
4509	        // Then selectively log options that users can modify.
4510	        const userOptions = [
4511	            'codecPreferences',
4512	            'edge',
4513	            'fakeMicInput',
4514	            'logLevel',
4515	            'signalingTimeoutMs',
4516	        ];
4517	        const userOptionOverrides = [
4518	            'audioContext',
4519	            'deviceFactory',
4520	            'fileInputStream',
4521	            'getRTCIceCandidateStatsReport',
4522	            'iceServers',
4523	            'rtcConfiguration',
4524	        ];
4525	        if (typeof options === 'object') {
4526	            const toLog = Object.assign({}, options);
4527	            Object.keys(toLog).forEach((key) => {
4528	                if (!userOptions.includes(key) && !userOptionOverrides.includes(key)) {
4529	                    delete toLog[key];
4530	                }
4531	                if (userOptionOverrides.includes(key)) {
4532	                    toLog[key] = true;
4533	                }
4534	            });
4535	            this._log.debug('.constructor', JSON.stringify(toLog));
4536	        }
4537	    }
4538	    /**
4539	     * Stops the current test and raises a failed event.
4540	     */
4541	    stop() {
4542	        this._log.debug('.stop');
4543	        const error = new GeneralErrors.CallCancelledError();
4544	        if (this._device) {
4545	            this._device.once(Device.EventName.Unregistered, () => this._onFailed(error));
4546	            this._device.destroy();
4547	        }
4548	        else {
4549	            this._onFailed(error);
4550	        }
4551	    }
4552	    /**
4553	     * Emit a {PreflightTest.Warning}
4554	     */
4555	    _emitWarning(name, description, rtcWarning) {
4556	        const warning = { name, description };
4557	        if (rtcWarning) {
4558	            warning.rtcWarning = rtcWarning;
4559	        }
4560	        this._warnings.push(warning);
4561	        this._log.debug(`#${PreflightTest.Events.Warning}`, JSON.stringify(warning));
4562	        this.emit(PreflightTest.Events.Warning, warning);
4563	    }
4564	    /**
4565	     * Returns call quality base on the RTC Stats
4566	     */
4567	    _getCallQuality(mos) {
4568	        if (mos > 4.2) {
4569	            return PreflightTest.CallQuality.Excellent;
4570	        }
4571	        else if (mos >= 4.1 && mos <= 4.2) {
4572	            return PreflightTest.CallQuality.Great;
4573	        }
4574	        else if (mos >= 3.7 && mos <= 4) {
4575	            return PreflightTest.CallQuality.Good;
4576	        }
4577	        else if (mos >= 3.1 && mos <= 3.6) {
4578	            return PreflightTest.CallQuality.Fair;
4579	        }
4580	        else {
4581	            return PreflightTest.CallQuality.Degraded;
4582	        }
4583	    }
4584	    /**
4585	     * Returns the report for this test.
4586	     */
4587	    _getReport() {
4588	        var _a, _b, _c;
4589	        const stats = this._getRTCStats();
4590	        const testTiming = { start: this._startTime };
4591	        if (this._endTime) {
4592	            testTiming.end = this._endTime;
4593	            testTiming.duration = this._endTime - this._startTime;
4594	        }
4595	        const report = {
4596	            callSid: this._callSid,
4597	            edge: this._edge,
4598	            iceCandidateStats: (_b = (_a = this._rtcIceCandidateStatsReport) === null || _a === void 0 ? void 0 : _a.iceCandidateStats) !== null && _b !== void 0 ? _b : [],
4599	            networkTiming: this._networkTiming,
4600	            samples: this._samples,
4601	            selectedEdge: this._options.edge,
4602	            stats,
4603	            testTiming,
4604	            totals: this._getRTCSampleTotals(),
4605	            warnings: this._warnings,
4606	        };
4607	        const selectedIceCandidatePairStats = (_c = this._rtcIceCandidateStatsReport) === null || _c === void 0 ? void 0 : _c.selectedIceCandidatePairStats;
4608	        if (selectedIceCandidatePairStats) {
4609	            report.selectedIceCandidatePairStats = selectedIceCandidatePairStats;
4610	            report.isTurnRequired = selectedIceCandidatePairStats.localCandidate.candidateType === 'relay'
4611	                || selectedIceCandidatePairStats.remoteCandidate.candidateType === 'relay';
4612	        }
4613	        if (stats) {
4614	            report.callQuality = this._getCallQuality(stats.mos.average);
4615	        }
4616	        return report;
4617	    }
4618	    /**
4619	     * Returns RTC stats totals for this test
4620	     */
4621	    _getRTCSampleTotals() {
4622	        if (!this._latestSample) {
4623	            return;
4624	        }
4625	        return Object.assign({}, this._latestSample.totals);
4626	    }
4627	    /**
4628	     * Returns RTC related stats captured during the test call
4629	     */
4630	    _getRTCStats() {
4631	        const firstMosSampleIdx = this._samples.findIndex(sample => typeof sample.mos === 'number' && sample.mos > 0);
4632	        const samples = firstMosSampleIdx >= 0
4633	            ? this._samples.slice(firstMosSampleIdx)
4634	            : [];
4635	        if (!samples || !samples.length) {
4636	            return;
4637	        }
4638	        return ['jitter', 'mos', 'rtt'].reduce((statObj, stat) => {
4639	            const values = samples.map(s => s[stat]);
4640	            return Object.assign(Object.assign({}, statObj), { [stat]: {
4641	                    average: Number((values.reduce((total, value) => total + value) / values.length).toPrecision(5)),
4642	                    max: Math.max(...values),
4643	                    min: Math.min(...values),
4644	                } });
4645	        }, {});
4646	    }
4647	    /**
4648	     * Returns a MediaStream from a media file
4649	     */
4650	    _getStreamFromFile() {
4651	        const audioContext = this._options.audioContext;
4652	        if (!audioContext) {
4653	            throw new NotSupportedError('Cannot fake input audio stream: AudioContext is not supported by this browser.');
4654	        }
4655	        const audioEl = new Audio(COWBELL_AUDIO_URL);
4656	        audioEl.addEventListener('canplaythrough', () => audioEl.play());
4657	        if (typeof audioEl.setAttribute === 'function') {
4658	            audioEl.setAttribute('crossorigin', 'anonymous');
4659	        }
4660	        const src = audioContext.createMediaElementSource(audioEl);
4661	        const dest = audioContext.createMediaStreamDestination();
4662	        src.connect(dest);
4663	        return dest.stream;
4664	    }
4665	    /**
4666	     * Initialize the device
4667	     */
4668	    _initDevice(token, options) {
4669	        try {
4670	            this._device = new (options.deviceFactory || Device)(token, {
4671	                chunderw: options.chunderw,
4672	                codecPreferences: options.codecPreferences,
4673	                edge: options.edge,
4674	                eventgw: options.eventgw,
4675	                fileInputStream: options.fileInputStream,
4676	                logLevel: options.logLevel,
4677	                preflight: true,
4678	            });
4679	            this._device.once(Device.EventName.Registered, () => {
4680	                this._onDeviceRegistered();
4681	            });
4682	            this._device.once(Device.EventName.Error, (error) => {
4683	                this._onDeviceError(error);
4684	            });
4685	            this._device.register();
4686	        }
4687	        catch (error) {
4688	            // We want to return before failing so the consumer can capture the event
4689	            setTimeout(() => {
4690	                this._onFailed(error);
4691	            });
4692	            return;
4693	        }
4694	        this._signalingTimeoutTimer = setTimeout(() => {
4695	            this._onDeviceError(new SignalingErrors.ConnectionError('WebSocket Connection Timeout'));
4696	        }, options.signalingTimeoutMs);
4697	    }
4698	    /**
4699	     * Called on {@link Device} error event
4700	     * @param error
4701	     */
4702	    _onDeviceError(error) {
4703	        this._device.destroy();
4704	        this._onFailed(error);
4705	    }
4706	    /**
4707	     * Called on {@link Device} ready event
4708	     */
4709	    _onDeviceRegistered() {
4710	        return __awaiter(this, void 0, void 0, function* () {
4711	            clearTimeout(this._echoTimer);
4712	            clearTimeout(this._signalingTimeoutTimer);
4713	            this._call = yield this._device.connect({
4714	                rtcConfiguration: this._options.rtcConfiguration,
4715	            });
4716	            this._networkTiming.signaling = { start: Date.now() };
4717	            this._setupCallHandlers(this._call);
4718	            this._edge = this._device.edge || undefined;
4719	            if (this._options.fakeMicInput) {
4720	                this._echoTimer = setTimeout(() => this._device.disconnectAll(), ECHO_TEST_DURATION);
4721	                const audio = this._device.audio;
4722	                if (audio) {
4723	                    audio.disconnect(false);
4724	                    audio.outgoing(false);
4725	                }
4726	            }
4727	            this._call.once('disconnect', () => {
4728	                this._device.once(Device.EventName.Unregistered, () => this._onUnregistered());
4729	                this._device.destroy();
4730	            });
4731	            const publisher = this._call['_publisher'];
4732	            publisher.on('error', () => {
4733	                if (!this._hasInsightsErrored) {
4734	                    this._emitWarning('insights-connection-error', 'Received an error when attempting to connect to Insights gateway');
4735	                }
4736	                this._hasInsightsErrored = true;
4737	            });
4738	        });
4739	    }
4740	    /**
4741	     * Called when there is a fatal error
4742	     * @param error
4743	     */
4744	    _onFailed(error) {
4745	        clearTimeout(this._echoTimer);
4746	        clearTimeout(this._signalingTimeoutTimer);
4747	        this._releaseHandlers();
4748	        this._endTime = Date.now();
4749	        this._status = PreflightTest.Status.Failed;
4750	        this._log.debug(`#${PreflightTest.Events.Failed}`, error);
4751	        this.emit(PreflightTest.Events.Failed, error);
4752	    }
4753	    /**
4754	     * Called when the device goes offline.
4755	     * This indicates that the test has been completed, but we won't know if it failed or not.
4756	     * The onError event will be the indicator whether the test failed.
4757	     */
4758	    _onUnregistered() {
4759	        // We need to make sure we always execute preflight.on('completed') last
4760	        // as client SDK sometimes emits 'offline' event before emitting fatal errors.
4761	        setTimeout(() => {
4762	            if (this._status === PreflightTest.Status.Failed) {
4763	                return;
4764	            }
4765	            clearTimeout(this._echoTimer);
4766	            clearTimeout(this._signalingTimeoutTimer);
4767	            this._releaseHandlers();
4768	            this._endTime = Date.now();
4769	            this._status = PreflightTest.Status.Completed;
4770	            this._report = this._getReport();
4771	            this._log.debug(`#${PreflightTest.Events.Completed}`, JSON.stringify(this._report));
4772	            this.emit(PreflightTest.Events.Completed, this._report);
4773	        }, 10);
4774	    }
4775	    /**
4776	     * Clean up all handlers for device and call
4777	     */
4778	    _releaseHandlers() {
4779	        [this._device, this._call].forEach((emitter) => {
4780	            if (emitter) {
4781	                emitter.eventNames().forEach((name) => emitter.removeAllListeners(name));
4782	            }
4783	        });
4784	    }
4785	    /**
4786	     * Setup the event handlers for the {@link Call} of the test call
4787	     * @param call
4788	     */
4789	    _setupCallHandlers(call) {
4790	        if (this._options.fakeMicInput) {
4791	            // When volume events start emitting, it means all audio outputs have been created.
4792	            // Let's mute them if we're using fake mic input.
4793	            call.once('volume', () => {
4794	                call['_mediaHandler'].outputs
4795	                    .forEach((output) => output.audio.muted = true);
4796	            });
4797	        }
4798	        call.on('warning', (name, data) => {
4799	            this._emitWarning(name, 'Received an RTCWarning. See .rtcWarning for the RTCWarning', data);
4800	        });
4801	        call.once('accept', () => {
4802	            this._callSid = call['_mediaHandler'].callSid;
4803	            this._status = PreflightTest.Status.Connected;
4804	            this._log.debug(`#${PreflightTest.Events.Connected}`);
4805	            this.emit(PreflightTest.Events.Connected);
4806	        });
4807	        call.on('sample', (sample) => __awaiter(this, void 0, void 0, function* () {
4808	            // RTC Stats are ready. We only need to get ICE candidate stats report once.
4809	            if (!this._latestSample) {
4810	                this._rtcIceCandidateStatsReport = yield (this._options.getRTCIceCandidateStatsReport || getRTCIceCandidateStatsReport)(call['_mediaHandler'].version.pc);
4811	            }
4812	            this._latestSample = sample;
4813	            this._samples.push(sample);
4814	            this._log.debug(`#${PreflightTest.Events.Sample}`, JSON.stringify(sample));
4815	            this.emit(PreflightTest.Events.Sample, sample);
4816	        }));
4817	        // TODO: Update the following once the SDK supports emitting these events
4818	        // Let's shim for now
4819	        [{
4820	                reportLabel: 'peerConnection',
4821	                type: 'pcconnection',
4822	            }, {
4823	                reportLabel: 'ice',
4824	                type: 'iceconnection',
4825	            }, {
4826	                reportLabel: 'dtls',
4827	                type: 'dtlstransport',
4828	            }, {
4829	                reportLabel: 'signaling',
4830	                type: 'signaling',
4831	            }].forEach(({ type, reportLabel }) => {
4832	            const handlerName = `on${type}statechange`;
4833	            const originalHandler = call['_mediaHandler'][handlerName];
4834	            call['_mediaHandler'][handlerName] = (state) => {
4835	                const timing = this._networkTiming[reportLabel]
4836	                    = this._networkTiming[reportLabel] || { start: 0 };
4837	                if (state === 'connecting' || state === 'checking') {
4838	                    timing.start = Date.now();
4839	                }
4840	                else if ((state === 'connected' || state === 'stable') && !timing.duration) {
4841	                    timing.end = Date.now();
4842	                    timing.duration = timing.end - timing.start;
4843	                }
4844	                originalHandler(state);
4845	            };
4846	        });
4847	    }
4848	    /**
4849	     * The callsid generated for the test call.
4850	     */
4851	    get callSid() {
4852	        return this._callSid;
4853	    }
4854	    /**
4855	     * A timestamp in milliseconds of when the test ended.
4856	     */
4857	    get endTime() {
4858	        return this._endTime;
4859	    }
4860	    /**
4861	     * The latest WebRTC sample collected.
4862	     */
4863	    get latestSample() {
4864	        return this._latestSample;
4865	    }
4866	    /**
4867	     * The report for this test.
4868	     */
4869	    get report() {
4870	        return this._report;
4871	    }
4872	    /**
4873	     * A timestamp in milliseconds of when the test started.
4874	     */
4875	    get startTime() {
4876	        return this._startTime;
4877	    }
4878	    /**
4879	     * The status of the test.
4880	     */
4881	    get status() {
4882	        return this._status;
4883	    }
4884	}
4885	/**
4886	 * @mergeModuleWith PreflightTest
4887	 */
4888	(function (PreflightTest) {
4889	    (function (CallQuality) {
4890	        /**
4891	         * If the average mos is over 4.2.
4892	         */
4893	        CallQuality["Excellent"] = "excellent";
4894	        /**
4895	         * If the average mos is between 4.1 and 4.2 both inclusive.
4896	         */
4897	        CallQuality["Great"] = "great";
4898	        /**
4899	         * If the average mos is between 3.7 and 4.0 both inclusive.
4900	         */
4901	        CallQuality["Good"] = "good";
4902	        /**
4903	         * If the average mos is between 3.1 and 3.6 both inclusive.
4904	         */
4905	        CallQuality["Fair"] = "fair";
4906	        /**
4907	         * If the average mos is 3.0 or below.
4908	         */
4909	        CallQuality["Degraded"] = "degraded";
4910	    })(PreflightTest.CallQuality || (PreflightTest.CallQuality = {}));
4911	    (function (Events) {
4912	        /**
4913	         * See [[PreflightTest.completedEvent]]
4914	         */
4915	        Events["Completed"] = "completed";
4916	        /**
4917	         * See [[PreflightTest.connectedEvent]]
4918	         */
4919	        Events["Connected"] = "connected";
4920	        /**
4921	         * See [[PreflightTest.failedEvent]]
4922	         */
4923	        Events["Failed"] = "failed";
4924	        /**
4925	         * See [[PreflightTest.sampleEvent]]
4926	         */
4927	        Events["Sample"] = "sample";
4928	        /**
4929	         * See [[PreflightTest.warningEvent]]
4930	         */
4931	        Events["Warning"] = "warning";
4932	    })(PreflightTest.Events || (PreflightTest.Events = {}));
4933	    (function (Status) {
4934	        /**
4935	         * Call to Twilio has initiated.
4936	         */
4937	        Status["Connecting"] = "connecting";
4938	        /**
4939	         * Call to Twilio has been established.
4940	         */
4941	        Status["Connected"] = "connected";
4942	        /**
4943	         * The connection to Twilio has been disconnected and the test call has completed.
4944	         */
4945	        Status["Completed"] = "completed";
4946	        /**
4947	         * The test has stopped and failed.
4948	         */
4949	        Status["Failed"] = "failed";
4950	    })(PreflightTest.Status || (PreflightTest.Status = {}));
4951	})(PreflightTest || (PreflightTest = {}));
4952
4953	const WebSocket = globalThis.WebSocket;
4954	const CONNECT_SUCCESS_TIMEOUT = 10000;
4955	const CONNECT_TIMEOUT = 5000;
4956	const HEARTBEAT_TIMEOUT = 15000;
4957	const MAX_PREFERRED_DURATION = 15000;
4958	const MAX_PRIMARY_DURATION = Infinity;
4959	const MAX_PREFERRED_DELAY = 1000;
4960	const MAX_PRIMARY_DELAY = 20000;
4961	/**
4962	 * All possible states of WSTransport.
4963	 */
4964	var WSTransportState;
4965	(function (WSTransportState) {
4966	    /**
4967	     * The WebSocket is not open but is trying to connect.
4968	     */
4969	    WSTransportState["Connecting"] = "connecting";
4970	    /**
4971	     * The WebSocket is not open and is not trying to connect.
4972	     */
4973	    WSTransportState["Closed"] = "closed";
4974	    /**
4975	     * The underlying WebSocket is open and active.
4976	     */
4977	    WSTransportState["Open"] = "open";
4978	})(WSTransportState || (WSTransportState = {}));
4979	/**
4980	 * WebSocket Transport
4981	 */
4982	class WSTransport extends eventsExports.EventEmitter {
4983	    /**
4984	     * @constructor
4985	     * @param uris - List of URI of the endpoints to connect to.
4986	     * @param [options] - Constructor options.
4987	     */
4988	    constructor(uris, options = {}) {
4989	        super();
4990	        /**
4991	         * The current state of the WSTransport.
4992	         */
4993	        this.state = WSTransportState.Closed;
4994	        /**
4995	         * Start timestamp values for backoffs.
4996	         */
4997	        this._backoffStartTime = {
4998	            preferred: null,
4999	            primary: null,
5000	        };
5001	        /**
5002	         * The URI that the transport is connecting or connected to. The value of this
5003	         * property is `null` if a connection attempt has not been made yet.
5004	         */
5005	        this._connectedUri = null;
5006	        /**
5007	         * An instance of Logger to use.
5008	         */
5009	        this._log = new Log('WSTransport');
5010	        /**
5011	         * Whether we should attempt to fallback if we receive an applicable error
5012	         * when trying to connect to a signaling endpoint.
5013	         */
5014	        this._shouldFallback = false;
5015	        /**
5016	         * The current uri index that the transport is connected to.
5017	         */
5018	        this._uriIndex = 0;
5019	        /**
5020	         * Move the uri index to the next index
5021	         * If the index is at the end, the index goes back to the first one.
5022	         */
5023	        this._moveUriIndex = () => {
5024	            this._uriIndex++;
5025	            if (this._uriIndex >= this._uris.length) {
5026	                this._uriIndex = 0;
5027	            }
5028	        };
5029	        /**
5030	         * Called in response to WebSocket#close event.
5031	         */
5032	        this._onSocketClose = (event) => {
5033	            this._log.error(`Received websocket close event code: ${event.code}. Reason: ${event.reason}`);
5034	            // 1006: Abnormal close. When the server is unreacheable
5035	            // 1015: TLS Handshake error
5036	            if (event.code === 1006 || event.code === 1015) {
5037	                this.emit('error', {
5038	                    code: 31005,
5039	                    message: event.reason ||
5040	                        'Websocket connection to Twilio\'s signaling servers were ' +
5041	                            'unexpectedly ended. If this is happening consistently, there may ' +
5042	                            'be an issue resolving the hostname provided. If a region or an ' +
5043	                            'edge is being specified in Device setup, ensure it is valid.',
5044	                    twilioError: new SignalingErrors.ConnectionError(),
5045	                });
5046	                const wasConnected = (
5047	                // Only in Safari and certain Firefox versions, on network interruption, websocket drops right away with 1006
5048	                // Let's check current state if it's open, meaning we should not fallback
5049	                // because we're coming from a previously connected session
5050	                this.state === WSTransportState.Open ||
5051	                    // But on other browsers, websocket doesn't drop
5052	                    // but our heartbeat catches it, setting the internal state to "Connecting".
5053	                    // With this, we should check the previous state instead.
5054	                    this._previousState === WSTransportState.Open);
5055	                // Only fallback if this is not the first error
5056	                // and if we were not connected previously
5057	                if (this._shouldFallback || !wasConnected) {
5058	                    this._moveUriIndex();
5059	                }
5060	                this._shouldFallback = true;
5061	            }
5062	            this._closeSocket();
5063	        };
5064	        /**
5065	         * Called in response to WebSocket#error event.
5066	         */
5067	        this._onSocketError = (err) => {
5068	            this._log.error(`WebSocket received error: ${err.message}`);
5069	            this.emit('error', {
5070	                code: 31000,
5071	                message: err.message || 'WSTransport socket error',
5072	                twilioError: new SignalingErrors.ConnectionDisconnected(),
5073	            });
5074	        };
5075	        /**
5076	         * Called in response to WebSocket#message event.
5077	         */
5078	        this._onSocketMessage = (message) => {
5079	            // Clear heartbeat timeout on any incoming message, as they
5080	            // all indicate an active connection.
5081	            this._setHeartbeatTimeout();
5082	            // Filter and respond to heartbeats
5083	            if (this._socket && message.data === '\n') {
5084	                this._socket.send('\n');
5085	                this._log.debug('heartbeat');
5086	                return;
5087	            }
5088	            if (message && typeof message.data === 'string') {
5089	                this._log.debug(`Received: ${message.data}`);
5090	            }
5091	            this.emit('message', message);
5092	        };
5093	        /**
5094	         * Called in response to WebSocket#open event.
5095	         */
5096	        this._onSocketOpen = () => {
5097	            this._log.info('WebSocket opened successfully.');
5098	            this._timeOpened = Date.now();
5099	            this._shouldFallback = false;
5100	            this._setState(WSTransportState.Open);
5101	            clearTimeout(this._connectTimeout);
5102	            this._resetBackoffs();
5103	            this._setHeartbeatTimeout();
5104	            this.emit('open');
5105	        };
5106	        this._options = Object.assign(Object.assign({}, WSTransport.defaultConstructorOptions), options);
5107	        this._uris = uris;
5108	        this._backoff = this._setupBackoffs();
5109	    }
5110	    /**
5111	     * Close the WebSocket, and don't try to reconnect.
5112	     */
5113	    close() {
5114	        this._log.info('WSTransport.close() called...');
5115	        this._close();
5116	    }
5117	    /**
5118	     * Attempt to open a WebSocket connection.
5119	     */
5120	    open() {
5121	        this._log.info('WSTransport.open() called...');
5122	        if (this._socket &&
5123	            (this._socket.readyState === WebSocket.CONNECTING ||
5124	                this._socket.readyState === WebSocket.OPEN)) {
5125	            this._log.info('WebSocket already open.');
5126	            return;
5127	        }
5128	        if (this._preferredUri) {
5129	            this._connect(this._preferredUri);
5130	        }
5131	        else {
5132	            this._connect(this._uris[this._uriIndex]);
5133	        }
5134	    }
5135	    /**
5136	     * Send a message through the WebSocket connection.
5137	     * @param message - A message to send to the endpoint.
5138	     * @returns Whether the message was sent.
5139	     */
5140	    send(message) {
5141	        this._log.debug(`Sending: ${message}`);
5142	        // We can't send the message if the WebSocket isn't open
5143	        if (!this._socket || this._socket.readyState !== WebSocket.OPEN) {
5144	            this._log.debug('Cannot send message. WebSocket is not open.');
5145	            return false;
5146	        }
5147	        try {
5148	            this._socket.send(message);
5149	        }
5150	        catch (e) {
5151	            // Some unknown error occurred. Reset the socket to get a fresh session.
5152	            this._log.error('Error while sending message:', e.message);
5153	            this._closeSocket();
5154	            return false;
5155	        }
5156	        return true;
5157	    }
5158	    /**
5159	     * Update the preferred URI to connect to. Useful for Call signaling
5160	     * reconnection, which requires connecting on the same edge. If `null` is
5161	     * passed, the preferred URI is unset and the original `uris` array and
5162	     * `uriIndex` is used to determine the signaling URI to connect to.
5163	     * @param uri
5164	     */
5165	    updatePreferredURI(uri) {
5166	        this._preferredUri = uri;
5167	    }
5168	    /**
5169	     * Update acceptable URIs to reconnect to. Resets the URI index to 0.
5170	     */
5171	    updateURIs(uris) {
5172	        if (typeof uris === 'string') {
5173	            uris = [uris];
5174	        }
5175	        this._uris = uris;
5176	        this._uriIndex = 0;
5177	    }
5178	    /**
5179	     * Close the WebSocket, and don't try to reconnect.
5180	     */
5181	    _close() {
5182	        this._setState(WSTransportState.Closed);
5183	        this._closeSocket();
5184	    }
5185	    /**
5186	     * Close the WebSocket and remove all event listeners.
5187	     */
5188	    _closeSocket() {
5189	        clearTimeout(this._connectTimeout);
5190	        clearTimeout(this._heartbeatTimeout);
5191	        this._log.info('Closing and cleaning up WebSocket...');
5192	        if (!this._socket) {
5193	            this._log.info('No WebSocket to clean up.');
5194	            return;
5195	        }
5196	        this._socket.removeEventListener('close', this._onSocketClose);
5197	        this._socket.removeEventListener('error', this._onSocketError);
5198	        this._socket.removeEventListener('message', this._onSocketMessage);
5199	        this._socket.removeEventListener('open', this._onSocketOpen);
5200	        if (this._socket.readyState === WebSocket.CONNECTING ||
5201	            this._socket.readyState === WebSocket.OPEN) {
5202	            this._socket.close();
5203	        }
5204	        // Reset backoff counter if connection was open for long enough to be considered successful
5205	        if (this._timeOpened && Date.now() - this._timeOpened > CONNECT_SUCCESS_TIMEOUT) {
5206	            this._resetBackoffs();
5207	        }
5208	        if (this.state !== WSTransportState.Closed) {
5209	            this._performBackoff();
5210	        }
5211	        delete this._socket;
5212	        this.emit('close');
5213	    }
5214	    /**
5215	     * Attempt to connect to the endpoint via WebSocket.
5216	     * @param [uri] - URI string to connect to.
5217	     * @param [retryCount] - Retry number, if this is a retry. Undefined if
5218	     *   first attempt, 1+ if a retry.
5219	     */
5220	    _connect(uri, retryCount) {
5221	        this._log.info(typeof retryCount === 'number'
5222	            ? `Attempting to reconnect (retry #${retryCount})...`
5223	            : 'Attempting to connect...');
5224	        this._closeSocket();
5225	        this._setState(WSTransportState.Connecting);
5226	        this._connectedUri = uri;
5227	        try {
5228	            this._socket = new this._options.WebSocket(this._connectedUri);
5229	        }
5230	        catch (e) {
5231	            this._log.error('Could not connect to endpoint:', e.message);
5232	            this._close();
5233	            this.emit('error', {
5234	                code: 31000,
5235	                message: e.message || `Could not connect to ${this._connectedUri}`,
5236	                twilioError: new SignalingErrors.ConnectionDisconnected(),
5237	            });
5238	            return;
5239	        }
5240	        this._socket.addEventListener('close', this._onSocketClose);
5241	        this._socket.addEventListener('error', this._onSocketError);
5242	        this._socket.addEventListener('message', this._onSocketMessage);
5243	        this._socket.addEventListener('open', this._onSocketOpen);
5244	        delete this._timeOpened;
5245	        this._connectTimeout = setTimeout(() => {
5246	            this._log.info('WebSocket connection attempt timed out.');
5247	            this._moveUriIndex();
5248	            this._closeSocket();
5249	        }, this._options.connectTimeoutMs);
5250	    }
5251	    /**
5252	     * Perform a backoff. If a preferred URI is set (not null), then backoff
5253	     * using the preferred mechanism. Otherwise, use the primary mechanism.
5254	     */
5255	    _performBackoff() {
5256	        if (this._preferredUri) {
5257	            this._log.info('Preferred URI set; backing off.');
5258	            this._backoff.preferred.backoff();
5259	        }
5260	        else {
5261	            this._log.info('Preferred URI not set; backing off.');
5262	            this._backoff.primary.backoff();
5263	        }
5264	    }
5265	    /**
5266	     * Reset both primary and preferred backoff mechanisms.
5267	     */
5268	    _resetBackoffs() {
5269	        this._backoff.preferred.reset();
5270	        this._backoff.primary.reset();
5271	        this._backoffStartTime.preferred = null;
5272	        this._backoffStartTime.primary = null;
5273	    }
5274	    /**
5275	     * Set a timeout to reconnect after HEARTBEAT_TIMEOUT milliseconds
5276	     *   have passed without receiving a message over the WebSocket.
5277	     */
5278	    _setHeartbeatTimeout() {
5279	        clearTimeout(this._heartbeatTimeout);
5280	        this._heartbeatTimeout = setTimeout(() => {
5281	            this._log.info(`No messages received in ${HEARTBEAT_TIMEOUT / 1000} seconds. Reconnecting...`);
5282	            this._shouldFallback = true;
5283	            this._closeSocket();
5284	        }, HEARTBEAT_TIMEOUT);
5285	    }
5286	    /**
5287	     * Set the current and previous state
5288	     */
5289	    _setState(state) {
5290	        this._previousState = this.state;
5291	        this.state = state;
5292	    }
5293	    /**
5294	     * Set up the primary and preferred backoff mechanisms.
5295	     */
5296	    _setupBackoffs() {
5297	        const preferredBackoffConfig = {
5298	            factor: 2.0,
5299	            jitter: 0.40,
5300	            max: this._options.maxPreferredDelayMs,
5301	            min: 100,
5302	        };
5303	        this._log.info('Initializing preferred transport backoff using config: ', preferredBackoffConfig);
5304	        const preferredBackoff = new Backoff(preferredBackoffConfig);
5305	        preferredBackoff.on('backoff', (attempt, delay) => {
5306	            if (this.state === WSTransportState.Closed) {
5307	                this._log.info('Preferred backoff initiated but transport state is closed; not attempting a connection.');
5308	                return;
5309	            }
5310	            this._log.info(`Will attempt to reconnect Websocket to preferred URI in ${delay}ms`);
5311	            if (attempt === 0) {
5312	                this._backoffStartTime.preferred = Date.now();
5313	                this._log.info(`Preferred backoff start; ${this._backoffStartTime.preferred}`);
5314	            }
5315	        });
5316	        preferredBackoff.on('ready', (attempt, _delay) => {
5317	            if (this.state === WSTransportState.Closed) {
5318	                this._log.info('Preferred backoff ready but transport state is closed; not attempting a connection.');
5319	                return;
5320	            }
5321	            if (this._backoffStartTime.preferred === null) {
5322	                this._log.info('Preferred backoff start time invalid; not attempting a connection.');
5323	                return;
5324	            }
5325	            if (Date.now() - this._backoffStartTime.preferred > this._options.maxPreferredDurationMs) {
5326	                this._log.info('Max preferred backoff attempt time exceeded; falling back to primary backoff.');
5327	                this._preferredUri = null;
5328	                this._backoff.primary.backoff();
5329	                return;
5330	            }
5331	            if (typeof this._preferredUri !== 'string') {
5332	                this._log.info('Preferred URI cleared; falling back to primary backoff.');
5333	                this._preferredUri = null;
5334	                this._backoff.primary.backoff();
5335	                return;
5336	            }
5337	            this._connect(this._preferredUri, attempt + 1);
5338	        });
5339	        const primaryBackoffConfig = {
5340	            factor: 2.0,
5341	            jitter: 0.40,
5342	            max: this._options.maxPrimaryDelayMs,
5343	            // We only want a random initial delay if there are any fallback edges
5344	            // Initial delay between 1s and 5s both inclusive
5345	            min: this._uris && this._uris.length > 1
5346	                ? Math.floor(Math.random() * (5000 - 1000 + 1)) + 1000
5347	                : 100,
5348	        };
5349	        this._log.info('Initializing primary transport backoff using config: ', primaryBackoffConfig);
5350	        const primaryBackoff = new Backoff(primaryBackoffConfig);
5351	        primaryBackoff.on('backoff', (attempt, delay) => {
5352	            if (this.state === WSTransportState.Closed) {
5353	                this._log.info('Primary backoff initiated but transport state is closed; not attempting a connection.');
5354	                return;
5355	            }
5356	            this._log.info(`Will attempt to reconnect WebSocket in ${delay}ms`);
5357	            if (attempt === 0) {
5358	                this._backoffStartTime.primary = Date.now();
5359	                this._log.info(`Primary backoff start; ${this._backoffStartTime.primary}`);
5360	            }
5361	        });
5362	        primaryBackoff.on('ready', (attempt, _delay) => {
5363	            if (this.state === WSTransportState.Closed) {
5364	                this._log.info('Primary backoff ready but transport state is closed; not attempting a connection.');
5365	                return;
5366	            }
5367	            if (this._backoffStartTime.primary === null) {
5368	                this._log.info('Primary backoff start time invalid; not attempting a connection.');
5369	                return;
5370	            }
5371	            if (Date.now() - this._backoffStartTime.primary > this._options.maxPrimaryDurationMs) {
5372	                this._log.info('Max primary backoff attempt time exceeded; not attempting a connection.');
5373	                return;
5374	            }
5375	            this._connect(this._uris[this._uriIndex], attempt + 1);
5376	        });
5377	        return {
5378	            preferred: preferredBackoff,
5379	            primary: primaryBackoff,
5380	        };
5381	    }
5382	    /**
5383	     * The uri the transport is currently connected to
5384	     */
5385	    get uri() {
5386	        return this._connectedUri;
5387	    }
5388	}
5389	WSTransport.defaultConstructorOptions = {
5390	    WebSocket,
5391	    connectTimeoutMs: CONNECT_TIMEOUT,
5392	    maxPreferredDelayMs: MAX_PREFERRED_DELAY,
5393	    maxPreferredDurationMs: MAX_PREFERRED_DURATION,
5394	    maxPrimaryDelayMs: MAX_PRIMARY_DELAY,
5395	    maxPrimaryDurationMs: MAX_PRIMARY_DURATION,
5396	};
5397
5398	// @ts-nocheck
5399	const PSTREAM_VERSION = '1.6';
5400	// In seconds
5401	const MAX_RECONNECT_TIMEOUT_ALLOWED = 30;
5402	/**
5403	 * Constructor for PStream objects.
5404	 *
5405	 * @exports PStream as Twilio.PStream
5406	 * @memberOf Twilio
5407	 * @borrows EventEmitter#addListener as #addListener
5408	 * @borrows EventEmitter#removeListener as #removeListener
5409	 * @borrows EventEmitter#emit as #emit
5410	 * @borrows EventEmitter#hasListener as #hasListener
5411	 * @constructor
5412	 * @param {string} token The Twilio capabilities JWT
5413	 * @param {string[]} uris An array of PStream endpoint URIs
5414	 * @param {object} [options]
5415	 * @config {boolean} [options.backoffMaxMs=20000] Enable debugging
5416	 */
5417	class PStream extends eventsExports.EventEmitter {
5418	    constructor(token, uris, options) {
5419	        super();
5420	        if (!(this instanceof PStream)) {
5421	            return new PStream(token, uris, options);
5422	        }
5423	        const defaults = {
5424	            TransportFactory: WSTransport,
5425	        };
5426	        options = options || {};
5427	        for (const prop in defaults) {
5428	            if (prop in options) {
5429	                continue;
5430	            }
5431	            options[prop] = defaults[prop];
5432	        }
5433	        this.options = options;
5434	        this.token = token || '';
5435	        this.status = 'disconnected';
5436	        this.gateway = null;
5437	        this.region = null;
5438	        this._messageQueue = [];
5439	        this._preferredUri = null;
5440	        this._uris = uris;
5441	        this._handleTransportClose = this._handleTransportClose.bind(this);
5442	        this._handleTransportError = this._handleTransportError.bind(this);
5443	        this._handleTransportMessage = this._handleTransportMessage.bind(this);
5444	        this._handleTransportOpen = this._handleTransportOpen.bind(this);
5445	        this._log = new Log('PStream');
5446	        // NOTE(mroberts): EventEmitter requires that we catch all errors.
5447	        this.on('error', () => {
5448	            this._log.warn('Unexpected error handled in pstream');
5449	        });
5450	        /*
5451	         *events used by device
5452	         *'invite',
5453	         *'ready',
5454	         *'error',
5455	         *'offline',
5456	         *
5457	         *'cancel',
5458	         *'presence',
5459	         *'roster',
5460	         *'answer',
5461	         *'candidate',
5462	         *'hangup'
5463	         */
5464	        const self = this;
5465	        this.addListener('ready', () => {
5466	            self.status = 'ready';
5467	        });
5468	        this.addListener('offline', () => {
5469	            self.status = 'offline';
5470	        });
5471	        this.addListener('close', () => {
5472	            self._log.info('Received "close" from server. Destroying PStream...');
5473	            self._destroy();
5474	        });
5475	        this.transport = new this.options.TransportFactory(this._uris, {
5476	            backoffMaxMs: this.options.backoffMaxMs,
5477	            maxPreferredDurationMs: this.options.maxPreferredDurationMs,
5478	        });
5479	        Object.defineProperties(this, {
5480	            uri: {
5481	                enumerable: true,
5482	                get() {
5483	                    return this.transport.uri;
5484	                },
5485	            },
5486	        });
5487	        this.transport.on('close', this._handleTransportClose);
5488	        this.transport.on('error', this._handleTransportError);
5489	        this.transport.on('message', this._handleTransportMessage);
5490	        this.transport.on('open', this._handleTransportOpen);
5491	        this.transport.open();
5492	        return this;
5493	    }
5494	}
5495	PStream.prototype._handleTransportClose = function () {
5496	    this.emit('transportClose');
5497	    if (this.status !== 'disconnected') {
5498	        if (this.status !== 'offline') {
5499	            this.emit('offline', this);
5500	        }
5501	        this.status = 'disconnected';
5502	    }
5503	};
5504	PStream.prototype._handleTransportError = function (error) {
5505	    if (!error) {
5506	        this.emit('error', { error: {
5507	                code: 31000,
5508	                message: 'Websocket closed without a provided reason',
5509	                twilioError: new SignalingErrors.ConnectionDisconnected(),
5510	            } });
5511	        return;
5512	    }
5513	    // We receive some errors without call metadata (just the error). We need to convert these
5514	    // to be contained within the 'error' field so that these errors match the expected format.
5515	    this.emit('error', typeof error.code !== 'undefined' ? { error } : error);
5516	};
5517	PStream.prototype._handleTransportMessage = function (msg) {
5518	    if (!msg || !msg.data || typeof msg.data !== 'string') {
5519	        return;
5520	    }
5521	    const { type, payload = {} } = JSON.parse(msg.data);
5522	    this.gateway = payload.gateway || this.gateway;
5523	    this.region = payload.region || this.region;
5524	    if (type === 'error' && payload.error) {
5525	        payload.error.twilioError = new SignalingErrors.ConnectionError();
5526	    }
5527	    this.emit(type, payload);
5528	};
5529	PStream.prototype._handleTransportOpen = function () {
5530	    this.status = 'connected';
5531	    this.setToken(this.token);
5532	    this.emit('transportOpen');
5533	    const messages = this._messageQueue.splice(0, this._messageQueue.length);
5534	    messages.forEach(message => this._publish(...message));
5535	};
5536	/**
5537	 * @return {string}
5538	 */
5539	PStream.toString = () => '[Twilio.PStream class]';
5540	PStream.prototype.toString = () => '[Twilio.PStream instance]';
5541	PStream.prototype.setToken = function (token) {
5542	    this._log.info('Setting token and publishing listen');
5543	    this.token = token;
5544	    let reconnectTimeout = 0;
5545	    const t = this.options.maxPreferredDurationMs;
5546	    this._log.info(`maxPreferredDurationMs:${t}`);
5547	    if (typeof t === 'number' && t >= 0) {
5548	        reconnectTimeout = Math.min(Math.ceil(t / 1000), MAX_RECONNECT_TIMEOUT_ALLOWED);
5549	    }
5550	    this._log.info(`reconnectTimeout:${reconnectTimeout}`);
5551	    const payload = {
5552	        browserinfo: getBrowserInfo(),
5553	        reconnectTimeout,
5554	        token,
5555	    };
5556	    this._publish('listen', payload);
5557	};
5558	PStream.prototype.sendMessage = function (callsid, content, contenttype = 'application/json', messagetype, voiceeventsid) {
5559	    const payload = {
5560	        callsid,
5561	        content,
5562	        contenttype,
5563	        messagetype,
5564	        voiceeventsid,
5565	    };
5566	    this._publish('message', payload, true);
5567	};
5568	PStream.prototype.register = function (mediaCapabilities) {
5569	    const regPayload = { media: mediaCapabilities };
5570	    this._publish('register', regPayload, true);
5571	};
5572	PStream.prototype.invite = function (sdp, callsid, params) {
5573	    const payload = {
5574	        callsid,
5575	        sdp,
5576	        twilio: params ? { params } : {},
5577	    };
5578	    this._publish('invite', payload, true);
5579	};
5580	PStream.prototype.reconnect = function (sdp, callsid, reconnect) {
5581	    const payload = {
5582	        callsid,
5583	        reconnect,
5584	        sdp,
5585	        twilio: {},
5586	    };
5587	    this._publish('invite', payload, true);
5588	};
5589	PStream.prototype.answer = function (sdp, callsid) {
5590	    this._publish('answer', { sdp, callsid }, true);
5591	};
5592	PStream.prototype.dtmf = function (callsid, digits) {
5593	    this._publish('dtmf', { callsid, dtmf: digits }, true);
5594	};
5595	PStream.prototype.hangup = function (callsid, message) {
5596	    const payload = message ? { callsid, message } : { callsid };
5597	    this._publish('hangup', payload, true);
5598	};
5599	PStream.prototype.reject = function (callsid) {
5600	    this._publish('reject', { callsid }, true);
5601	};
5602	PStream.prototype.reinvite = function (sdp, callsid) {
5603	    this._publish('reinvite', { sdp, callsid }, false);
5604	};
5605	PStream.prototype._destroy = function () {
5606	    this.transport.removeListener('close', this._handleTransportClose);
5607	    this.transport.removeListener('error', this._handleTransportError);
5608	    this.transport.removeListener('message', this._handleTransportMessage);
5609	    this.transport.removeListener('open', this._handleTransportOpen);
5610	    this.transport.close();
5611	    this.emit('offline', this);
5612	};
5613	PStream.prototype.destroy = function () {
5614	    this._log.info('PStream.destroy() called...');
5615	    this._destroy();
5616	    return this;
5617	};
5618	PStream.prototype.updatePreferredURI = function (uri) {
5619	    this._preferredUri = uri;
5620	    this.transport.updatePreferredURI(uri);
5621	};
5622	PStream.prototype.updateURIs = function (uris) {
5623	    this._uris = uris;
5624	    this.transport.updateURIs(this._uris);
5625	};
5626	PStream.prototype.publish = function (type, payload) {
5627	    return this._publish(type, payload, true);
5628	};
5629	PStream.prototype._publish = function (type, payload, shouldRetry) {
5630	    const msg = JSON.stringify({
5631	        payload,
5632	        type,
5633	        version: PSTREAM_VERSION,
5634	    });
5635	    const isSent = !!this.transport.send(msg);
5636	    if (!isSent) {
5637	        this.emit('error', { error: {
5638	                code: 31009,
5639	                message: 'No transport available to send or receive messages',
5640	                twilioError: new GeneralErrors.TransportError(),
5641	            } });
5642	        if (shouldRetry) {
5643	            this._messageQueue.push([type, payload, true]);
5644	        }
5645	    }
5646	};
5647	function getBrowserInfo() {
5648	    const nav = typeof navigator !== 'undefined' ? navigator : {};
5649	    const info = {
5650	        browser: {
5651	            platform: nav.platform || 'unknown',
5652	            userAgent: nav.userAgent || 'unknown',
5653	        },
5654	        p: 'browser',
5655	        plugin: 'rtc',
5656	        v: RELEASE_VERSION,
5657	    };
5658	    return info;
5659	}
5660
5661	/**
5662	 * Valid edges.
5663	 */
5664	var Edge;
5665	(function (Edge) {
5666	    /**
5667	     * Public edges
5668	     */
5669	    Edge["Sydney"] = "sydney";
5670	    Edge["SaoPaulo"] = "sao-paulo";
5671	    Edge["Dublin"] = "dublin";
5672	    Edge["Frankfurt"] = "frankfurt";
5673	    Edge["Tokyo"] = "tokyo";
5674	    Edge["Singapore"] = "singapore";
5675	    Edge["Ashburn"] = "ashburn";
5676	    Edge["Umatilla"] = "umatilla";
5677	    Edge["Roaming"] = "roaming";
5678	    /**
5679	     * Interconnect edges
5680	     */
5681	    Edge["AshburnIx"] = "ashburn-ix";
5682	    Edge["SanJoseIx"] = "san-jose-ix";
5683	    Edge["LondonIx"] = "london-ix";
5684	    Edge["FrankfurtIx"] = "frankfurt-ix";
5685	    Edge["SingaporeIx"] = "singapore-ix";
5686	    Edge["SydneyIx"] = "sydney-ix";
5687	    Edge["TokyoIx"] = "tokyo-ix";
5688	})(Edge || (Edge = {}));
5689	/**
5690	 * Valid current regions.
5691	 *
5692	 * @deprecated
5693	 *
5694	 * CLIENT-6831
5695	 * This is no longer used or updated for checking validity of regions in the
5696	 * SDK. We now allow any string to be passed for region. Invalid regions won't
5697	 * be able to connect, and won't throw an exception.
5698	 *
5699	 * CLIENT-7519
5700	 * This is used again to temporarily convert edge values to regions as part of
5701	 * Phase 1 Regional. This is still considered deprecated.
5702	 *
5703	 * @private
5704	 */
5705	var Region;
5706	(function (Region) {
5707	    Region["Au1"] = "au1";
5708	    Region["Au1Ix"] = "au1-ix";
5709	    Region["Br1"] = "br1";
5710	    Region["De1"] = "de1";
5711	    Region["De1Ix"] = "de1-ix";
5712	    Region["Gll"] = "gll";
5713	    Region["Ie1"] = "ie1";
5714	    Region["Ie1Ix"] = "ie1-ix";
5715	    Region["Ie1Tnx"] = "ie1-tnx";
5716	    Region["Jp1"] = "jp1";
5717	    Region["Jp1Ix"] = "jp1-ix";
5718	    Region["Sg1"] = "sg1";
5719	    Region["Sg1Ix"] = "sg1-ix";
5720	    Region["Sg1Tnx"] = "sg1-tnx";
5721	    Region["Us1"] = "us1";
5722	    Region["Us1Ix"] = "us1-ix";
5723	    Region["Us1Tnx"] = "us1-tnx";
5724	    Region["Us2"] = "us2";
5725	    Region["Us2Ix"] = "us2-ix";
5726	    Region["Us2Tnx"] = "us2-tnx";
5727	})(Region || (Region = {}));
5728	/**
5729	 * Region shortcodes. Maps the full region name from AWS to the Twilio shortcode.
5730	 * @private
5731	 */
5732	const regionShortcodes = {
5733	    ASIAPAC_SINGAPORE: Region.Sg1,
5734	    ASIAPAC_SYDNEY: Region.Au1,
5735	    ASIAPAC_TOKYO: Region.Jp1,
5736	    EU_FRANKFURT: Region.De1,
5737	    EU_IRELAND: Region.Ie1,
5738	    SOUTH_AMERICA_SAO_PAULO: Region.Br1,
5739	    US_EAST_VIRGINIA: Region.Us1,
5740	    US_WEST_OREGON: Region.Us2,
5741	};
5742	/**
5743	 * Region to edge mapping, as part of Phase 1 Regional (CLIENT-7519).
5744	 * Temporary.
5745	 * @private
5746	 */
5747	const regionToEdge = {
5748	    [Region.Au1]: Edge.Sydney,
5749	    [Region.Br1]: Edge.SaoPaulo,
5750	    [Region.Ie1]: Edge.Dublin,
5751	    [Region.De1]: Edge.Frankfurt,
5752	    [Region.Jp1]: Edge.Tokyo,
5753	    [Region.Sg1]: Edge.Singapore,
5754	    [Region.Us1]: Edge.Ashburn,
5755	    [Region.Us2]: Edge.Umatilla,
5756	    [Region.Gll]: Edge.Roaming,
5757	    /**
5758	     * Interconnect edges
5759	     */
5760	    [Region.Us1Ix]: Edge.AshburnIx,
5761	    [Region.Us2Ix]: Edge.SanJoseIx,
5762	    [Region.Ie1Ix]: Edge.LondonIx,
5763	    [Region.De1Ix]: Edge.FrankfurtIx,
5764	    [Region.Sg1Ix]: Edge.SingaporeIx,
5765	    [Region.Au1Ix]: Edge.SydneyIx,
5766	    [Region.Jp1Ix]: Edge.TokyoIx,
5767	    /**
5768	     * Tnx regions
5769	     */
5770	    [Region.Us1Tnx]: Edge.AshburnIx,
5771	    [Region.Us2Tnx]: Edge.AshburnIx,
5772	    [Region.Ie1Tnx]: Edge.LondonIx,
5773	    [Region.Sg1Tnx]: Edge.SingaporeIx,
5774	};
5775	/**
5776	 * The default edge to connect to and create a chunder uri from, if the edge
5777	 * parameter is not specified during setup in `Device`.
5778	 * @constant
5779	 */
5780	const defaultEdge = Edge.Roaming;
5781	/**
5782	 * The default event gateway URI to publish to.
5783	 * @constant
5784	 * @private
5785	 */
5786	const defaultEventGatewayURI = 'eventgw.twilio.com';
5787	/**
5788	 * String template for an edge chunder URI
5789	 * @param edge - The edge.
5790	 */
5791	function createChunderEdgeURI(edge) {
5792	    return `voice-js.${edge}.twilio.com`;
5793	}
5794	/**
5795	 * String template for a region insights URI
5796	 * @param region - The region.
5797	 */
5798	function createEventGatewayURI(region) {
5799	    return region
5800	        ? `eventgw.${region}.twilio.com`
5801	        : defaultEventGatewayURI;
5802	}
5803	/**
5804	 * Create a signaling endpoint URL to connect a websocket to from a chunder URI.
5805	 * @param uri the chunder URI to create a signaling endpoint URL for
5806	 */
5807	function createSignalingEndpointURL(uri) {
5808	    return `wss://${uri}/signal`;
5809	}
5810	/**
5811	 * Get the URI associated with the passed edge.
5812	 * @private
5813	 * @param edge - A string or an array of edge values
5814	 * @returns An array of chunder URIs
5815	 */
5816	function getChunderURIs(edge) {
5817	    if (!!edge && typeof edge !== 'string' && !Array.isArray(edge)) {
5818	        throw new InvalidArgumentError('If `edge` is provided, it must be of type `string` or an array of strings.');
5819	    }
5820	    let uris;
5821	    if (edge) {
5822	        const edgeParams = Array.isArray(edge) ? edge : [edge];
5823	        uris = edgeParams.map((param) => createChunderEdgeURI(param));
5824	    }
5825	    else {
5826	        uris = [createChunderEdgeURI(defaultEdge)];
5827	    }
5828	    return uris;
5829	}
5830	/**
5831	 * Get the region shortcode by its full AWS region string.
5832	 *
5833	 * @private
5834	 * @param region - The region's full AWS string.
5835	 */
5836	function getRegionShortcode(region) {
5837	    return regionShortcodes[region] || null;
5838	}
5839
5840	// @ts-nocheck
5841	const ptToFixedBitrateAudioCodecName = {
5842	    0: 'PCMU',
5843	    8: 'PCMA',
5844	};
5845	const defaultOpusId = 111;
5846	const BITRATE_MAX = 510000;
5847	const BITRATE_MIN = 6000;
5848	function getPreferredCodecInfo(sdp) {
5849	    const [, codecId, codecName] = /a=rtpmap:(\d+) (\S+)/m.exec(sdp) || [null, '', ''];
5850	    const regex = new RegExp(`a=fmtp:${codecId} (\\S+)`, 'm');
5851	    const [, codecParams] = regex.exec(sdp) || [null, ''];
5852	    return { codecName, codecParams };
5853	}
5854	function setIceAggressiveNomination(sdp) {
5855	    // This only works on Chrome. We don't want any side effects on other browsers
5856	    // https://bugs.chromium.org/p/chromium/issues/detail?id=1024096
5857	    // https://issues.corp.twilio.com/browse/CLIENT-6911
5858	    if (!isChrome(window, window.navigator)) {
5859	        return sdp;
5860	    }
5861	    return sdp.split('\n')
5862	        .filter(line => line.indexOf('a=ice-lite') === -1)
5863	        .join('\n');
5864	}
5865	function setMaxAverageBitrate(sdp, maxAverageBitrate) {
5866	    if (typeof maxAverageBitrate !== 'number'
5867	        || maxAverageBitrate < BITRATE_MIN
5868	        || maxAverageBitrate > BITRATE_MAX) {
5869	        return sdp;
5870	    }
5871	    const matches = /a=rtpmap:(\d+) opus/m.exec(sdp);
5872	    const opusId = matches && matches.length ? matches[1] : defaultOpusId;
5873	    const regex = new RegExp(`a=fmtp:${opusId}`);
5874	    const lines = sdp.split('\n').map(line => regex.test(line)
5875	        ? line + `;maxaveragebitrate=${maxAverageBitrate}`
5876	        : line);
5877	    return lines.join('\n');
5878	}
5879	/**
5880	 * Return a new SDP string with the re-ordered codec preferences.
5881	 * @param {string} sdp
5882	 * @param {Array<AudioCodec>} preferredCodecs - If empty, the existing order
5883	 *   of audio codecs is preserved
5884	 * @returns {string} Updated SDP string
5885	 */
5886	function setCodecPreferences(sdp, preferredCodecs) {
5887	    const mediaSections = getMediaSections(sdp);
5888	    const session = sdp.split('\r\nm=')[0];
5889	    return [session].concat(mediaSections.map(section => {
5890	        // Codec preferences should not be applied to m=application sections.
5891	        if (!/^m=(audio|video)/.test(section)) {
5892	            return section;
5893	        }
5894	        const kind = section.match(/^m=(audio|video)/)[1];
5895	        const codecMap = createCodecMapForMediaSection(section);
5896	        const payloadTypes = getReorderedPayloadTypes(codecMap, preferredCodecs);
5897	        const newSection = setPayloadTypesInMediaSection(payloadTypes, section);
5898	        const pcmaPayloadTypes = codecMap.get('pcma') || [];
5899	        const pcmuPayloadTypes = codecMap.get('pcmu') || [];
5900	        const fixedBitratePayloadTypes = kind === 'audio'
5901	            ? new Set(pcmaPayloadTypes.concat(pcmuPayloadTypes))
5902	            : new Set();
5903	        return fixedBitratePayloadTypes.has(payloadTypes[0])
5904	            ? newSection.replace(/\r\nb=(AS|TIAS):([0-9]+)/g, '')
5905	            : newSection;
5906	    })).join('\r\n');
5907	}
5908	/**
5909	 * Get the m= sections of a particular kind and direction from an sdp.
5910	 * @param {string} sdp - SDP string
5911	 * @param {string} [kind] - Pattern for matching kind
5912	 * @param {string} [direction] - Pattern for matching direction
5913	 * @returns {Array<string>} mediaSections
5914	 */
5915	function getMediaSections(sdp, kind, direction) {
5916	    return sdp.replace(/\r\n\r\n$/, '\r\n').split('\r\nm=').slice(1).map(mediaSection => `m=${mediaSection}`).filter(mediaSection => {
5917	        const kindPattern = new RegExp(`m=${'.*'}`, 'gm');
5918	        const directionPattern = new RegExp(`a=${'.*'}`, 'gm');
5919	        return kindPattern.test(mediaSection) && directionPattern.test(mediaSection);
5920	    });
5921	}
5922	/**
5923	 * Create a Codec Map for the given m= section.
5924	 * @param {string} section - The given m= section
5925	 * @returns {Map<Codec, Array<PT>>}
5926	 */
5927	function createCodecMapForMediaSection(section) {
5928	    return Array.from(createPtToCodecName(section)).reduce((codecMap, pair) => {
5929	        const pt = pair[0];
5930	        const codecName = pair[1];
5931	        const pts = codecMap.get(codecName) || [];
5932	        return codecMap.set(codecName, pts.concat(pt));
5933	    }, new Map());
5934	}
5935	/**
5936	 * Create the reordered Codec Payload Types based on the preferred Codec Names.
5937	 * @param {Map<Codec, Array<PT>>} codecMap - Codec Map
5938	 * @param {Array<Codec>} preferredCodecs - Preferred Codec Names
5939	 * @returns {Array<PT>} Reordered Payload Types
5940	 */
5941	function getReorderedPayloadTypes(codecMap, preferredCodecs) {
5942	    preferredCodecs = preferredCodecs.map(codecName => codecName.toLowerCase());
5943	    const preferredPayloadTypes = flatMap(preferredCodecs, codecName => codecMap.get(codecName) || []);
5944	    const remainingCodecs = difference(Array.from(codecMap.keys()), preferredCodecs);
5945	    const remainingPayloadTypes = flatMap(remainingCodecs, codecName => codecMap.get(codecName));
5946	    return preferredPayloadTypes.concat(remainingPayloadTypes);
5947	}
5948	/**
5949	 * Set the given Codec Payload Types in the first line of the given m= section.
5950	 * @param {Array<PT>} payloadTypes - Payload Types
5951	 * @param {string} section - Given m= section
5952	 * @returns {string} - Updated m= section
5953	 */
5954	function setPayloadTypesInMediaSection(payloadTypes, section) {
5955	    const lines = section.split('\r\n');
5956	    let mLine = lines[0];
5957	    const otherLines = lines.slice(1);
5958	    mLine = mLine.replace(/([0-9]+\s?)+$/, payloadTypes.join(' '));
5959	    return [mLine].concat(otherLines).join('\r\n');
5960	}
5961	/**
5962	 * Create a Map from PTs to codec names for the given m= section.
5963	 * @param {string} mediaSection - The given m= section.
5964	 * @returns {Map<PT, Codec>} ptToCodecName
5965	 */
5966	function createPtToCodecName(mediaSection) {
5967	    return getPayloadTypesInMediaSection(mediaSection).reduce((ptToCodecName, pt) => {
5968	        const rtpmapPattern = new RegExp(`a=rtpmap:${pt} ([^/]+)`);
5969	        const matches = mediaSection.match(rtpmapPattern);
5970	        const codecName = matches
5971	            ? matches[1].toLowerCase()
5972	            : ptToFixedBitrateAudioCodecName[pt]
5973	                ? ptToFixedBitrateAudioCodecName[pt].toLowerCase()
5974	                : '';
5975	        return ptToCodecName.set(pt, codecName);
5976	    }, new Map());
5977	}
5978	/**
5979	 * Get the Codec Payload Types present in the first line of the given m= section
5980	 * @param {string} section - The m= section
5981	 * @returns {Array<PT>} Payload Types
5982	 */
5983	function getPayloadTypesInMediaSection(section) {
5984	    const mLine = section.split('\r\n')[0];
5985	    // In "m=<kind> <port> <proto> <payload_type_1> <payload_type_2> ... <payload_type_n>",
5986	    // the regex matches <port> and the PayloadTypes.
5987	    const matches = mLine.match(/([0-9]+)/g);
5988	    // This should not happen, but in case there are no PayloadTypes in
5989	    // the m= line, return an empty array.
5990	    if (!matches) {
5991	        return [];
5992	    }
5993	    // Since only the PayloadTypes are needed, we discard the <port>.
5994	    return matches.slice(1).map(match => parseInt(match, 10));
5995	}
5996
5997	// @ts-nocheck
5998	// tslint:disable only-arrow-functions
5999	/* global webkitRTCPeerConnection, mozRTCPeerConnection, mozRTCSessionDescription, mozRTCIceCandidate */
6000	function RTCPC(options) {
6001	    this.log = new Log('RTCPC');
6002	    if (typeof window === 'undefined') {
6003	        this.log.info('No RTCPeerConnection implementation available. The window object was not found.');
6004	        return;
6005	    }
6006	    if (options && options.RTCPeerConnection) {
6007	        this.RTCPeerConnection = options.RTCPeerConnection;
6008	    }
6009	    else if (typeof window.RTCPeerConnection === 'function') {
6010	        this.RTCPeerConnection = window.RTCPeerConnection;
6011	    }
6012	    else if (typeof window.webkitRTCPeerConnection === 'function') {
6013	        this.RTCPeerConnection = webkitRTCPeerConnection;
6014	    }
6015	    else if (typeof window.mozRTCPeerConnection === 'function') {
6016	        this.RTCPeerConnection = mozRTCPeerConnection;
6017	        window.RTCSessionDescription = mozRTCSessionDescription;
6018	        window.RTCIceCandidate = mozRTCIceCandidate;
6019	    }
6020	    else {
6021	        this.log.info('No RTCPeerConnection implementation available');
6022	    }
6023	}
6024	RTCPC.prototype.create = function (rtcConfiguration) {
6025	    this.pc = new this.RTCPeerConnection(rtcConfiguration);
6026	};
6027	RTCPC.prototype.createModernConstraints = c => {
6028	    // createOffer differs between Chrome 23 and Chrome 24+.
6029	    // See https://groups.google.com/forum/?fromgroups=#!topic/discuss-webrtc/JBDZtrMumyU
6030	    // Unfortunately I haven't figured out a way to detect which format
6031	    // is required ahead of time, so we'll first try the old way, and
6032	    // if we get an exception, then we'll try the new way.
6033	    if (typeof c === 'undefined') {
6034	        return null;
6035	    }
6036	    // NOTE(mroberts): As of Chrome 38, Chrome still appears to expect
6037	    // constraints under the 'mandatory' key, and with the first letter of each
6038	    // constraint capitalized. Firefox, on the other hand, has deprecated the
6039	    // 'mandatory' key and does not expect the first letter of each constraint
6040	    // capitalized.
6041	    const nc = Object.assign({}, c);
6042	    if (typeof webkitRTCPeerConnection !== 'undefined' && !isLegacyEdge()) {
6043	        nc.mandatory = {};
6044	        if (typeof c.audio !== 'undefined') {
6045	            nc.mandatory.OfferToReceiveAudio = c.audio;
6046	        }
6047	        if (typeof c.video !== 'undefined') {
6048	            nc.mandatory.OfferToReceiveVideo = c.video;
6049	        }
6050	    }
6051	    else {
6052	        if (typeof c.audio !== 'undefined') {
6053	            nc.offerToReceiveAudio = c.audio;
6054	        }
6055	        if (typeof c.video !== 'undefined') {
6056	            nc.offerToReceiveVideo = c.video;
6057	        }
6058	    }
6059	    delete nc.audio;
6060	    delete nc.video;
6061	    return nc;
6062	};
6063	RTCPC.prototype.createOffer = function (maxAverageBitrate, constraints, onSuccess, onError) {
6064	    constraints = this.createModernConstraints(constraints);
6065	    return promisifyCreate(this.pc.createOffer, this.pc)(constraints).then(offer => {
6066	        if (!this.pc) {
6067	            return Promise.resolve();
6068	        }
6069	        const sdp = setMaxAverageBitrate(offer.sdp, maxAverageBitrate);
6070	        return promisifySet(this.pc.setLocalDescription, this.pc)(new RTCSessionDescription({
6071	            sdp,
6072	            type: 'offer',
6073	        }));
6074	    }).then(onSuccess, onError);
6075	};
6076	RTCPC.prototype.createAnswer = function (maxAverageBitrate, constraints, onSuccess, onError) {
6077	    constraints = this.createModernConstraints(constraints);
6078	    return promisifyCreate(this.pc.createAnswer, this.pc)(constraints).then(answer => {
6079	        if (!this.pc) {
6080	            return Promise.resolve();
6081	        }
6082	        const sdp = setMaxAverageBitrate(answer.sdp, maxAverageBitrate);
6083	        return promisifySet(this.pc.setLocalDescription, this.pc)(new RTCSessionDescription({
6084	            sdp,
6085	            type: 'answer',
6086	        }));
6087	    }).then(onSuccess, onError);
6088	};
6089	RTCPC.prototype.processSDP = function (maxAverageBitrate, codecPreferences, sdp, constraints, onSuccess, onError) {
6090	    sdp = setCodecPreferences(sdp, codecPreferences);
6091	    const desc = new RTCSessionDescription({ sdp, type: 'offer' });
6092	    return promisifySet(this.pc.setRemoteDescription, this.pc)(desc).then(() => {
6093	        this.createAnswer(maxAverageBitrate, constraints, onSuccess, onError);
6094	    });
6095	};
6096	RTCPC.prototype.getSDP = function () {
6097	    return this.pc.localDescription.sdp;
6098	};
6099	RTCPC.prototype.processAnswer = function (codecPreferences, sdp, onSuccess, onError) {
6100	    if (!this.pc) {
6101	        return Promise.resolve();
6102	    }
6103	    sdp = setCodecPreferences(sdp, codecPreferences);
6104	    return promisifySet(this.pc.setRemoteDescription, this.pc)(new RTCSessionDescription({ sdp, type: 'answer' })).then(onSuccess, onError);
6105	};
6106	/* NOTE(mroberts): Firefox 18 through 21 include a `mozRTCPeerConnection`
6107	   object, but attempting to instantiate it will throw the error
6108
6109	       Error: PeerConnection not enabled (did you set the pref?)
6110
6111	   unless the `media.peerconnection.enabled` pref is enabled. So we need to test
6112	   if we can actually instantiate `mozRTCPeerConnection`; however, if the user
6113	   *has* enabled `media.peerconnection.enabled`, we need to perform the same
6114	   test that we use to detect Firefox 24 and above, namely:
6115
6116	       typeof (new mozRTCPeerConnection()).getLocalStreams === 'function'
6117
6118	    NOTE(rrowland): We no longer support Legacy Edge as of Sep 1, 2020.
6119	*/
6120	RTCPC.test = () => {
6121	    if (typeof navigator === 'object') {
6122	        const getUserMedia = (navigator.mediaDevices && navigator.mediaDevices.getUserMedia)
6123	            || navigator.webkitGetUserMedia
6124	            || navigator.mozGetUserMedia
6125	            || navigator.getUserMedia;
6126	        if (isLegacyEdge(navigator)) {
6127	            return false;
6128	        }
6129	        if (getUserMedia && typeof window.RTCPeerConnection === 'function') {
6130	            return true;
6131	        }
6132	        else if (getUserMedia && typeof window.webkitRTCPeerConnection === 'function') {
6133	            return true;
6134	        }
6135	        else if (getUserMedia && typeof window.mozRTCPeerConnection === 'function') {
6136	            try {
6137	                const test = new window.mozRTCPeerConnection();
6138	                if (typeof test.getLocalStreams !== 'function') {
6139	                    return false;
6140	                }
6141	            }
6142	            catch (e) {
6143	                return false;
6144	            }
6145	            return true;
6146	        }
6147	        else if (typeof RTCIceGatherer !== 'undefined') {
6148	            return true;
6149	        }
6150	    }
6151	    return false;
6152	};
6153	function promisify(fn, ctx, areCallbacksFirst, checkRval) {
6154	    return function () {
6155	        const args = Array.prototype.slice.call(arguments);
6156	        return new Promise(resolve => {
6157	            const returnValue = fn.apply(ctx, args);
6158	            if (!checkRval) {
6159	                resolve(returnValue);
6160	                return;
6161	            }
6162	            if (typeof returnValue === 'object' && typeof returnValue.then === 'function') {
6163	                resolve(returnValue);
6164	            }
6165	            else {
6166	                throw new Error();
6167	            }
6168	        }).catch(() => new Promise((resolve, reject) => {
6169	            fn.apply(ctx, areCallbacksFirst
6170	                ? [resolve, reject].concat(args)
6171	                : args.concat([resolve, reject]));
6172	        }));
6173	    };
6174	}
6175	function promisifyCreate(fn, ctx) {
6176	    return promisify(fn, ctx, true, true);
6177	}
6178	function promisifySet(fn, ctx) {
6179	    return promisify(fn, ctx, false, false);
6180	}
6181
6182	// @ts-nocheck
6183	const ICE_GATHERING_TIMEOUT = 15000;
6184	const ICE_GATHERING_FAIL_NONE = 'none';
6185	const ICE_GATHERING_FAIL_TIMEOUT = 'timeout';
6186	const INITIAL_ICE_CONNECTION_STATE = 'new';
6187	const VOLUME_INTERVAL_MS = 50;
6188	/**
6189	 * @typedef {Object} PeerConnection
6190	 * @param audioHelper
6191	 * @param pstream
6192	 * @param options
6193	 * @return {PeerConnection}
6194	 * @constructor
6195	 */
6196	function PeerConnection(audioHelper, pstream, options) {
6197	    if (!audioHelper || !pstream) {
6198	        throw new InvalidArgumentError('Audiohelper, and pstream are required arguments');
6199	    }
6200	    if (!(this instanceof PeerConnection)) {
6201	        return new PeerConnection(audioHelper, pstream, options);
6202	    }
6203	    this._log = new Log('PeerConnection');
6204	    function noop() {
6205	        this._log.warn('Unexpected noop call in peerconnection');
6206	    }
6207	    this.onaudio = noop;
6208	    this.onopen = noop;
6209	    this.onerror = noop;
6210	    this.onclose = noop;
6211	    this.ondisconnected = noop;
6212	    this.onfailed = noop;
6213	    this.onconnected = noop;
6214	    this.onreconnected = noop;
6215	    this.onsignalingstatechange = noop;
6216	    this.ondtlstransportstatechange = noop;
6217	    this.onicegatheringfailure = noop;
6218	    this.onicegatheringstatechange = noop;
6219	    this.oniceconnectionstatechange = noop;
6220	    this.onpcconnectionstatechange = noop;
6221	    this.onicecandidate = noop;
6222	    this.onselectedcandidatepairchange = noop;
6223	    this.onvolume = noop;
6224	    this.version = null;
6225	    this.pstream = pstream;
6226	    this.stream = null;
6227	    this.sinkIds = new Set(['default']);
6228	    this.outputs = new Map();
6229	    this.status = 'connecting';
6230	    this.callSid = null;
6231	    this.isMuted = false;
6232	    const AudioContext = typeof window !== 'undefined'
6233	        && (window.AudioContext || window.webkitAudioContext);
6234	    this._isSinkSupported = !!AudioContext &&
6235	        typeof HTMLAudioElement !== 'undefined' && HTMLAudioElement.prototype.setSinkId;
6236	    // NOTE(mmalavalli): Since each Connection creates its own AudioContext,
6237	    // after 6 instances an exception is thrown. Refer https://www.w3.org/2011/audio/track/issues/3.
6238	    // In order to get around it, we are re-using the Device's AudioContext.
6239	    this._audioContext = AudioContext && audioHelper._audioContext;
6240	    this._audioHelper = audioHelper;
6241	    this._hasIceCandidates = false;
6242	    this._hasIceGatheringFailures = false;
6243	    this._iceGatheringTimeoutId = null;
6244	    this._masterAudio = null;
6245	    this._masterAudioDeviceId = null;
6246	    this._mediaStreamSource = null;
6247	    this._dtmfSender = null;
6248	    this._dtmfSenderUnsupported = false;
6249	    this._callEvents = [];
6250	    this._nextTimeToPublish = Date.now();
6251	    this._onAnswerOrRinging = noop;
6252	    this._onHangup = noop;
6253	    this._remoteStream = null;
6254	    this._shouldManageStream = true;
6255	    this._iceState = INITIAL_ICE_CONNECTION_STATE;
6256	    this.options = options = options || {};
6257	    this.navigator = options.navigator
6258	        || (typeof navigator !== 'undefined' ? navigator : null);
6259	    this.util = options.util || util;
6260	    this.codecPreferences = options.codecPreferences;
6261	    return this;
6262	}
6263	PeerConnection.prototype.uri = function () {
6264	    return this._uri;
6265	};
6266	/**
6267	 * Open the underlying RTCPeerConnection with a MediaStream obtained by
6268	 *   passed constraints. The resulting MediaStream is created internally
6269	 *   and will therefore be managed and destroyed internally.
6270	 * @param {MediaStreamConstraints} constraints
6271	 */
6272	PeerConnection.prototype.openDefaultDeviceWithConstraints = function (constraints) {
6273	    return this._audioHelper._openDefaultDeviceWithConstraints(constraints)
6274	        .then(this._setInputTracksFromStream.bind(this, false));
6275	};
6276	/**
6277	 * Replace the existing input audio tracks with the audio tracks from the
6278	 *   passed input audio stream. We re-use the existing stream because
6279	 *   the AnalyzerNode is bound to the stream.
6280	 * @param {MediaStream} stream
6281	 */
6282	PeerConnection.prototype.setInputTracksFromStream = function (stream) {
6283	    const self = this;
6284	    return this._setInputTracksFromStream(true, stream).then(() => {
6285	        self._shouldManageStream = false;
6286	    });
6287	};
6288	PeerConnection.prototype._createAnalyser = (audioContext, options) => {
6289	    options = Object.assign({
6290	        fftSize: 32,
6291	        smoothingTimeConstant: 0.3,
6292	    }, options);
6293	    const analyser = audioContext.createAnalyser();
6294	    // tslint:disable-next-line
6295	    for (const field in options) {
6296	        analyser[field] = options[field];
6297	    }
6298	    return analyser;
6299	};
6300	PeerConnection.prototype._setVolumeHandler = function (handler) {
6301	    this.onvolume = handler;
6302	};
6303	PeerConnection.prototype._startPollingVolume = function () {
6304	    if (!this._audioContext || !this.stream || !this._remoteStream) {
6305	        return;
6306	    }
6307	    const audioContext = this._audioContext;
6308	    const inputAnalyser = this._inputAnalyser = this._createAnalyser(audioContext);
6309	    const inputBufferLength = inputAnalyser.frequencyBinCount;
6310	    const inputDataArray = new Uint8Array(inputBufferLength);
6311	    this._inputAnalyser2 = this._createAnalyser(audioContext, {
6312	        maxDecibels: 0,
6313	        minDecibels: -127,
6314	        smoothingTimeConstant: 0,
6315	    });
6316	    const outputAnalyser = this._outputAnalyser = this._createAnalyser(audioContext);
6317	    const outputBufferLength = outputAnalyser.frequencyBinCount;
6318	    const outputDataArray = new Uint8Array(outputBufferLength);
6319	    this._outputAnalyser2 = this._createAnalyser(audioContext, {
6320	        maxDecibels: 0,
6321	        minDecibels: -127,
6322	        smoothingTimeConstant: 0,
6323	    });
6324	    this._updateInputStreamSource(this.stream);
6325	    this._updateOutputStreamSource(this._remoteStream);
6326	    const self = this;
6327	    setTimeout(function emitVolume() {
6328	        if (!self._audioContext) {
6329	            return;
6330	        }
6331	        else if (self.status === 'closed') {
6332	            self._inputAnalyser.disconnect();
6333	            self._outputAnalyser.disconnect();
6334	            self._inputAnalyser2.disconnect();
6335	            self._outputAnalyser2.disconnect();
6336	            return;
6337	        }
6338	        self._inputAnalyser.getByteFrequencyData(inputDataArray);
6339	        const inputVolume = self.util.average(inputDataArray);
6340	        self._inputAnalyser2.getByteFrequencyData(inputDataArray);
6341	        const inputVolume2 = self.util.average(inputDataArray);
6342	        self._outputAnalyser.getByteFrequencyData(outputDataArray);
6343	        const outputVolume = self.util.average(outputDataArray);
6344	        self._outputAnalyser2.getByteFrequencyData(outputDataArray);
6345	        const outputVolume2 = self.util.average(outputDataArray);
6346	        self.onvolume(inputVolume / 255, outputVolume / 255, inputVolume2, outputVolume2);
6347	        setTimeout(emitVolume, VOLUME_INTERVAL_MS);
6348	    }, VOLUME_INTERVAL_MS);
6349	};
6350	PeerConnection.prototype._stopStream = function _stopStream() {
6351	    // We shouldn't stop the tracks if they were not created inside
6352	    //   this PeerConnection.
6353	    if (!this._shouldManageStream) {
6354	        return;
6355	    }
6356	    this._audioHelper._stopDefaultInputDeviceStream();
6357	};
6358	/**
6359	 * Update the stream source with the new input audio stream.
6360	 * @param {MediaStream} stream
6361	 * @private
6362	 */
6363	PeerConnection.prototype._updateInputStreamSource = function (stream) {
6364	    if (this._inputStreamSource) {
6365	        this._inputStreamSource.disconnect();
6366	    }
6367	    try {
6368	        this._inputStreamSource = this._audioContext.createMediaStreamSource(stream);
6369	        this._inputStreamSource.connect(this._inputAnalyser);
6370	        this._inputStreamSource.connect(this._inputAnalyser2);
6371	    }
6372	    catch (ex) {
6373	        this._log.warn('Unable to update input MediaStreamSource', ex);
6374	        this._inputStreamSource = null;
6375	    }
6376	};
6377	/**
6378	 * Update the stream source with the new ouput audio stream.
6379	 * @param {MediaStream} stream
6380	 * @private
6381	 */
6382	PeerConnection.prototype._updateOutputStreamSource = function (stream) {
6383	    if (this._outputStreamSource) {
6384	        this._outputStreamSource.disconnect();
6385	    }
6386	    try {
6387	        this._outputStreamSource = this._audioContext.createMediaStreamSource(stream);
6388	        this._outputStreamSource.connect(this._outputAnalyser);
6389	        this._outputStreamSource.connect(this._outputAnalyser2);
6390	    }
6391	    catch (ex) {
6392	        this._log.warn('Unable to update output MediaStreamSource', ex);
6393	        this._outputStreamSource = null;
6394	    }
6395	};
6396	/**
6397	 * Replace the tracks of the current stream with new tracks. We do this rather than replacing the
6398	 *   whole stream because AnalyzerNodes are bound to a stream.
6399	 * @param {Boolean} shouldClone - Whether the stream should be cloned if it is the first
6400	 *   stream, or set directly. As a rule of thumb, streams that are passed in externally may have
6401	 *   their lifecycle managed externally, and should be cloned so that we do not tear it or its tracks
6402	 *   down when the call ends. Streams that we create internally (inside PeerConnection) should be set
6403	 *   directly so that when the call ends it is disposed of.
6404	 * @param {MediaStream} newStream - The new stream to copy the tracks over from.
6405	 * @private
6406	 */
6407	PeerConnection.prototype._setInputTracksFromStream = function (shouldClone, newStream) {
6408	    if (!newStream) {
6409	        return Promise.reject(new InvalidArgumentError('Can not set input stream to null while in a call'));
6410	    }
6411	    if (!newStream.getAudioTracks().length) {
6412	        return Promise.reject(new InvalidArgumentError('Supplied input stream has no audio tracks'));
6413	    }
6414	    const localStream = this.stream;
6415	    const getStreamPromise = () => {
6416	        // Apply mute settings to new input track
6417	        this.mute(this.isMuted);
6418	        return Promise.resolve(this.stream);
6419	    };
6420	    if (!localStream) {
6421	        // We can't use MediaStream.clone() here because it stopped copying over tracks
6422	        //   as of Chrome 61. https://bugs.chromium.org/p/chromium/issues/detail?id=770908
6423	        this.stream = shouldClone ? cloneStream(newStream, this.options.MediaStream) : newStream;
6424	    }
6425	    else {
6426	        // If the call was started with gUM, and we are now replacing that track with an
6427	        // external stream's tracks, we should stop the old managed track.
6428	        if (this._shouldManageStream) {
6429	            this._stopStream();
6430	        }
6431	        if (!this._sender) {
6432	            this._sender = this.version.pc.getSenders()[0];
6433	        }
6434	        return this._sender.replaceTrack(newStream.getAudioTracks()[0]).then(() => {
6435	            this._updateInputStreamSource(newStream);
6436	            this.stream = shouldClone ? cloneStream(newStream, this.options.MediaStream) : newStream;
6437	            return getStreamPromise();
6438	        });
6439	    }
6440	    return getStreamPromise();
6441	};
6442	PeerConnection.prototype._onInputDevicesChanged = function () {
6443	    if (!this.stream) {
6444	        return;
6445	    }
6446	    // If all of our active tracks are ended, then our active input was lost
6447	    const activeInputWasLost = this.stream.getAudioTracks().every(track => track.readyState === 'ended');
6448	    // We only want to act if we manage the stream in PeerConnection (It was created
6449	    // here, rather than passed in.)
6450	    if (activeInputWasLost && this._shouldManageStream) {
6451	        this.openDefaultDeviceWithConstraints({ audio: true });
6452	    }
6453	};
6454	PeerConnection.prototype._onIceGatheringFailure = function (type) {
6455	    this._hasIceGatheringFailures = true;
6456	    this.onicegatheringfailure(type);
6457	};
6458	PeerConnection.prototype._onMediaConnectionStateChange = function (newState) {
6459	    const previousState = this._iceState;
6460	    if (previousState === newState
6461	        || (newState !== 'connected'
6462	            && newState !== 'disconnected'
6463	            && newState !== 'failed')) {
6464	        return;
6465	    }
6466	    this._iceState = newState;
6467	    let message;
6468	    switch (newState) {
6469	        case 'connected':
6470	            if (previousState === 'disconnected' || previousState === 'failed') {
6471	                message = 'ICE liveliness check succeeded. Connection with Twilio restored';
6472	                this._log.info(message);
6473	                this.onreconnected(message);
6474	            }
6475	            else {
6476	                message = 'Media connection established.';
6477	                this._log.info(message);
6478	                this.onconnected(message);
6479	            }
6480	            this._stopIceGatheringTimeout();
6481	            this._hasIceGatheringFailures = false;
6482	            break;
6483	        case 'disconnected':
6484	            message = 'ICE liveliness check failed. May be having trouble connecting to Twilio';
6485	            this._log.warn(message);
6486	            this.ondisconnected(message);
6487	            break;
6488	        case 'failed':
6489	            message = 'Connection with Twilio was interrupted.';
6490	            this._log.warn(message);
6491	            this.onfailed(message);
6492	            break;
6493	    }
6494	};
6495	PeerConnection.prototype._setSinkIds = function (sinkIds) {
6496	    if (!this._isSinkSupported) {
6497	        return Promise.reject(new NotSupportedError('Audio output selection is not supported by this browser'));
6498	    }
6499	    this.sinkIds = new Set(sinkIds.forEach ? sinkIds : [sinkIds]);
6500	    return this.version
6501	        ? this._updateAudioOutputs()
6502	        : Promise.resolve();
6503	};
6504	/**
6505	 * Start timeout for ICE Gathering
6506	 */
6507	PeerConnection.prototype._startIceGatheringTimeout = function startIceGatheringTimeout() {
6508	    this._stopIceGatheringTimeout();
6509	    this._iceGatheringTimeoutId = setTimeout(() => {
6510	        this._onIceGatheringFailure(ICE_GATHERING_FAIL_TIMEOUT);
6511	    }, ICE_GATHERING_TIMEOUT);
6512	};
6513	/**
6514	 * Stop timeout for ICE Gathering
6515	 */
6516	PeerConnection.prototype._stopIceGatheringTimeout = function stopIceGatheringTimeout() {
6517	    clearInterval(this._iceGatheringTimeoutId);
6518	};
6519	PeerConnection.prototype._updateAudioOutputs = function updateAudioOutputs() {
6520	    const addedOutputIds = Array.from(this.sinkIds).filter(function (id) {
6521	        return !this.outputs.has(id);
6522	    }, this);
6523	    const removedOutputIds = Array.from(this.outputs.keys()).filter(function (id) {
6524	        return !this.sinkIds.has(id);
6525	    }, this);
6526	    const self = this;
6527	    const createOutputPromises = addedOutputIds.map(this._createAudioOutput, this);
6528	    return Promise.all(createOutputPromises).then(() => Promise.all(removedOutputIds.map(self._removeAudioOutput, self)));
6529	};
6530	PeerConnection.prototype._createAudio = function createAudio(arr) {
6531	    const audio = new Audio(arr);
6532	    this.onaudio(audio);
6533	    return audio;
6534	};
6535	PeerConnection.prototype._createAudioOutput = function createAudioOutput(id) {
6536	    let dest = null;
6537	    if (this._mediaStreamSource) {
6538	        dest = this._audioContext.createMediaStreamDestination();
6539	        this._mediaStreamSource.connect(dest);
6540	    }
6541	    const audio = this._createAudio();
6542	    setAudioSource(audio, dest && dest.stream ? dest.stream : this.pcStream);
6543	    const self = this;
6544	    return audio.setSinkId(id).then(() => audio.play()).then(() => {
6545	        self.outputs.set(id, {
6546	            audio,
6547	            dest,
6548	        });
6549	    });
6550	};
6551	PeerConnection.prototype._removeAudioOutputs = function removeAudioOutputs() {
6552	    if (this._masterAudio && typeof this._masterAudioDeviceId !== 'undefined') {
6553	        this._disableOutput(this, this._masterAudioDeviceId);
6554	        this.outputs.delete(this._masterAudioDeviceId);
6555	        this._masterAudioDeviceId = null;
6556	        // Release the audio resources before deleting the audio
6557	        if (!this._masterAudio.paused) {
6558	            this._masterAudio.pause();
6559	        }
6560	        if (typeof this._masterAudio.srcObject !== 'undefined') {
6561	            this._masterAudio.srcObject = null;
6562	        }
6563	        else {
6564	            this._masterAudio.src = '';
6565	        }
6566	        this._masterAudio = null;
6567	    }
6568	    return Array.from(this.outputs.keys()).map(this._removeAudioOutput, this);
6569	};
6570	PeerConnection.prototype._disableOutput = function disableOutput(pc, id) {
6571	    const output = pc.outputs.get(id);
6572	    if (!output) {
6573	        return;
6574	    }
6575	    if (output.audio) {
6576	        output.audio.pause();
6577	        output.audio.src = '';
6578	    }
6579	    if (output.dest) {
6580	        output.dest.disconnect();
6581	    }
6582	};
6583	/**
6584	 * Disable a non-master output, and update the master output to assume its state. This
6585	 *   is called when the device ID assigned to the master output has been removed from
6586	 *   active devices. We can not simply remove the master audio output, so we must
6587	 *   instead reassign it.
6588	 * @private
6589	 * @param {PeerConnection} pc
6590	 * @param {string} masterId - The current device ID assigned to the master audio element.
6591	 */
6592	PeerConnection.prototype._reassignMasterOutput = function reassignMasterOutput(pc, masterId) {
6593	    const masterOutput = pc.outputs.get(masterId);
6594	    pc.outputs.delete(masterId);
6595	    const self = this;
6596	    const activeDeviceId = Array.from(pc.outputs.keys())[0];
6597	    // The audio device key could also be '' on Chrome if no media device permissions are allowed
6598	    const idToReplace = typeof activeDeviceId === 'string' ? activeDeviceId : 'default';
6599	    return masterOutput.audio.setSinkId(idToReplace).then(() => {
6600	        self._disableOutput(pc, idToReplace);
6601	        pc.outputs.set(idToReplace, masterOutput);
6602	        pc._masterAudioDeviceId = idToReplace;
6603	    }).catch(function rollback() {
6604	        pc.outputs.set(masterId, masterOutput);
6605	        self._log.info('Could not reassign master output. Attempted to roll back.');
6606	    });
6607	};
6608	PeerConnection.prototype._removeAudioOutput = function removeAudioOutput(id) {
6609	    if (this._masterAudioDeviceId === id) {
6610	        return this._reassignMasterOutput(this, id);
6611	    }
6612	    this._disableOutput(this, id);
6613	    this.outputs.delete(id);
6614	    return Promise.resolve();
6615	};
6616	/**
6617	 * Use an AudioContext to potentially split our audio output stream to multiple
6618	 *   audio devices. This is only available to browsers with AudioContext and
6619	 *   HTMLAudioElement.setSinkId() available. We save the source stream in
6620	 *   _masterAudio, and use it for one of the active audio devices. We keep
6621	 *   track of its ID because we must replace it if we lose its initial device.
6622	 */
6623	PeerConnection.prototype._onAddTrack = function onAddTrack(pc, stream) {
6624	    const audio = pc._masterAudio = this._createAudio();
6625	    setAudioSource(audio, stream);
6626	    audio.play();
6627	    // Assign the initial master audio element to a random active output device
6628	    const activeDeviceId = Array.from(pc.outputs.keys())[0];
6629	    // The audio device key could also be '' on Chrome if no media device permissions are allowed
6630	    const deviceId = typeof activeDeviceId === 'string' ? activeDeviceId : 'default';
6631	    pc._masterAudioDeviceId = deviceId;
6632	    pc.outputs.set(deviceId, { audio });
6633	    try {
6634	        pc._mediaStreamSource = pc._audioContext.createMediaStreamSource(stream);
6635	    }
6636	    catch (ex) {
6637	        this._log.warn('Unable to create a MediaStreamSource from onAddTrack', ex);
6638	        this._mediaStreamSource = null;
6639	    }
6640	    pc.pcStream = stream;
6641	    pc._updateAudioOutputs();
6642	};
6643	/**
6644	 * Use a single audio element to play the audio output stream. This does not
6645	 *   support multiple output devices, and is a fallback for when AudioContext
6646	 *   and/or HTMLAudioElement.setSinkId() is not available to the client.
6647	 */
6648	PeerConnection.prototype._fallbackOnAddTrack = function fallbackOnAddTrack(pc, stream) {
6649	    const audio = document && document.createElement('audio');
6650	    audio.autoplay = true;
6651	    if (!setAudioSource(audio, stream)) {
6652	        pc._log.info('Error attaching stream to element.');
6653	    }
6654	    pc.outputs.set('default', { audio });
6655	};
6656	PeerConnection.prototype._setEncodingParameters = function (enableDscp) {
6657	    if (!enableDscp
6658	        || !this._sender
6659	        || typeof this._sender.getParameters !== 'function'
6660	        || typeof this._sender.setParameters !== 'function') {
6661	        return;
6662	    }
6663	    const params = this._sender.getParameters();
6664	    if (!params.priority && !(params.encodings && params.encodings.length)) {
6665	        return;
6666	    }
6667	    // This is how MDN's RTPSenderParameters defines priority
6668	    params.priority = 'high';
6669	    // And this is how it's currently implemented in Chrome M72+
6670	    if (params.encodings && params.encodings.length) {
6671	        params.encodings.forEach(encoding => {
6672	            encoding.priority = 'high';
6673	            encoding.networkPriority = 'high';
6674	        });
6675	    }
6676	    this._sender.setParameters(params);
6677	};
6678	PeerConnection.prototype._setupPeerConnection = function (rtcConfiguration) {
6679	    const self = this;
6680	    const version = new (this.options.rtcpcFactory || RTCPC)({ RTCPeerConnection: this.options.RTCPeerConnection });
6681	    version.create(rtcConfiguration);
6682	    addStream(version.pc, this.stream);
6683	    const supportedCodecs = RTCRtpReceiver.getCapabilities('audio').codecs;
6684	    this._log.debug('sorting codecs', supportedCodecs, this.codecPreferences);
6685	    const sortedCodecs = sortByMimeTypes(supportedCodecs, this.codecPreferences);
6686	    const [transceiver] = version.pc.getTransceivers();
6687	    this._log.debug('setting sorted codecs', sortedCodecs);
6688	    transceiver.setCodecPreferences(sortedCodecs);
6689	    const eventName = 'ontrack' in version.pc
6690	        ? 'ontrack' : 'onaddstream';
6691	    version.pc[eventName] = event => {
6692	        const stream = self._remoteStream = event.stream || event.streams[0];
6693	        if (typeof version.pc.getSenders === 'function') {
6694	            this._sender = version.pc.getSenders()[0];
6695	        }
6696	        if (self._isSinkSupported) {
6697	            self._onAddTrack(self, stream);
6698	        }
6699	        else {
6700	            self._fallbackOnAddTrack(self, stream);
6701	        }
6702	        self._startPollingVolume();
6703	    };
6704	    return version;
6705	};
6706	PeerConnection.prototype._maybeSetIceAggressiveNomination = function (sdp) {
6707	    return this.options.forceAggressiveIceNomination ? setIceAggressiveNomination(sdp) : sdp;
6708	};
6709	PeerConnection.prototype._setupChannel = function () {
6710	    const pc = this.version.pc;
6711	    // Chrome 25 supports onopen
6712	    this.version.pc.onopen = () => {
6713	        this.status = 'open';
6714	        this.onopen();
6715	    };
6716	    // Chrome 26 doesn't support onopen so must detect state change
6717	    this.version.pc.onstatechange = () => {
6718	        if (this.version.pc && this.version.pc.readyState === 'stable') {
6719	            this.status = 'open';
6720	            this.onopen();
6721	        }
6722	    };
6723	    // Chrome 27 changed onstatechange to onsignalingstatechange
6724	    this.version.pc.onsignalingstatechange = () => {
6725	        const state = pc.signalingState;
6726	        this._log.info(`signalingState is "${state}"`);
6727	        if (this.version.pc && this.version.pc.signalingState === 'stable') {
6728	            this.status = 'open';
6729	            this.onopen();
6730	        }
6731	        this.onsignalingstatechange(pc.signalingState);
6732	    };
6733	    // Chrome 72+
6734	    pc.onconnectionstatechange = event => {
6735	        let state = pc.connectionState;
6736	        if (!state && event && event.target) {
6737	            // VDI environment
6738	            const targetPc = event.target;
6739	            state = targetPc.connectionState || targetPc.connectionState_;
6740	            this._log.info(`pc.connectionState not detected. Using target PC. State=${state}`);
6741	        }
6742	        if (!state) {
6743	            this._log.warn(`onconnectionstatechange detected but state is "${state}"`);
6744	        }
6745	        else {
6746	            this._log.info(`pc.connectionState is "${state}"`);
6747	        }
6748	        this.onpcconnectionstatechange(state);
6749	        this._onMediaConnectionStateChange(state);
6750	    };
6751	    pc.onicecandidate = event => {
6752	        const { candidate } = event;
6753	        if (candidate) {
6754	            this._hasIceCandidates = true;
6755	            this.onicecandidate(candidate);
6756	            this._setupRTCIceTransportListener();
6757	        }
6758	        this._log.info(`ICE Candidate: ${JSON.stringify(candidate)}`);
6759	    };
6760	    pc.onicegatheringstatechange = () => {
6761	        const state = pc.iceGatheringState;
6762	        if (state === 'gathering') {
6763	            this._startIceGatheringTimeout();
6764	        }
6765	        else if (state === 'complete') {
6766	            this._stopIceGatheringTimeout();
6767	            // Fail if no candidates found
6768	            if (!this._hasIceCandidates) {
6769	                this._onIceGatheringFailure(ICE_GATHERING_FAIL_NONE);
6770	            }
6771	            // There was a failure mid-gathering phase. We want to start our timer and issue
6772	            // an ice restart if we don't get connected after our timeout
6773	            if (this._hasIceCandidates && this._hasIceGatheringFailures) {
6774	                this._startIceGatheringTimeout();
6775	            }
6776	        }
6777	        this._log.info(`pc.iceGatheringState is "${pc.iceGatheringState}"`);
6778	        this.onicegatheringstatechange(state);
6779	    };
6780	    pc.oniceconnectionstatechange = () => {
6781	        this._log.info(`pc.iceConnectionState is "${pc.iceConnectionState}"`);
6782	        this.oniceconnectionstatechange(pc.iceConnectionState);
6783	        this._onMediaConnectionStateChange(pc.iceConnectionState);
6784	    };
6785	};
6786	PeerConnection.prototype._initializeMediaStream = function (rtcConfiguration) {
6787	    // if mediastream already open then do nothing
6788	    if (this.status === 'open') {
6789	        return false;
6790	    }
6791	    if (this.pstream.status === 'disconnected') {
6792	        this.onerror({ info: {
6793	                code: 31000,
6794	                message: 'Cannot establish connection. Client is disconnected',
6795	                twilioError: new SignalingErrors.ConnectionDisconnected(),
6796	            } });
6797	        this.close();
6798	        return false;
6799	    }
6800	    this.version = this._setupPeerConnection(rtcConfiguration);
6801	    this._setupChannel();
6802	    return true;
6803	};
6804	/**
6805	 * Remove reconnection-related listeners
6806	 * @private
6807	 */
6808	PeerConnection.prototype._removeReconnectionListeners = function () {
6809	    if (this.pstream) {
6810	        this.pstream.removeListener('answer', this._onAnswerOrRinging);
6811	        this.pstream.removeListener('hangup', this._onHangup);
6812	    }
6813	};
6814	/**
6815	 * Setup a listener for RTCDtlsTransport to capture state changes events
6816	 * @private
6817	 */
6818	PeerConnection.prototype._setupRTCDtlsTransportListener = function () {
6819	    const dtlsTransport = this.getRTCDtlsTransport();
6820	    if (!dtlsTransport || dtlsTransport.onstatechange) {
6821	        return;
6822	    }
6823	    const handler = () => {
6824	        this._log.info(`dtlsTransportState is "${dtlsTransport.state}"`);
6825	        this.ondtlstransportstatechange(dtlsTransport.state);
6826	    };
6827	    // Publish initial state
6828	    handler();
6829	    dtlsTransport.onstatechange = handler;
6830	};
6831	/**
6832	 * Setup a listener for RTCIceTransport to capture selected candidate pair changes
6833	 * @private
6834	 */
6835	PeerConnection.prototype._setupRTCIceTransportListener = function () {
6836	    const iceTransport = this._getRTCIceTransport();
6837	    if (!iceTransport || iceTransport.onselectedcandidatepairchange) {
6838	        return;
6839	    }
6840	    iceTransport.onselectedcandidatepairchange = () => this.onselectedcandidatepairchange(iceTransport.getSelectedCandidatePair());
6841	};
6842	/**
6843	 * Restarts ICE for the current connection
6844	 * ICE Restart failures are ignored. Retries are managed in Connection
6845	 * @private
6846	 */
6847	PeerConnection.prototype.iceRestart = function () {
6848	    this._log.info('Attempting to restart ICE...');
6849	    this._hasIceCandidates = false;
6850	    this.version.createOffer(this.options.maxAverageBitrate, { iceRestart: true }).then(() => {
6851	        this._removeReconnectionListeners();
6852	        this._onAnswerOrRinging = payload => {
6853	            this._removeReconnectionListeners();
6854	            if (!payload.sdp || this.version.pc.signalingState !== 'have-local-offer') {
6855	                const message = 'Invalid state or param during ICE Restart:'
6856	                    + `hasSdp:${!!payload.sdp}, signalingState:${this.version.pc.signalingState}`;
6857	                this._log.warn(message);
6858	                return;
6859	            }
6860	            const sdp = this._maybeSetIceAggressiveNomination(payload.sdp);
6861	            this._answerSdp = sdp;
6862	            if (this.status !== 'closed') {
6863	                this.version.processAnswer(this.codecPreferences, sdp, null, err => {
6864	                    const message = err && err.message ? err.message : err;
6865	                    this._log.error(`Failed to process answer during ICE Restart. Error: ${message}`);
6866	                });
6867	            }
6868	        };
6869	        this._onHangup = () => {
6870	            this._log.info('Received hangup during ICE Restart');
6871	            this._removeReconnectionListeners();
6872	        };
6873	        this.pstream.on('answer', this._onAnswerOrRinging);
6874	        this.pstream.on('hangup', this._onHangup);
6875	        this.pstream.reinvite(this.version.getSDP(), this.callSid);
6876	    }).catch((err) => {
6877	        const message = err && err.message ? err.message : err;
6878	        this._log.error(`Failed to createOffer during ICE Restart. Error: ${message}`);
6879	        // CreateOffer failures doesn't transition ice state to failed
6880	        // We need trigger it so it can be picked up by retries
6881	        this.onfailed(message);
6882	    });
6883	};
6884	PeerConnection.prototype.makeOutgoingCall = function (params, signalingReconnectToken, callsid, rtcConfiguration, onMediaStarted) {
6885	    if (!this._initializeMediaStream(rtcConfiguration)) {
6886	        return;
6887	    }
6888	    const self = this;
6889	    this.callSid = callsid;
6890	    function onAnswerSuccess() {
6891	        if (self.options) {
6892	            self._setEncodingParameters(self.options.dscp);
6893	        }
6894	        onMediaStarted(self.version.pc);
6895	    }
6896	    function onAnswerError(err) {
6897	        const errMsg = err.message || err;
6898	        self.onerror({ info: {
6899	                code: 31000,
6900	                message: `Error processing answer: ${errMsg}`,
6901	                twilioError: new MediaErrors.ClientRemoteDescFailed(),
6902	            } });
6903	    }
6904	    this._onAnswerOrRinging = payload => {
6905	        if (!payload.sdp) {
6906	            return;
6907	        }
6908	        const sdp = this._maybeSetIceAggressiveNomination(payload.sdp);
6909	        self._answerSdp = sdp;
6910	        if (self.status !== 'closed') {
6911	            self.version.processAnswer(this.codecPreferences, sdp, onAnswerSuccess, onAnswerError);
6912	        }
6913	        self.pstream.removeListener('answer', self._onAnswerOrRinging);
6914	        self.pstream.removeListener('ringing', self._onAnswerOrRinging);
6915	    };
6916	    this.pstream.on('answer', this._onAnswerOrRinging);
6917	    this.pstream.on('ringing', this._onAnswerOrRinging);
6918	    function onOfferSuccess() {
6919	        if (self.status !== 'closed') {
6920	            if (signalingReconnectToken) {
6921	                self.pstream.reconnect(self.version.getSDP(), self.callSid, signalingReconnectToken);
6922	            }
6923	            else {
6924	                self.pstream.invite(self.version.getSDP(), self.callSid, params);
6925	            }
6926	            self._setupRTCDtlsTransportListener();
6927	        }
6928	    }
6929	    function onOfferError(err) {
6930	        const errMsg = err.message || err;
6931	        self.onerror({ info: {
6932	                code: 31000,
6933	                message: `Error creating the offer: ${errMsg}`,
6934	                twilioError: new MediaErrors.ClientLocalDescFailed(),
6935	            } });
6936	    }
6937	    this.version.createOffer(this.options.maxAverageBitrate, { audio: true }, onOfferSuccess, onOfferError);
6938	};
6939	PeerConnection.prototype.answerIncomingCall = function (callSid, sdp, rtcConfiguration, onMediaStarted) {
6940	    if (!this._initializeMediaStream(rtcConfiguration)) {
6941	        return;
6942	    }
6943	    sdp = this._maybeSetIceAggressiveNomination(sdp);
6944	    this._answerSdp = sdp.replace(/^a=setup:actpass$/gm, 'a=setup:passive');
6945	    this.callSid = callSid;
6946	    const self = this;
6947	    function onAnswerSuccess() {
6948	        if (self.status !== 'closed') {
6949	            self.pstream.answer(self.version.getSDP(), callSid);
6950	            if (self.options) {
6951	                self._setEncodingParameters(self.options.dscp);
6952	            }
6953	            onMediaStarted(self.version.pc);
6954	            self._setupRTCDtlsTransportListener();
6955	        }
6956	    }
6957	    function onAnswerError(err) {
6958	        const errMsg = err.message || err;
6959	        self.onerror({ info: {
6960	                code: 31000,
6961	                message: `Error creating the answer: ${errMsg}`,
6962	                twilioError: new MediaErrors.ClientRemoteDescFailed(),
6963	            } });
6964	    }
6965	    this.version.processSDP(this.options.maxAverageBitrate, this.codecPreferences, sdp, { audio: true }, onAnswerSuccess, onAnswerError);
6966	};
6967	PeerConnection.prototype.close = function () {
6968	    if (this.version && this.version.pc) {
6969	        if (this.version.pc.signalingState !== 'closed') {
6970	            this.version.pc.close();
6971	        }
6972	        this.version.pc = null;
6973	    }
6974	    if (this.stream) {
6975	        this.mute(false);
6976	        this._stopStream();
6977	    }
6978	    this.stream = null;
6979	    this._removeReconnectionListeners();
6980	    this._stopIceGatheringTimeout();
6981	    Promise.all(this._removeAudioOutputs()).catch(() => {
6982	        // We don't need to alert about failures here.
6983	    });
6984	    if (this._mediaStreamSource) {
6985	        this._mediaStreamSource.disconnect();
6986	    }
6987	    if (this._inputAnalyser) {
6988	        this._inputAnalyser.disconnect();
6989	    }
6990	    if (this._outputAnalyser) {
6991	        this._outputAnalyser.disconnect();
6992	    }
6993	    if (this._inputAnalyser2) {
6994	        this._inputAnalyser2.disconnect();
6995	    }
6996	    if (this._outputAnalyser2) {
6997	        this._outputAnalyser2.disconnect();
6998	    }
6999	    this.status = 'closed';
7000	    this.onclose();
7001	};
7002	PeerConnection.prototype.reject = function (callSid) {
7003	    this.callSid = callSid;
7004	};
7005	PeerConnection.prototype.ignore = function (callSid) {
7006	    this.callSid = callSid;
7007	};
7008	/**
7009	 * Mute or unmute input audio. If the stream is not yet present, the setting
7010	 *   is saved and applied to future streams/tracks.
7011	 * @params {boolean} shouldMute - Whether the input audio should
7012	 *   be muted or unmuted.
7013	 */
7014	PeerConnection.prototype.mute = function (shouldMute) {
7015	    this.isMuted = shouldMute;
7016	    if (!this.stream) {
7017	        return;
7018	    }
7019	    if (this._sender && this._sender.track) {
7020	        this._sender.track.enabled = !shouldMute;
7021	    }
7022	    else {
7023	        const audioTracks = typeof this.stream.getAudioTracks === 'function'
7024	            ? this.stream.getAudioTracks()
7025	            : this.stream.audioTracks;
7026	        audioTracks.forEach(track => {
7027	            track.enabled = !shouldMute;
7028	        });
7029	    }
7030	};
7031	/**
7032	 * Get or create an RTCDTMFSender for the first local audio MediaStreamTrack
7033	 * we can get from the RTCPeerConnection. Return null if unsupported.
7034	 * @instance
7035	 * @returns ?RTCDTMFSender
7036	 */
7037	PeerConnection.prototype.getOrCreateDTMFSender = function getOrCreateDTMFSender() {
7038	    if (this._dtmfSender || this._dtmfSenderUnsupported) {
7039	        return this._dtmfSender || null;
7040	    }
7041	    const self = this;
7042	    const pc = this.version.pc;
7043	    if (!pc) {
7044	        this._log.warn('No RTCPeerConnection available to call createDTMFSender on');
7045	        return null;
7046	    }
7047	    if (typeof pc.getSenders === 'function' && (typeof RTCDTMFSender === 'function' || typeof RTCDtmfSender === 'function')) {
7048	        const chosenSender = pc.getSenders().find(sender => sender.dtmf);
7049	        if (chosenSender) {
7050	            this._log.info('Using RTCRtpSender#dtmf');
7051	            this._dtmfSender = chosenSender.dtmf;
7052	            return this._dtmfSender;
7053	        }
7054	    }
7055	    if (typeof pc.createDTMFSender === 'function' && typeof pc.getLocalStreams === 'function') {
7056	        const track = pc.getLocalStreams().map(stream => {
7057	            const tracks = self._getAudioTracks(stream);
7058	            return tracks && tracks[0];
7059	        })[0];
7060	        if (!track) {
7061	            this._log.warn('No local audio MediaStreamTrack available on the RTCPeerConnection to pass to createDTMFSender');
7062	            return null;
7063	        }
7064	        this._log.info('Creating RTCDTMFSender');
7065	        this._dtmfSender = pc.createDTMFSender(track);
7066	        return this._dtmfSender;
7067	    }
7068	    this._log.info('RTCPeerConnection does not support RTCDTMFSender');
7069	    this._dtmfSenderUnsupported = true;
7070	    return null;
7071	};
7072	/**
7073	 * Get the RTCDtlTransport object from the PeerConnection
7074	 * @returns RTCDtlTransport
7075	 */
7076	PeerConnection.prototype.getRTCDtlsTransport = function getRTCDtlsTransport() {
7077	    const sender = this.version && this.version.pc
7078	        && typeof this.version.pc.getSenders === 'function'
7079	        && this.version.pc.getSenders()[0];
7080	    return sender && sender.transport || null;
7081	};
7082	PeerConnection.prototype._canStopMediaStreamTrack = () => typeof MediaStreamTrack.prototype.stop === 'function';
7083	PeerConnection.prototype._getAudioTracks = stream => typeof stream.getAudioTracks === 'function' ?
7084	    stream.getAudioTracks() : stream.audioTracks;
7085	/**
7086	 * Get the RTCIceTransport object from the PeerConnection
7087	 * @returns RTCIceTransport
7088	 */
7089	PeerConnection.prototype._getRTCIceTransport = function _getRTCIceTransport() {
7090	    const dtlsTransport = this.getRTCDtlsTransport();
7091	    return dtlsTransport && dtlsTransport.iceTransport || null;
7092	};
7093	// Is PeerConnection.protocol used outside of our SDK? We should remove this if not.
7094	PeerConnection.protocol = ((() => RTCPC.test() ? new RTCPC() : null))();
7095	function addStream(pc, stream) {
7096	    if (typeof pc.addTrack === 'function') {
7097	        stream.getAudioTracks().forEach(track => {
7098	            // The second parameters, stream, should not be necessary per the latest editor's
7099	            //   draft, but FF requires it. https://bugzilla.mozilla.org/show_bug.cgi?id=1231414
7100	            pc.addTrack(track, stream);
7101	        });
7102	    }
7103	    else {
7104	        pc.addStream(stream);
7105	    }
7106	}
7107	function cloneStream(oldStream, _MediaStream) {
7108	    let newStream;
7109	    if (_MediaStream) {
7110	        newStream = new _MediaStream();
7111	    }
7112	    else if (typeof MediaStream !== 'undefined') {
7113	        newStream = new MediaStream();
7114	    }
7115	    else {
7116	        newStream = new webkitMediaStream();
7117	    }
7118	    oldStream.getAudioTracks().forEach(newStream.addTrack, newStream);
7119	    return newStream;
7120	}
7121	/**
7122	 * Set the source of an HTMLAudioElement to the specified MediaStream
7123	 * @param {HTMLAudioElement} audio
7124	 * @param {MediaStream} stream
7125	 * @returns {boolean} Whether the audio source was set successfully
7126	 */
7127	function setAudioSource(audio, stream) {
7128	    if (typeof audio.srcObject !== 'undefined') {
7129	        audio.srcObject = stream;
7130	    }
7131	    else if (typeof audio.mozSrcObject !== 'undefined') {
7132	        audio.mozSrcObject = stream;
7133	    }
7134	    else if (typeof audio.src !== 'undefined') {
7135	        const _window = audio.options.window || window;
7136	        audio.src = (_window.URL || _window.webkitURL).createObjectURL(stream);
7137	    }
7138	    else {
7139	        return false;
7140	    }
7141	    return true;
7142	}
7143	PeerConnection.enabled = RTCPC.test();
7144
7145	// @ts-nocheck
7146	function enabled() {
7147	    return RTCPC.test();
7148	}
7149	function getMediaEngine() {
7150	    return typeof RTCIceGatherer !== 'undefined' ? 'ORTC' : 'WebRTC';
7151	}
7152
7153	// @ts-nocheck
7154	function getUserMedia(constraints, options) {
7155	    options = options || {};
7156	    options.util = options.util || util;
7157	    options.navigator = options.navigator
7158	        || (typeof navigator !== 'undefined' ? navigator : null);
7159	    return new Promise((resolve, reject) => {
7160	        if (!options.navigator) {
7161	            throw new NotSupportedError('getUserMedia is not supported');
7162	        }
7163	        switch ('function') {
7164	            case typeof (options.navigator.mediaDevices && options.navigator.mediaDevices.getUserMedia):
7165	                return resolve(options.navigator.mediaDevices.getUserMedia(constraints));
7166	            case typeof options.navigator.webkitGetUserMedia:
7167	                return options.navigator.webkitGetUserMedia(constraints, resolve, reject);
7168	            case typeof options.navigator.mozGetUserMedia:
7169	                return options.navigator.mozGetUserMedia(constraints, resolve, reject);
7170	            case typeof options.navigator.getUserMedia:
7171	                return options.navigator.getUserMedia(constraints, resolve, reject);
7172	            default:
7173	                throw new NotSupportedError('getUserMedia is not supported');
7174	        }
7175	    }).catch(e => {
7176	        throw (options.util.isFirefox() && e.name === 'NotReadableError')
7177	            ? new NotSupportedError('Firefox does not currently support opening multiple audio input tracks' +
7178	                'simultaneously, even across different tabs.\n' +
7179	                'Related Bugzilla thread: https://bugzilla.mozilla.org/show_bug.cgi?id=1299324')
7180	            : e;
7181	    });
7182	}
7183
7184	/**
7185	 * Generates a 128-bit long random string that is formatted as a 32 long string
7186	 * of characters where each character is from the set:
7187	 * [0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f].
7188	 */
7189	function generateRandomizedString() {
7190	    if (typeof window !== 'object') {
7191	        throw new NotSupportedError('This platform is not supported.');
7192	    }
7193	    const { crypto } = window;
7194	    if (typeof crypto !== 'object') {
7195	        throw new NotSupportedError('The `crypto` module is not available on this platform.');
7196	    }
7197	    if (typeof crypto.getRandomValues !== 'function') {
7198	        throw new NotSupportedError('The function `crypto.getRandomValues` is not available on this ' +
7199	            'platform.');
7200	    }
7201	    if (typeof window.Uint8Array !== 'function') {
7202	        throw new NotSupportedError('The `Uint8Array` module is not available on this platform.');
7203	    }
7204	    return crypto
7205	        .getRandomValues(new window.Uint8Array(16))
7206	        .reduce((r, n) => `${r}${n.toString(16).padStart(2, '0')}`, '');
7207	}
7208	function generateVoiceEventSid() {
7209	    return `KX${generateRandomizedString()}`;
7210	}
7211
7212	/**
7213	 * Deferred Promise
7214	 */
7215	let Deferred$1 = class Deferred {
7216	    /**
7217	     * @constructor
7218	     */
7219	    constructor() {
7220	        this._promise = new Promise((resolve, reject) => {
7221	            this._resolve = resolve;
7222	            this._reject = reject;
7223	        });
7224	    }
7225	    /**
7226	     * @returns The {@link Deferred} Promise
7227	     */
7228	    get promise() {
7229	        return this._promise;
7230	    }
7231	    /**
7232	     * Rejects this promise
7233	     */
7234	    reject(reason) {
7235	        this._reject(reason);
7236	    }
7237	    /**
7238	     * Resolves this promise
7239	     */
7240	    resolve(value) {
7241	        this._resolve(value);
7242	    }
7243	};
7244
7245	/**
7246	 * Queue async operations and executes them synchronously.
7247	 */
7248	class AsyncQueue {
7249	    constructor() {
7250	        /**
7251	         * The list of async operations in this queue
7252	         */
7253	        this._operations = [];
7254	    }
7255	    /**
7256	     * Adds the async operation to the queue
7257	     * @param callback An async callback that returns a promise
7258	     * @returns A promise that will get resolved or rejected after executing the callback
7259	     */
7260	    enqueue(callback) {
7261	        const hasPending = !!this._operations.length;
7262	        const deferred = new Deferred$1();
7263	        this._operations.push({ deferred, callback });
7264	        if (!hasPending) {
7265	            this._processQueue();
7266	        }
7267	        return deferred.promise;
7268	    }
7269	    /**
7270	     * Start processing the queue. This executes the first item and removes it after.
7271	     * Then do the same for next items until the queue is emptied.
7272	     */
7273	    _processQueue() {
7274	        return __awaiter(this, void 0, void 0, function* () {
7275	            while (this._operations.length) {
7276	                // Grab first item, don't remove from array yet until it's resolved/rejected
7277	                const { deferred, callback } = this._operations[0];
7278	                // We want to capture the result/error first so we can remove the item from the queue later
7279	                let result;
7280	                let error;
7281	                // Sometimes result and error are empty. So let's use a separate flag to determine if the promise has resolved
7282	                let hasResolved;
7283	                try {
7284	                    result = yield callback();
7285	                    hasResolved = true;
7286	                }
7287	                catch (e) {
7288	                    error = e;
7289	                }
7290	                // Remove the item
7291	                this._operations.shift();
7292	                if (hasResolved) {
7293	                    deferred.resolve(result);
7294	                }
7295	                else {
7296	                    deferred.reject(error);
7297	                }
7298	            }
7299	        });
7300	    }
7301	}
7302
7303	// @ts-nocheck
7304	class Deferred {
7305	    get reject() { return this._reject; }
7306	    get resolve() { return this._resolve; }
7307	    constructor() {
7308	        this.promise = new Promise((resolve, reject) => {
7309	            this._resolve = resolve;
7310	            this._reject = reject;
7311	        });
7312	    }
7313	}
7314
7315	// @ts-nocheck
7316	class EventTarget {
7317	    constructor() {
7318	        this._eventEmitter = new eventsExports.EventEmitter();
7319	    }
7320	    addEventListener(name, handler) {
7321	        return this._eventEmitter.addListener(name, handler);
7322	    }
7323	    dispatchEvent(name, ...args) {
7324	        return this._eventEmitter.emit(name, ...args);
7325	    }
7326	    removeEventListener(name, handler) {
7327	        return this._eventEmitter.removeListener(name, handler);
7328	    }
7329	}
7330
7331	/**
7332	 * An {@link AudioPlayer} is an HTMLAudioElement-like object that uses AudioContext
7333	 *   to circumvent browser limitations.
7334	 * @private
7335	 */
7336	class AudioPlayer extends EventTarget {
7337	    get destination() { return this._destination; }
7338	    get loop() { return this._loop; }
7339	    set loop(shouldLoop) {
7340	        const self = this;
7341	        function pauseAfterPlaythrough() {
7342	            self._audioNode.removeEventListener('ended', pauseAfterPlaythrough);
7343	            self.pause();
7344	        }
7345	        // If a sound is already looping, it should continue playing
7346	        //   the current playthrough and then stop.
7347	        if (!shouldLoop && this.loop && !this.paused) {
7348	            this._audioNode.addEventListener('ended', pauseAfterPlaythrough);
7349	        }
7350	        this._loop = shouldLoop;
7351	    }
7352	    /**
7353	     * Whether the audio element is muted.
7354	     */
7355	    get muted() { return this._gainNode.gain.value === 0; }
7356	    set muted(shouldBeMuted) {
7357	        this._gainNode.gain.value = shouldBeMuted ? 0 : 1;
7358	    }
7359	    /**
7360	     * Whether the sound is paused. this._audioNode only exists when sound is playing;
7361	     *   otherwise AudioPlayer is considered paused.
7362	     */
7363	    get paused() { return this._audioNode === null; }
7364	    get src() { return this._src; }
7365	    set src(src) {
7366	        this._load(src);
7367	    }
7368	    /**
7369	     * The srcObject of the HTMLMediaElement
7370	     */
7371	    get srcObject() {
7372	        return this._audioElement.srcObject;
7373	    }
7374	    set srcObject(srcObject) {
7375	        this._audioElement.srcObject = srcObject;
7376	    }
7377	    get sinkId() { return this._sinkId; }
7378	    /**
7379	     * @private
7380	     */
7381	    constructor(audioContext, srcOrOptions = {}, options = {}) {
7382	        super();
7383	        /**
7384	         * The AudioBufferSourceNode of the actively loaded sound. Null if a sound
7385	         *   has not been loaded yet. This is re-used for each time the sound is
7386	         *   played.
7387	         */
7388	        this._audioNode = null;
7389	        /**
7390	         * Whether or not the audio element should loop. If disabled during playback,
7391	         *   playing continues until the sound ends and then stops looping.
7392	         */
7393	        this._loop = false;
7394	        /**
7395	         * An Array of deferred-like objects for each pending `play` Promise. When
7396	         *   .pause() is called or .src is set, all pending play Promises are
7397	         *   immediately rejected.
7398	         */
7399	        this._pendingPlayDeferreds = [];
7400	        /**
7401	         * The current sinkId of the device audio is being played through.
7402	         */
7403	        this._sinkId = 'default';
7404	        /**
7405	         * The source URL of the sound to play. When set, the currently playing sound will stop.
7406	         */
7407	        this._src = '';
7408	        if (typeof srcOrOptions !== 'string') {
7409	            options = srcOrOptions;
7410	        }
7411	        this._audioContext = audioContext;
7412	        this._audioElement = new (options.AudioFactory || Audio)();
7413	        this._bufferPromise = this._createPlayDeferred().promise;
7414	        this._destination = this._audioContext.destination;
7415	        this._gainNode = this._audioContext.createGain();
7416	        this._gainNode.connect(this._destination);
7417	        this._XMLHttpRequest = options.XMLHttpRequestFactory || XMLHttpRequest;
7418	        this.addEventListener('canplaythrough', () => {
7419	            this._resolvePlayDeferreds();
7420	        });
7421	        if (typeof srcOrOptions === 'string') {
7422	            this.src = srcOrOptions;
7423	        }
7424	    }
7425	    /**
7426	     * Stop any ongoing playback and reload the source file.
7427	     */
7428	    load() {
7429	        this._load(this._src);
7430	    }
7431	    /**
7432	     * Pause the audio coming from this AudioPlayer. This will reject any pending
7433	     *   play Promises.
7434	     */
7435	    pause() {
7436	        if (this.paused) {
7437	            return;
7438	        }
7439	        this._audioElement.pause();
7440	        this._audioNode.stop();
7441	        this._audioNode.disconnect(this._gainNode);
7442	        this._audioNode = null;
7443	        this._rejectPlayDeferreds(new Error('The play() request was interrupted by a call to pause().'));
7444	    }
7445	    /**
7446	     * Play the sound. If the buffer hasn't loaded yet, wait for the buffer to load. If
7447	     *   the source URL is not set yet, this Promise will remain pending until a source
7448	     *   URL is set.
7449	     */
7450	    play() {
7451	        return __awaiter(this, void 0, void 0, function* () {
7452	            if (!this.paused) {
7453	                yield this._bufferPromise;
7454	                if (!this.paused) {
7455	                    return;
7456	                }
7457	                throw new Error('The play() request was interrupted by a call to pause().');
7458	            }
7459	            this._audioNode = this._audioContext.createBufferSource();
7460	            this._audioNode.loop = this.loop;
7461	            this._audioNode.addEventListener('ended', () => {
7462	                if (this._audioNode && this._audioNode.loop) {
7463	                    return;
7464	                }
7465	                this.dispatchEvent('ended');
7466	            });
7467	            const buffer = yield this._bufferPromise;
7468	            if (this.paused) {
7469	                throw new Error('The play() request was interrupted by a call to pause().');
7470	            }
7471	            this._audioNode.buffer = buffer;
7472	            this._audioNode.connect(this._gainNode);
7473	            this._audioNode.start();
7474	            if (this._audioElement.srcObject) {
7475	                return this._audioElement.play();
7476	            }
7477	        });
7478	    }
7479	    /**
7480	     * Change which device the sound should play through.
7481	     * @param sinkId - The sink of the device to play sound through.
7482	     */
7483	    setSinkId(sinkId) {
7484	        return __awaiter(this, void 0, void 0, function* () {
7485	            if (typeof this._audioElement.setSinkId !== 'function') {
7486	                throw new Error('This browser does not support setSinkId.');
7487	            }
7488	            if (sinkId === this.sinkId) {
7489	                return;
7490	            }
7491	            if (sinkId === 'default') {
7492	                if (!this.paused) {
7493	                    this._gainNode.disconnect(this._destination);
7494	                }
7495	                this._audioElement.srcObject = null;
7496	                this._destination = this._audioContext.destination;
7497	                this._gainNode.connect(this._destination);
7498	                this._sinkId = sinkId;
7499	                return;
7500	            }
7501	            yield this._audioElement.setSinkId(sinkId);
7502	            if (this._audioElement.srcObject) {
7503	                return;
7504	            }
7505	            this._gainNode.disconnect(this._audioContext.destination);
7506	            this._destination = this._audioContext.createMediaStreamDestination();
7507	            this._audioElement.srcObject = this._destination.stream;
7508	            this._sinkId = sinkId;
7509	            this._gainNode.connect(this._destination);
7510	        });
7511	    }
7512	    /**
7513	     * Create a Deferred for a Promise that will be resolved when .src is set or rejected
7514	     *   when .pause is called.
7515	     */
7516	    _createPlayDeferred() {
7517	        const deferred = new Deferred();
7518	        this._pendingPlayDeferreds.push(deferred);
7519	        return deferred;
7520	    }
7521	    /**
7522	     * Stop current playback and load a sound file.
7523	     * @param src - The source URL of the file to load
7524	     */
7525	    _load(src) {
7526	        if (this._src && this._src !== src) {
7527	            this.pause();
7528	        }
7529	        this._src = src;
7530	        this._bufferPromise = new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
7531	            if (!src) {
7532	                return this._createPlayDeferred().promise;
7533	            }
7534	            const buffer = yield bufferSound(this._audioContext, this._XMLHttpRequest, src);
7535	            this.dispatchEvent('canplaythrough');
7536	            resolve(buffer);
7537	        }));
7538	    }
7539	    /**
7540	     * Reject all deferreds for the Play promise.
7541	     * @param reason
7542	     */
7543	    _rejectPlayDeferreds(reason) {
7544	        const deferreds = this._pendingPlayDeferreds;
7545	        deferreds.splice(0, deferreds.length).forEach(({ reject }) => reject(reason));
7546	    }
7547	    /**
7548	     * Resolve all deferreds for the Play promise.
7549	     * @param result
7550	     */
7551	    _resolvePlayDeferreds(result) {
7552	        const deferreds = this._pendingPlayDeferreds;
7553	        deferreds.splice(0, deferreds.length).forEach(({ resolve }) => resolve(result));
7554	    }
7555	}
7556	/**
7557	 * Use XMLHttpRequest to load the AudioBuffer of a remote audio asset.
7558	 * @private
7559	 * @param context - The AudioContext to use to decode the audio data
7560	 * @param RequestFactory - The XMLHttpRequest factory to build
7561	 * @param src - The URL of the audio asset to load.
7562	 * @returns A Promise containing the decoded AudioBuffer.
7563	 */
7564	// tslint:disable-next-line:variable-name
7565	function bufferSound(context, RequestFactory, src) {
7566	    return __awaiter(this, void 0, void 0, function* () {
7567	        const request = new RequestFactory();
7568	        request.open('GET', src, true);
7569	        request.responseType = 'arraybuffer';
7570	        const event = yield new Promise(resolve => {
7571	            request.addEventListener('load', resolve);
7572	            request.send();
7573	        });
7574	        // Safari uses a callback here instead of a Promise.
7575	        try {
7576	            return context.decodeAudioData(event.target.response);
7577	        }
7578	        catch (e) {
7579	            return new Promise(resolve => {
7580	                context.decodeAudioData(event.target.response, resolve);
7581	            });
7582	        }
7583	    });
7584	}
7585
7586	// @ts-nocheck
7587	/**
7588	 * @class
7589	 * @param {string} name - Name of the sound
7590	 * @param {string} url - URL of the sound
7591	 * @param {Sound#ConstructorOptions} options
7592	 * @property {boolean} isPlaying - Whether the Sound is currently playing audio.
7593	 * @property {string} name - Name of the sound
7594	 * @property {string} url - URL of the sound
7595	 * @property {AudioContext} audioContext - The AudioContext to use if available for AudioPlayer.
7596	 */
7597	/**
7598	 * @typedef {Object} Sound#ConstructorOptions
7599	 * @property {number} [maxDuration=0] - The maximum length of time to play the sound
7600	 *   before stopping it.
7601	 * @property {Boolean} [shouldLoop=false] - Whether the sound should be looped.
7602	 */
7603	function Sound(name, url, options) {
7604	    if (!(this instanceof Sound)) {
7605	        return new Sound(name, url, options);
7606	    }
7607	    if (!name || !url) {
7608	        throw new InvalidArgumentError('name and url are required arguments');
7609	    }
7610	    options = Object.assign({
7611	        AudioFactory: typeof Audio !== 'undefined' ? Audio : null,
7612	        maxDuration: 0,
7613	        shouldLoop: false,
7614	    }, options);
7615	    options.AudioPlayer = options.audioContext
7616	        ? AudioPlayer.bind(AudioPlayer, options.audioContext)
7617	        : options.AudioFactory;
7618	    Object.defineProperties(this, {
7619	        _Audio: { value: options.AudioPlayer },
7620	        _activeEls: { value: new Map() },
7621	        _isSinkSupported: {
7622	            value: options.AudioFactory !== null
7623	                && typeof options.AudioFactory.prototype.setSinkId === 'function',
7624	        },
7625	        _maxDuration: { value: options.maxDuration },
7626	        _maxDurationTimeout: {
7627	            value: null,
7628	            writable: true,
7629	        },
7630	        _operations: { value: new AsyncQueue() },
7631	        _playPromise: {
7632	            value: null,
7633	            writable: true,
7634	        },
7635	        _shouldLoop: { value: options.shouldLoop },
7636	        _sinkIds: { value: ['default'] },
7637	        isPlaying: {
7638	            enumerable: true,
7639	            get() {
7640	                return !!this._playPromise;
7641	            },
7642	        },
7643	        name: {
7644	            enumerable: true,
7645	            value: name,
7646	        },
7647	        url: {
7648	            enumerable: true,
7649	            value: url,
7650	        },
7651	    });
7652	    if (this._Audio) {
7653	        // Play it (muted and should not loop) as soon as possible so that it does not get incorrectly caught by Chrome's
7654	        // "gesture requirement for media playback" feature.
7655	        // https://plus.google.com/+FrancoisBeaufort/posts/6PiJQqJzGqX
7656	        this._play(true, false);
7657	    }
7658	}
7659	function destroyAudioElement(audioElement) {
7660	    if (audioElement) {
7661	        audioElement.pause();
7662	        audioElement.src = '';
7663	        audioElement.srcObject = null;
7664	        audioElement.load();
7665	    }
7666	}
7667	/**
7668	 * Plays the audio element that was initialized using the speficied sinkId
7669	 */
7670	Sound.prototype._playAudioElement = function _playAudioElement(sinkId, isMuted, shouldLoop) {
7671	    const audioElement = this._activeEls.get(sinkId);
7672	    if (!audioElement) {
7673	        throw new InvalidArgumentError(`sinkId: "${sinkId}" doesn't have an audio element`);
7674	    }
7675	    audioElement.muted = !!isMuted;
7676	    audioElement.loop = !!shouldLoop;
7677	    return audioElement.play()
7678	        .then(() => audioElement)
7679	        .catch((reason) => {
7680	        destroyAudioElement(audioElement);
7681	        this._activeEls.delete(sinkId);
7682	        throw reason;
7683	    });
7684	};
7685	/**
7686	 * Start playing the sound. Will stop the currently playing sound first.
7687	 * If it exists, the audio element that was initialized for the sinkId will be used
7688	 */
7689	Sound.prototype._play = function _play(forceIsMuted, forceShouldLoop) {
7690	    if (this.isPlaying) {
7691	        this._stop();
7692	    }
7693	    if (this._maxDuration > 0) {
7694	        this._maxDurationTimeout = setTimeout(this._stop.bind(this), this._maxDuration);
7695	    }
7696	    forceShouldLoop = typeof forceShouldLoop === 'boolean' ? forceShouldLoop : this._shouldLoop;
7697	    const self = this;
7698	    const playPromise = this._playPromise = Promise.all(this._sinkIds.map(function createAudioElement(sinkId) {
7699	        if (!self._Audio) {
7700	            return Promise.resolve();
7701	        }
7702	        let audioElement = self._activeEls.get(sinkId);
7703	        if (audioElement) {
7704	            return self._playAudioElement(sinkId, forceIsMuted, forceShouldLoop);
7705	        }
7706	        audioElement = new self._Audio(self.url);
7707	        // Make sure the browser always retrieves the resource using CORS.
7708	        // By default when using media tags, origin header is not sent to server
7709	        // which causes the server to not return CORS headers. When this caches
7710	        // on the CDN or browser, it causes issues to future requests that needs CORS,
7711	        // which is true when using AudioContext. Please note that we won't have to do this
7712	        // once we migrate to CloudFront.
7713	        if (typeof audioElement.setAttribute === 'function') {
7714	            audioElement.setAttribute('crossorigin', 'anonymous');
7715	        }
7716	        /**
7717	         * (rrowland) Bug in Chrome 53 & 54 prevents us from calling Audio.setSinkId without
7718	         *   crashing the tab. https://bugs.chromium.org/p/chromium/issues/detail?id=655342
7719	         */
7720	        return new Promise(resolve => {
7721	            audioElement.addEventListener('canplaythrough', resolve);
7722	        }).then(() => {
7723	            return (self._isSinkSupported
7724	                ? audioElement.setSinkId(sinkId)
7725	                : Promise.resolve()).then(function setSinkIdSuccess() {
7726	                self._activeEls.set(sinkId, audioElement);
7727	                // Stop has been called, bail out
7728	                if (!self._playPromise) {
7729	                    return Promise.resolve();
7730	                }
7731	                return self._playAudioElement(sinkId, forceIsMuted, forceShouldLoop);
7732	            });
7733	        });
7734	    }));
7735	    return playPromise;
7736	};
7737	/**
7738	 * Stop playing the sound.
7739	 */
7740	Sound.prototype._stop = function _stop() {
7741	    this._activeEls.forEach((audioEl, sinkId) => {
7742	        if (this._sinkIds.includes(sinkId)) {
7743	            audioEl.pause();
7744	            audioEl.currentTime = 0;
7745	        }
7746	        else {
7747	            // Destroy the ones that are not used anymore
7748	            destroyAudioElement(audioEl);
7749	            this._activeEls.delete(sinkId);
7750	        }
7751	    });
7752	    clearTimeout(this._maxDurationTimeout);
7753	    this._playPromise = null;
7754	    this._maxDurationTimeout = null;
7755	};
7756	/**
7757	 * Update the sinkIds of the audio output devices this sound should play through.
7758	 */
7759	Sound.prototype.setSinkIds = function setSinkIds(ids) {
7760	    if (!this._isSinkSupported) {
7761	        return;
7762	    }
7763	    ids = ids.forEach ? ids : [ids];
7764	    [].splice.apply(this._sinkIds, [0, this._sinkIds.length].concat(ids));
7765	};
7766	/**
7767	 * Add a stop operation to the queue
7768	 */
7769	Sound.prototype.stop = function stop() {
7770	    this._operations.enqueue(() => {
7771	        this._stop();
7772	        return Promise.resolve();
7773	    });
7774	};
7775	/**
7776	 * Add a play operation to the queue
7777	 */
7778	Sound.prototype.play = function play() {
7779	    return this._operations.enqueue(() => this._play());
7780	};
7781
7782	const REGISTRATION_INTERVAL = 30000;
7783	const RINGTONE_PLAY_TIMEOUT = 2000;
7784	const PUBLISHER_PRODUCT_NAME = 'twilio-js-sdk';
7785	const INVALID_TOKEN_MESSAGE = 'Parameter "token" must be of type "string".';
7786	/**
7787	 * Twilio Device. Allows registration for incoming calls, and placing outgoing calls.
7788	 */
7789	class Device extends eventsExports.EventEmitter {
7790	    /**
7791	     * The AudioContext to be used by {@link Device} instances.
7792	     * @private
7793	     */
7794	    static get audioContext() {
7795	        return Device._audioContext;
7796	    }
7797	    /**
7798	     * Which sound file extension is supported.
7799	     * @private
7800	     */
7801	    static get extension() {
7802	        // NOTE(mroberts): Node workaround.
7803	        const a = typeof document !== 'undefined'
7804	            ? document.createElement('audio') : { canPlayType: false };
7805	        let canPlayMp3;
7806	        try {
7807	            canPlayMp3 = a.canPlayType && !!a.canPlayType('audio/mpeg').replace(/no/, '');
7808	        }
7809	        catch (e) {
7810	            canPlayMp3 = false;
7811	        }
7812	        let canPlayVorbis;
7813	        try {
7814	            canPlayVorbis = a.canPlayType && !!a.canPlayType('audio/ogg;codecs=\'vorbis\'').replace(/no/, '');
7815	        }
7816	        catch (e) {
7817	            canPlayVorbis = false;
7818	        }
7819	        return (canPlayVorbis && !canPlayMp3) ? 'ogg' : 'mp3';
7820	    }
7821	    /**
7822	     * Whether or not this SDK is supported by the current browser.
7823	     */
7824	    static get isSupported() { return enabled(); }
7825	    /**
7826	     * Package name of the SDK.
7827	     */
7828	    static get packageName() { return PACKAGE_NAME; }
7829	    /**
7830	     * Run some tests to identify issues, if any, prohibiting successful calling.
7831	     * @param token - A Twilio JWT token string
7832	     * @param options
7833	     */
7834	    static runPreflight(token, options) {
7835	        return new PreflightTest(token, Object.assign({ audioContext: Device._getOrCreateAudioContext() }, options));
7836	    }
7837	    /**
7838	     * String representation of {@link Device} class.
7839	     * @private
7840	     */
7841	    static toString() {
7842	        return '[Twilio.Device class]';
7843	    }
7844	    /**
7845	     * Current SDK version.
7846	     */
7847	    static get version() { return RELEASE_VERSION; }
7848	    /**
7849	     * Initializes the AudioContext instance shared across the Voice SDK,
7850	     * or returns the existing instance if one has already been initialized.
7851	     */
7852	    static _getOrCreateAudioContext() {
7853	        if (!Device._audioContext) {
7854	            if (typeof AudioContext !== 'undefined') {
7855	                Device._audioContext = new AudioContext();
7856	            }
7857	            else if (typeof webkitAudioContext !== 'undefined') {
7858	                Device._audioContext = new webkitAudioContext();
7859	            }
7860	        }
7861	        return Device._audioContext;
7862	    }
7863	    /**
7864	     * Construct a {@link Device} instance. The {@link Device} can be registered
7865	     * to make and listen for calls using {@link Device.register}.
7866	     * @param options
7867	     */
7868	    constructor(token, options = {}) {
7869	        super();
7870	        /**
7871	         * The currently active {@link Call}, if there is one.
7872	         */
7873	        this._activeCall = null;
7874	        /**
7875	         * The AudioHelper instance associated with this {@link Device}.
7876	         */
7877	        this._audio = null;
7878	        /**
7879	         * The AudioProcessorEventObserver instance to use
7880	         */
7881	        this._audioProcessorEventObserver = null;
7882	        /**
7883	         * An audio input MediaStream to pass to new {@link Call} instances.
7884	         */
7885	        this._callInputStream = null;
7886	        /**
7887	         * An array of {@link Call}s. Though only one can be active, multiple may exist when there
7888	         * are multiple incoming, unanswered {@link Call}s.
7889	         */
7890	        this._calls = [];
7891	        /**
7892	         * An array of {@link Device} IDs to be used to play sounds through, to be passed to
7893	         * new {@link Call} instances.
7894	         */
7895	        this._callSinkIds = ['default'];
7896	        /**
7897	         * The list of chunder URIs that will be passed to PStream
7898	         */
7899	        this._chunderURIs = [];
7900	        /**
7901	         * Default options used by {@link Device}.
7902	         */
7903	        this._defaultOptions = {
7904	            allowIncomingWhileBusy: false,
7905	            closeProtection: false,
7906	            codecPreferences: [Call.Codec.PCMU, Call.Codec.Opus],
7907	            dscp: true,
7908	            enableImprovedSignalingErrorPrecision: false,
7909	            forceAggressiveIceNomination: false,
7910	            logLevel: loglevelExports.levels.ERROR,
7911	            maxCallSignalingTimeoutMs: 0,
7912	            preflight: false,
7913	            sounds: {},
7914	            tokenRefreshMs: 10000,
7915	            voiceEventSidGenerator: generateVoiceEventSid,
7916	        };
7917	        /**
7918	         * The name of the edge the {@link Device} is connected to.
7919	         */
7920	        this._edge = null;
7921	        /**
7922	         * The name of the home region the {@link Device} is connected to.
7923	         */
7924	        this._home = null;
7925	        /**
7926	         * The identity associated with this Device.
7927	         */
7928	        this._identity = null;
7929	        /**
7930	         * An instance of Logger to use.
7931	         */
7932	        this._log = new Log('Device');
7933	        /**
7934	         * The internal promise created when calling {@link Device.makeCall}.
7935	         */
7936	        this._makeCallPromise = null;
7937	        /**
7938	         * The options passed to {@link Device} constructor or {@link Device.updateOptions}.
7939	         */
7940	        this._options = {};
7941	        /**
7942	         * The preferred URI to (re)-connect signaling to.
7943	         */
7944	        this._preferredURI = null;
7945	        /**
7946	         * An Insights Event Publisher.
7947	         */
7948	        this._publisher = null;
7949	        /**
7950	         * The region the {@link Device} is connected to.
7951	         */
7952	        this._region = null;
7953	        /**
7954	         * A timeout ID for a setTimeout schedule to re-register the {@link Device}.
7955	         */
7956	        this._regTimer = null;
7957	        /**
7958	         * Boolean representing whether or not the {@link Device} was registered when
7959	         * receiving a signaling `offline`. Determines if the {@link Device} attempts
7960	         * a `re-register` once signaling is re-established when receiving a
7961	         * `connected` event from the stream.
7962	         */
7963	        this._shouldReRegister = false;
7964	        /**
7965	         * A Map of Sounds to play.
7966	         */
7967	        this._soundcache = new Map();
7968	        /**
7969	         * The current status of the {@link Device}.
7970	         */
7971	        this._state = Device.State.Unregistered;
7972	        /**
7973	         * A map from {@link Device.State} to {@link Device.EventName}.
7974	         */
7975	        this._stateEventMapping = {
7976	            [Device.State.Destroyed]: Device.EventName.Destroyed,
7977	            [Device.State.Unregistered]: Device.EventName.Unregistered,
7978	            [Device.State.Registering]: Device.EventName.Registering,
7979	            [Device.State.Registered]: Device.EventName.Registered,
7980	        };
7981	        /**
7982	         * The Signaling stream.
7983	         */
7984	        this._stream = null;
7985	        /**
7986	         * A promise that will resolve when the Signaling stream is ready.
7987	         */
7988	        this._streamConnectedPromise = null;
7989	        /**
7990	         * A timeout to track when the current AccessToken will expire.
7991	         */
7992	        this._tokenWillExpireTimeout = null;
7993	        /**
7994	         * Create the default Insights payload
7995	         * @param call
7996	         */
7997	        this._createDefaultPayload = (call) => {
7998	            const payload = {
7999	                aggressive_nomination: this._options.forceAggressiveIceNomination,
8000	                browser_extension: this._isBrowserExtension,
8001	                dscp: !!this._options.dscp,
8002	                ice_restart_enabled: true,
8003	                platform: getMediaEngine(),
8004	                sdk_version: RELEASE_VERSION,
8005	            };
8006	            function setIfDefined(propertyName, value) {
8007	                if (value) {
8008	                    payload[propertyName] = value;
8009	                }
8010	            }
8011	            if (call) {
8012	                const callSid = call.parameters.CallSid;
8013	                setIfDefined('call_sid', /^TJ/.test(callSid) ? undefined : callSid);
8014	                setIfDefined('temp_call_sid', call.outboundConnectionId);
8015	                setIfDefined('audio_codec', call.codec);
8016	                payload.direction = call.direction;
8017	            }
8018	            setIfDefined('gateway', this._stream && this._stream.gateway);
8019	            setIfDefined('region', this._stream && this._stream.region);
8020	            return payload;
8021	        };
8022	        /**
8023	         * Called when a 'close' event is received from the signaling stream.
8024	         */
8025	        this._onSignalingClose = () => {
8026	            this._stream = null;
8027	            this._streamConnectedPromise = null;
8028	        };
8029	        /**
8030	         * Called when a 'connected' event is received from the signaling stream.
8031	         */
8032	        this._onSignalingConnected = (payload) => {
8033	            var _a;
8034	            const region = getRegionShortcode(payload.region);
8035	            this._edge = payload.edge || regionToEdge[region] || payload.region;
8036	            this._region = region || payload.region;
8037	            this._home = payload.home;
8038	            (_a = this._publisher) === null || _a === void 0 ? void 0 : _a.setHost(createEventGatewayURI(payload.home));
8039	            if (payload.token) {
8040	                this._identity = payload.token.identity;
8041	                if (typeof payload.token.ttl === 'number' &&
8042	                    typeof this._options.tokenRefreshMs === 'number') {
8043	                    const ttlMs = payload.token.ttl * 1000;
8044	                    const timeoutMs = Math.max(0, ttlMs - this._options.tokenRefreshMs);
8045	                    this._tokenWillExpireTimeout = setTimeout(() => {
8046	                        this._log.debug('#tokenWillExpire');
8047	                        this.emit('tokenWillExpire', this);
8048	                        if (this._tokenWillExpireTimeout) {
8049	                            clearTimeout(this._tokenWillExpireTimeout);
8050	                            this._tokenWillExpireTimeout = null;
8051	                        }
8052	                    }, timeoutMs);
8053	                }
8054	            }
8055	            const preferredURIs = this._getChunderws() || getChunderURIs(this._edge);
8056	            if (preferredURIs.length > 0) {
8057	                const [preferredURI] = preferredURIs;
8058	                this._preferredURI = createSignalingEndpointURL(preferredURI);
8059	            }
8060	            else {
8061	                this._log.warn('Could not parse a preferred URI from the stream#connected event.');
8062	            }
8063	            // The signaling stream emits a `connected` event after reconnection, if the
8064	            // device was registered before this, then register again.
8065	            if (this._shouldReRegister) {
8066	                this.register();
8067	            }
8068	        };
8069	        /**
8070	         * Called when an 'error' event is received from the signaling stream.
8071	         */
8072	        this._onSignalingError = (payload) => {
8073	            if (typeof payload !== 'object') {
8074	                this._log.warn('Invalid signaling error payload', payload);
8075	                return;
8076	            }
8077	            const { error: originalError, callsid, voiceeventsid } = payload;
8078	            // voiceeventsid is for call message events which are handled in the call object
8079	            // missing originalError shouldn't be possible but check here to fail properly
8080	            if (typeof originalError !== 'object' || !!voiceeventsid) {
8081	                this._log.warn('Ignoring signaling error payload', { originalError, voiceeventsid });
8082	                return;
8083	            }
8084	            const call = (typeof callsid === 'string' && this._findCall(callsid)) || undefined;
8085	            const { code, message: customMessage } = originalError;
8086	            let { twilioError } = originalError;
8087	            if (typeof code === 'number') {
8088	                if (code === 31201) {
8089	                    twilioError = new AuthorizationErrors.AuthenticationFailed(originalError);
8090	                }
8091	                else if (code === 31204) {
8092	                    twilioError = new AuthorizationErrors.AccessTokenInvalid(originalError);
8093	                }
8094	                else if (code === 31205) {
8095	                    // Stop trying to register presence after token expires
8096	                    this._stopRegistrationTimer();
8097	                    twilioError = new AuthorizationErrors.AccessTokenExpired(originalError);
8098	                }
8099	                else {
8100	                    const errorConstructor = getPreciseSignalingErrorByCode(!!this._options.enableImprovedSignalingErrorPrecision, code);
8101	                    if (typeof errorConstructor !== 'undefined') {
8102	                        twilioError = new errorConstructor(originalError);
8103	                    }
8104	                }
8105	            }
8106	            if (!twilioError) {
8107	                this._log.error('Unknown signaling error: ', originalError);
8108	                twilioError = new GeneralErrors.UnknownError(customMessage, originalError);
8109	            }
8110	            this._log.error('Received error: ', twilioError);
8111	            this._log.debug('#error', originalError);
8112	            this.emit(Device.EventName.Error, twilioError, call);
8113	        };
8114	        /**
8115	         * Called when an 'invite' event is received from the signaling stream.
8116	         */
8117	        this._onSignalingInvite = (payload) => __awaiter(this, void 0, void 0, function* () {
8118	            var _a;
8119	            const wasBusy = !!this._activeCall;
8120	            if (wasBusy && !this._options.allowIncomingWhileBusy) {
8121	                this._log.info('Device busy; ignoring incoming invite');
8122	                return;
8123	            }
8124	            if (!payload.callsid || !payload.sdp) {
8125	                this._log.debug('#error', payload);
8126	                this.emit(Device.EventName.Error, new ClientErrors.BadRequest('Malformed invite from gateway'));
8127	                return;
8128	            }
8129	            const callParameters = payload.parameters || {};
8130	            callParameters.CallSid = callParameters.CallSid || payload.callsid;
8131	            const customParameters = Object.assign({}, queryToJson(callParameters.Params));
8132	            this._makeCallPromise = this._makeCall(customParameters, {
8133	                callParameters,
8134	                enableImprovedSignalingErrorPrecision: !!this._options.enableImprovedSignalingErrorPrecision,
8135	                offerSdp: payload.sdp,
8136	                reconnectToken: payload.reconnect,
8137	                voiceEventSidGenerator: this._options.voiceEventSidGenerator,
8138	            });
8139	            let call;
8140	            try {
8141	                call = yield this._makeCallPromise;
8142	            }
8143	            finally {
8144	                this._makeCallPromise = null;
8145	            }
8146	            this._calls.push(call);
8147	            call.once('accept', () => {
8148	                this._soundcache.get(Device.SoundName.Incoming).stop();
8149	                this._publishNetworkChange();
8150	            });
8151	            const play = (((_a = this._audio) === null || _a === void 0 ? void 0 : _a.incoming()) && !wasBusy)
8152	                ? () => this._soundcache.get(Device.SoundName.Incoming).play()
8153	                : () => Promise.resolve();
8154	            this._showIncomingCall(call, play);
8155	        });
8156	        /**
8157	         * Called when an 'offline' event is received from the signaling stream.
8158	         */
8159	        this._onSignalingOffline = () => {
8160	            this._log.info('Stream is offline');
8161	            this._edge = null;
8162	            this._region = null;
8163	            this._shouldReRegister = this.state !== Device.State.Unregistered;
8164	            this._setState(Device.State.Unregistered);
8165	        };
8166	        /**
8167	         * Called when a 'ready' event is received from the signaling stream.
8168	         */
8169	        this._onSignalingReady = () => {
8170	            this._log.info('Stream is ready');
8171	            this._setState(Device.State.Registered);
8172	        };
8173	        /**
8174	         * Publish a NetworkInformation#change event to Insights if there's an active {@link Call}.
8175	         */
8176	        this._publishNetworkChange = () => {
8177	            if (!this._activeCall) {
8178	                return;
8179	            }
8180	            if (this._networkInformation) {
8181	                this._publisher.info('network-information', 'network-change', {
8182	                    connection_type: this._networkInformation.type,
8183	                    downlink: this._networkInformation.downlink,
8184	                    downlinkMax: this._networkInformation.downlinkMax,
8185	                    effective_type: this._networkInformation.effectiveType,
8186	                    rtt: this._networkInformation.rtt,
8187	                }, this._activeCall);
8188	            }
8189	        };
8190	        /**
8191	         * Update the input stream being used for calls so that any current call and all future calls
8192	         * will use the new input stream.
8193	         * @param inputStream
8194	         */
8195	        this._updateInputStream = (inputStream) => {
8196	            const call = this._activeCall;
8197	            if (call && !inputStream) {
8198	                return Promise.reject(new InvalidStateError('Cannot unset input device while a call is in progress.'));
8199	            }
8200	            this._callInputStream = inputStream;
8201	            return call
8202	                ? call._setInputTracksFromStream(inputStream)
8203	                : Promise.resolve();
8204	        };
8205	        /**
8206	         * Update the device IDs of output devices being used to play sounds through.
8207	         * @param type - Whether to update ringtone or speaker sounds
8208	         * @param sinkIds - An array of device IDs
8209	         */
8210	        this._updateSinkIds = (type, sinkIds) => {
8211	            const promise = type === 'ringtone'
8212	                ? this._updateRingtoneSinkIds(sinkIds)
8213	                : this._updateSpeakerSinkIds(sinkIds);
8214	            return promise.then(() => {
8215	                this._publisher.info('audio', `${type}-devices-set`, {
8216	                    audio_device_ids: sinkIds,
8217	                }, this._activeCall);
8218	            }, error => {
8219	                this._publisher.error('audio', `${type}-devices-set-failed`, {
8220	                    audio_device_ids: sinkIds,
8221	                    message: error.message,
8222	                }, this._activeCall);
8223	                throw error;
8224	            });
8225	        };
8226	        // Setup loglevel asap to avoid missed logs
8227	        this._setupLoglevel(options.logLevel);
8228	        this._logOptions('constructor', options);
8229	        this.updateToken(token);
8230	        if (isLegacyEdge()) {
8231	            throw new NotSupportedError('Microsoft Edge Legacy (https://support.microsoft.com/en-us
8231/help/4533505/what-is-microsoft-edge-legacy) ' +
8232	                'is deprecated and will not be able to connect to Twilio to make or receive calls after September 1st, 2020. ' +
8233	                'Please see this documentation for a list of supported browsers ' +
8234	                'https://www.twilio.com/docs/voice/client/javascript#supported-browsers');
8235	        }
8236	        if (!Device.isSupported && options.ignoreBrowserSupport) {
8237	            if (window && window.location && window.location.protocol === 'http:') {
8238	                throw new NotSupportedError(`twilio.js wasn't able to find WebRTC browser support. \
8239          This is most likely because this page is served over http rather than https, \
8240          which does not support WebRTC in many browsers. Please load this page over https and \
8241          try again.`);
8242	            }
8243	            throw new NotSupportedError(`twilio.js 1.3+ SDKs require WebRTC browser support. \
8244        For more information, see <https://www.twilio.com/docs/api/client/twilio-js>. \
8245        If you have any questions about this announcement, please contact \
8246        Twilio Support at <[email protected]>.`);
8247	        }
8248	        const root = globalThis;
8249	        const browser = root.msBrowser || root.browser || root.chrome;
8250	        this._isBrowserExtension = (!!browser && !!browser.runtime && !!browser.runtime.id)
8251	            || (!!root.safari && !!root.safari.extension);
8252	        if (this._isBrowserExtension) {
8253	            this._log.info('Running as browser extension.');
8254	        }
8255	        if (navigator) {
8256	            const n = navigator;
8257	            this._networkInformation = n.connection
8258	                || n.mozConnection
8259	                || n.webkitConnection;
8260	        }
8261	        if (this._networkInformation && typeof this._networkInformation.addEventListener === 'function') {
8262	            this._networkInformation.addEventListener('change', this._publishNetworkChange);
8263	        }
8264	        Device._getOrCreateAudioContext();
8265	        if (Device._audioContext) {
8266	            if (!Device._dialtonePlayer) {
8267	                Device._dialtonePlayer = new DialtonePlayer(Device._audioContext);
8268	            }
8269	        }
8270	        this._boundDestroy = this.destroy.bind(this);
8271	        this._boundConfirmClose = this._confirmClose.bind(this);
8272	        if (typeof window !== 'undefined' && window.addEventListener) {
8273	            window.addEventListener('unload', this._boundDestroy);
8274	            window.addEventListener('pagehide', this._boundDestroy);
8275	        }
8276	        this.updateOptions(options);
8277	    }
8278	    /**
8279	     * Return the {@link AudioHelper} used by this {@link Device}.
8280	     */
8281	    get audio() {
8282	        return this._audio;
8283	    }
8284	    /**
8285	     * Make an outgoing Call.
8286	     * @param options
8287	     */
8288	    connect() {
8289	        return __awaiter(this, arguments, void 0, function* (options = {}) {
8290	            this._log.debug('.connect', JSON.stringify(options));
8291	            this._throwIfDestroyed();
8292	            if (this._activeCall) {
8293	                throw new InvalidStateError('A Call is already active');
8294	            }
8295	            let customParameters;
8296	            let parameters;
8297	            let signalingReconnectToken;
8298	            if (options.connectToken) {
8299	                try {
8300	                    const connectTokenParts = JSON.parse(decodeURIComponent(atob(options.connectToken)));
8301	                    customParameters = connectTokenParts.customParameters;
8302	                    parameters = connectTokenParts.parameters;
8303	                    signalingReconnectToken = connectTokenParts.signalingReconnectToken;
8304	                }
8305	                catch (_a) {
8306	                    throw new InvalidArgumentError('Cannot parse connectToken');
8307	                }
8308	                if (!parameters || !parameters.CallSid || !signalingReconnectToken) {
8309	                    throw new InvalidArgumentError('Invalid connectToken');
8310	                }
8311	            }
8312	            let isReconnect = false;
8313	            let twimlParams = {};
8314	            const callOptions = {
8315	                enableImprovedSignalingErrorPrecision: !!this._options.enableImprovedSignalingErrorPrecision,
8316	                rtcConfiguration: options.rtcConfiguration,
8317	                voiceEventSidGenerator: this._options.voiceEventSidGenerator,
8318	            };
8319	            if (signalingReconnectToken && parameters) {
8320	                isReconnect = true;
8321	                callOptions.callParameters = parameters;
8322	                callOptions.reconnectCallSid = parameters.CallSid;
8323	                callOptions.reconnectToken = signalingReconnectToken;
8324	                twimlParams = customParameters || twimlParams;
8325	            }
8326	            else {
8327	                twimlParams = options.params || twimlParams;
8328	            }
8329	            let activeCall;
8330	            this._makeCallPromise = this._makeCall(twimlParams, callOptions, isReconnect);
8331	            try {
8332	                activeCall = this._activeCall = yield this._makeCallPromise;
8333	            }
8334	            finally {
8335	                this._makeCallPromise = null;
8336	            }
8337	            // Make sure any incoming calls are ignored
8338	            this._calls.splice(0).forEach(call => call.ignore());
8339	            // Stop the incoming sound if it's playing
8340	            this._soundcache.get(Device.SoundName.Incoming).stop();
8341	            activeCall.accept({ rtcConstraints: options.rtcConstraints });
8342	            this._publishNetworkChange();
8343	            return activeCall;
8344	        });
8345	    }
8346	    /**
8347	     * Return the calls that this {@link Device} is maintaining.
8348	     */
8349	    get calls() {
8350	        return this._calls;
8351	    }
8352	    /**
8353	     * Destroy the {@link Device}, freeing references to be garbage collected.
8354	     */
8355	    destroy() {
8356	        var _a;
8357	        this._log.debug('.destroy');
8358	        this._log.debug('Rejecting any incoming calls');
8359	        const calls = this._calls.slice(0);
8360	        calls.forEach((call) => call.reject());
8361	        this.disconnectAll();
8362	        this._stopRegistrationTimer();
8363	        this._destroyStream();
8364	        this._destroyAudioHelper();
8365	        (_a = this._audioProcessorEventObserver) === null || _a === void 0 ? void 0 : _a.destroy();
8366	        this._destroyPublisher();
8367	        if (this._networkInformation && typeof this._networkInformation.removeEventListener === 'function') {
8368	            this._networkInformation.removeEventListener('change', this._publishNetworkChange);
8369	        }
8370	        if (typeof window !== 'undefined' && window.removeEventListener) {
8371	            window.removeEventListener('beforeunload', this._boundConfirmClose);
8372	            window.removeEventListener('unload', this._boundDestroy);
8373	            window.removeEventListener('pagehide', this._boundDestroy);
8374	        }
8375	        this._setState(Device.State.Destroyed);
8376	        eventsExports.EventEmitter.prototype.removeAllListeners.call(this);
8377	    }
8378	    /**
8379	     * Disconnect all {@link Call}s.
8380	     */
8381	    disconnectAll() {
8382	        this._log.debug('.disconnectAll');
8383	        const calls = this._calls.splice(0);
8384	        calls.forEach((call) => call.disconnect());
8385	        if (this._activeCall) {
8386	            this._activeCall.disconnect();
8387	        }
8388	    }
8389	    /**
8390	     * Returns the {@link Edge} value the {@link Device} is currently connected
8391	     * to. The value will be `null` when the {@link Device} is offline.
8392	     */
8393	    get edge() {
8394	        return this._edge;
8395	    }
8396	    /**
8397	     * Returns the home value the {@link Device} is currently connected
8398	     * to. The value will be `null` when the {@link Device} is offline.
8399	     */
8400	    get home() {
8401	        return this._home;
8402	    }
8403	    /**
8404	     * Returns the identity associated with the {@link Device} for incoming calls. Only
8405	     * populated when registered.
8406	     */
8407	    get identity() {
8408	        return this._identity;
8409	    }
8410	    /**
8411	     * Whether the Device is currently on an active Call.
8412	     */
8413	    get isBusy() {
8414	        return !!this._activeCall;
8415	    }
8416	    /**
8417	     * Register the `Device` to the Twilio backend, allowing it to receive calls.
8418	     */
8419	    register() {
8420	        return __awaiter(this, void 0, void 0, function* () {
8421	            this._log.debug('.register');
8422	            if (this.state !== Device.State.Unregistered) {
8423	                throw new InvalidStateError(`Attempt to register when device is in state "${this.state}". ` +
8424	                    `Must be "${Device.State.Unregistered}".`);
8425	            }
8426	            this._shouldReRegister = false;
8427	            this._setState(Device.State.Registering);
8428	            yield (this._streamConnectedPromise || this._setupStream());
8429	            yield this._sendPresence(true);
8430	            yield promisifyEvents(this, Device.State.Registered, Device.State.Unregistered);
8431	        });
8432	    }
8433	    /**
8434	     * Get the state of this {@link Device} instance
8435	     */
8436	    get state() {
8437	        return this._state;
8438	    }
8439	    /**
8440	     * Get the token used by this {@link Device}.
8441	     */
8442	    get token() {
8443	        return this._token;
8444	    }
8445	    /**
8446	     * String representation of {@link Device} instance.
8447	     * @private
8448	     */
8449	    toString() {
8450	        return '[Twilio.Device instance]';
8451	    }
8452	    /**
8453	     * Unregister the `Device` to the Twilio backend, disallowing it to receive
8454	     * calls.
8455	     */
8456	    unregister() {
8457	        return __awaiter(this, void 0, void 0, function* () {
8458	            this._log.debug('.unregister');
8459	            if (this.state !== Device.State.Registered) {
8460	                throw new InvalidStateError(`Attempt to unregister when device is in state "${this.state}". ` +
8461	                    `Must be "${Device.State.Registered}".`);
8462	            }
8463	            this._shouldReRegister = false;
8464	            const stream = yield this._streamConnectedPromise;
8465	            const streamOfflinePromise = new Promise(resolve => {
8466	                stream.on('offline', resolve);
8467	            });
8468	            yield this._sendPresence(false);
8469	            yield streamOfflinePromise;
8470	        });
8471	    }
8472	    /**
8473	     * Set the options used within the {@link Device}.
8474	     * @param options
8475	     */
8476	    updateOptions(options = {}) {
8477	        this._logOptions('updateOptions', options);
8478	        if (this.state === Device.State.Destroyed) {
8479	            throw new InvalidStateError(`Attempt to "updateOptions" when device is in state "${this.state}".`);
8480	        }
8481	        this._options = Object.assign(Object.assign(Object.assign({}, this._defaultOptions), this._options), options);
8482	        const originalChunderURIs = new Set(this._chunderURIs);
8483	        const newChunderURIs = this._chunderURIs = (this._getChunderws() || getChunderURIs(this._options.edge)).map(createSignalingEndpointURL);
8484	        let hasChunderURIsChanged = originalChunderURIs.size !== newChunderURIs.length;
8485	        if (!hasChunderURIsChanged) {
8486	            for (const uri of newChunderURIs) {
8487	                if (!originalChunderURIs.has(uri)) {
8488	                    hasChunderURIsChanged = true;
8489	                    break;
8490	                }
8491	            }
8492	        }
8493	        if (this.isBusy && hasChunderURIsChanged) {
8494	            throw new InvalidStateError('Cannot change Edge while on an active 
8494Call');
8495	        }
8496	        this._setupLoglevel(this._options.logLevel);
8497	        for (const name of Object.keys(Device._defaultSounds)) {
8498	            const soundDef = Device._defaultSounds[name];
8499	            const defaultUrl = `${SOUNDS_BASE_URL}/${soundDef.filename}.${Device.extension}`
8500	                + `?cache=${RELEASE_VERSION}`;
8501	            const soundUrl = this._options.sounds && this._options.sounds[name] || defaultUrl;
8502	            const sound = new (this._options.Sound || Sound)(name, soundUrl, {
8503	                audioContext: this._options.disableAudioContextSounds ? null : Device.audioContext,
8504	                maxDuration: soundDef.maxDuration,
8505	                shouldLoop: soundDef.shouldLoop,
8506	            });
8507	            this._soundcache.set(name, sound);
8508	        }
8509	        this._setupAudioHelper();
8510	        this._setupPublisher();
8511	        if (hasChunderURIsChanged && this._streamConnectedPromise) {
8512	            this._setupStream();
8513	        }
8514	        // Setup close protection and make sure we clean up ongoing calls on unload.
8515	        if (typeof window !== 'undefined' &&
8516	            typeof window.addEventListener === 'function' &&
8517	            this._options.closeProtection) {
8518	            window.removeEventListener('beforeunload', this._boundConfirmClose);
8519	            window.addEventListener('beforeunload', this._boundConfirmClose);
8520	        }
8521	    }
8522	    /**
8523	     * Update the token used by this {@link Device} to connect to Twilio.
8524	     * It is recommended to call this API after [[Device.tokenWillExpireEvent]] is emitted,
8525	     * and before or after a call to prevent a potential ~1s audio loss during the update process.
8526	     * @param token
8527	     */
8528	    updateToken(token) {
8529	        this._log.debug('.updateToken');
8530	        if (this.state === Device.State.Destroyed) {
8531	            throw new InvalidStateError(`Attempt to "updateToken" when device is in state "${this.state}".`);
8532	        }
8533	        if (typeof token !== 'string') {
8534	            throw new InvalidArgumentError(INVALID_TOKEN_MESSAGE);
8535	        }
8536	        this._token = token;
8537	        if (this._stream) {
8538	            this._stream.setToken(this._token);
8539	        }
8540	        if (this._publisher) {
8541	            this._publisher.setToken(this._token);
8542	        }
8543	    }
8544	    /**
8545	     * Called on window's beforeunload event if closeProtection is enabled,
8546	     * preventing users from accidentally navigating away from an active call.
8547	     * @param event
8548	     */
8549	    _confirmClose(event) {
8550	        if (!this._activeCall) {
8551	            return '';
8552	        }
8553	        const closeProtection = this._options.closeProtection || false;
8554	        const confirmationMsg = typeof closeProtection !== 'string'
8555	            ? 'A call is currently in-progress. Leaving or reloading this page will end the call.'
8556	            : closeProtection;
8557	        (event || window.event).returnValue = confirmationMsg;
8558	        return confirmationMsg;
8559	    }
8560	    /**
8561	     * Destroy the AudioHelper.
8562	     */
8563	    _destroyAudioHelper() {
8564	        if (!this._audio) {
8565	            return;
8566	        }
8567	        this._audio._destroy();
8568	        this._audio = null;
8569	    }
8570	    /**
8571	     * Destroy the publisher.
8572	     */
8573	    _destroyPublisher() {
8574	        // Attempt to destroy non-existent publisher.
8575	        if (!this._publisher) {
8576	            return;
8577	        }
8578	        this._publisher = null;
8579	    }
8580	    /**
8581	     * Destroy the connection to the signaling server.
8582	     */
8583	    _destroyStream() {
8584	        if (this._stream) {
8585	            this._stream.removeListener('close', this._onSignalingClose);
8586	            this._stream.removeListener('connected', this._onSignalingConnected);
8587	            this._stream.removeListener('error', this._onSignalingError);
8588	            this._stream.removeListener('invite', this._onSignalingInvite);
8589	            this._stream.removeListener('offline', this._onSignalingOffline);
8590	            this._stream.removeListener('ready', this._onSignalingReady);
8591	            this._stream.destroy();
8592	            this._stream = null;
8593	        }
8594	        this._onSignalingOffline();
8595	        this._streamConnectedPromise = null;
8596	    }
8597	    /**
8598	     * Find a {@link Call} by its CallSid.
8599	     * @param callSid
8600	     */
8601	    _findCall(callSid) {
8602	        return this._calls.find(call => call.parameters.CallSid === callSid
8603	            || call.outboundConnectionId === callSid) || null;
8604	    }
8605	    /**
8606	     * Get chunderws array from the chunderw param
8607	     */
8608	    _getChunderws() {
8609	        return typeof this._options.chunderw === 'string' ? [this._options.chunderw]
8610	            : Array.isArray(this._options.chunderw) ? this._options.chunderw : null;
8611	    }
8612	    /**
8613	     * Utility function to log device options
8614	     */
8615	    _logOptions(caller, options = {}) {
8616	        // Selectively log options that users can modify.
8617	        // Also, convert user overrides.
8618	        // This prevents potential app crash when calling JSON.stringify
8619	        // and when sending log strings remotely
8620	        const userOptions = [
8621	            'allowIncomingWhileBusy',
8622	            'appName',
8623	            'appVersion',
8624	            'closeProtection',
8625	            'codecPreferences',
8626	            'disableAudioContextSounds',
8627	            'dscp',
8628	            'edge',
8629	            'enableImprovedSignalingErrorPrecision',
8630	            'forceAggressiveIceNomination',
8631	            'logLevel',
8632	            'maxAverageBitrate',
8633	            'maxCallSignalingTimeoutMs',
8634	            'sounds',
8635	            'tokenRefreshMs',
8636	        ];
8637	        const userOptionOverrides = [
8638	            'RTCPeerConnection',
8639	            'enumerateDevices',
8640	            'getUserMedia',
8641	            'MediaStream',
8642	        ];
8643	        if (typeof options === 'object') {
8644	            const toLog = Object.assign({}, options);
8645	            Object.keys(toLog).forEach((key) => {
8646	                if (!userOptions.includes(key) && !userOptionOverrides.includes(key)) {
8647	                    delete toLog[key];
8648	                }
8649	                if (userOptionOverrides.includes(key)) {
8650	                    toLog[key] = true;
8651	                }
8652	            });
8653	            this._log.debug(`.${caller}`, JSON.stringify(toLog));
8654	        }
8655	    }
8656	    /**
8657	     * Create a new {@link Call}.
8658	     * @param twimlParams - A flat object containing key:value pairs to be sent to the TwiML app.
8659	     * @param options - Options to be used to instantiate the {@link Call}.
8660	     */
8661	    _makeCall(twimlParams_1, options_1) {
8662	        return __awaiter(this, arguments, void 0, function* (twimlParams, options, isReconnect = false) {
8663	            var _a;
8664	            // Wait for the input device if it's set by the user
8665	            const inputDevicePromise = (_a = this._audio) === null || _a === void 0 ? void 0 : _a._getInputDevicePromise();
8666	            if (inputDevicePromise) {
8667	                this._log.debug('inputDevicePromise detected, waiting...');
8668	                yield inputDevicePromise;
8669	                this._log.debug('inputDevicePromise resolved');
8670	            }
8671	            const config = {
8672	                audioHelper: this._audio,
8673	                onIgnore: () => {
8674	                    this._soundcache.get(Device.SoundName.Incoming).stop();
8675	                },
8676	                pstream: yield (this._streamConnectedPromise || this._setupStream()),
8677	                publisher: this._publisher,
8678	                soundcache: this._soundcache,
8679	            };
8680	            options = Object.assign({
8681	                MediaStream: this._options.MediaStream,
8682	                RTCPeerConnection: this._options.RTCPeerConnection,
8683	                beforeAccept: (currentCall) => {
8684	                    if (!this._activeCall || this._activeCall === currentCall) {
8685	                        return;
8686	                    }
8687	                    this._activeCall.disconnect();
8688	                    this._removeCall(this._activeCall);
8689	                },
8690	                codecPreferences: this._options.codecPreferences,
8691	                customSounds: this._options.sounds,
8692	                dialtonePlayer: Device._dialtonePlayer,
8693	                dscp: this._options.dscp,
8694	                // TODO(csantos): Remove forceAggressiveIceNomination option in 3.x
8695	                forceAggressiveIceNomination: this._options.forceAggressiveIceNomination,
8696	                getInputStream: () => this._options.fileInputStream || this._callInputStream,
8697	                getSinkIds: () => this._callSinkIds,
8698	                maxAverageBitrate: this._options.maxAverageBitrate,
8699	                preflight: this._options.preflight,
8700	                rtcConstraints: this._options.rtcConstraints,
8701	                shouldPlayDisconnect: () => { var _a; return (_a = this._audio) === null || _a === void 0 ? void 0 : _a.disconnect(); },
8702	                twimlParams,
8703	                voiceEventSidGenerator: this._options.voiceEventSidGenerator,
8704	            }, options);
8705	            const maybeUnsetPreferredUri = () => {
8706	                if (!this._stream) {
8707	                    this._log.warn('UnsetPreferredUri called without a stream');
8708	                    return;
8709	                }
8710	                if (this._activeCall === null && this._calls.length === 0) {
8711	                    this._stream.updatePreferredURI(null);
8712	                }
8713	            };
8714	            const call = new (this._options.Call || Call)(config, options);
8715	            this._publisher.info('settings', 'init', {
8716	                MediaStream: !!this._options.MediaStream,
8717	                RTCPeerConnection: !!this._options.RTCPeerConnection,
8718	                enumerateDevices: !!this._options.enumerateDevices,
8719	                getUserMedia: !!this._options.getUserMedia,
8720	            }, call);
8721	            call.once('accept', () => {
8722	                var _a, _b, _c;
8723	                this._stream.updatePreferredURI(this._preferredURI);
8724	                this._removeCall(call);
8725	                this._activeCall = call;
8726	                if (this._audio) {
8727	                    this._audio._maybeStartPollingVolume();
8728	                }
8729	                if (call.direction === Call.CallDirection.Outgoing && ((_a = this._audio) === null || _a === void 0 ? void 0 : _a.outgoing()) && !isReconnect) {
8730	                    this._soundcache.get(Device.SoundName.Outgoing).play();
8731	                }
8732	                const data = { edge: this._edge || this._region };
8733	                if (this._options.edge) {
8734	                    data['selected_edge'] = Array.isArray(this._options.edge)
8735	                        ? this._options.edge
8736	                        : [this._options.edge];
8737	                }
8738	                this._publisher.info('settings', 'edge', data, call);
8739	                if ((_b = this._audio) === null || _b === void 0 ? void 0 : _b.processedStream) {
8740	                    (_c = this._audioProcessorEventObserver) === null || _c === void 0 ? void 0 : _c.emit('enabled');
8741	                }
8742	            });
8743	            call.addListener('error', (error) => {
8744	                if (call.status() === 'closed') {
8745	                    this._removeCall(call);
8746	                    maybeUnsetPreferredUri();
8747	                }
8748	                if (this._audio) {
8749	                    this._audio._maybeStopPollingVolume();
8750	                }
8751	                this._maybeStopIncomingSound();
8752	            });
8753	            call.once('cancel', () => {
8754	                this._log.info(`Canceled: ${call.parameters.CallSid}`);
8755	                this._removeCall(call);
8756	                maybeUnsetPreferredUri();
8757	                if (this._audio) {
8758	                    this._audio._maybeStopPollingVolume();
8759	                }
8760	                this._maybeStopIncomingSound();
8761	            });
8762	            call.once('disconnect', () => {
8763	                if (this._audio) {
8764	                    this._audio._maybeStopPollingVolume();
8765	                }
8766	                this._removeCall(call);
8767	                maybeUnsetPreferredUri();
8768	                /**
8769	                 * NOTE(kamalbennani): We need to stop the incoming sound when the call is
8770	                 * disconnected right after the user has accepted the call (activeCall.accept()), and before
8771	                 * the call has been fully connected (i.e. before the `pstream.answer` event)
8772	                 */
8773	                this._maybeStopIncomingSound();
8774	            });
8775	            call.once('reject', () => {
8776	                this._log.info(`Rejected: ${call.parameters.CallSid}`);
8777	                if (this._audio) {
8778	                    this._audio._maybeStopPollingVolume();
8779	                }
8780	                this._removeCall(call);
8781	                maybeUnsetPreferredUri();
8782	                this._maybeStopIncomingSound();
8783	            });
8784	            call.on('transportClose', () => {
8785	                if (call.status() !== Call.State.Pending) {
8786	                    return;
8787	                }
8788	                if (this._audio) {
8789	                    this._audio._maybeStopPollingVolume();
8790	                }
8791	                this._removeCall(call);
8792	                /**
8793	                 * NOTE(mhuynh): We don't want to call `maybeUnsetPreferredUri` because
8794	                 * a `transportClose` will happen during signaling reconnection.
8795	                 */
8796	                this._maybeStopIncomingSound();
8797	            });
8798	            return call;
8799	        });
8800	    }
8801	    /**
8802	     * Stop the incoming sound if no {@link Call}s remain.
8803	     */
8804	    _maybeStopIncomingSound() {
8805	        if (!this._calls.length) {
8806	            this._soundcache.get(Device.SoundName.Incoming).stop();
8807	        }
8808	    }
8809	    /**
8810	     * Remove a {@link Call} from device.calls by reference
8811	     * @param call
8812	     */
8813	    _removeCall(call) {
8814	        if (this._activeCall === call) {
8815	            this._activeCall = null;
8816	            this._makeCallPromise = null;
8817	        }
8818	        for (let i = this._calls.length - 1; i >= 0; i--) {
8819	            if (call === this._calls[i]) {
8820	                this._calls.splice(i, 1);
8821	            }
8822	        }
8823	    }
8824	    /**
8825	     * Register with the signaling server.
8826	     */
8827	    _sendPresence(presence) {
8828	        return __awaiter(this, void 0, void 0, function* () {
8829	            const stream = yield this._streamConnectedPromise;
8830	            if (!stream) {
8831	                return;
8832	            }
8833	            stream.register({ audio: presence });
8834	            if (presence) {
8835	                this._startRegistrationTimer();
8836	            }
8837	            else {
8838	                this._stopRegistrationTimer();
8839	            }
8840	        });
8841	    }
8842	    /**
8843	     * Helper function that sets and emits the state of the device.
8844	     * @param state The new state of the device.
8845	     */
8846	    _setState(state) {
8847	        if (state === this.state) {
8848	            return;
8849	        }
8850	        this._state = state;
8851	        const name = this._stateEventMapping[state];
8852	        this._log.debug(`#${name}`);
8853	        this.emit(name);
8854	    }
8855	    /**
8856	     * Set up an audio helper for usage by this {@link Device}.
8857	     */
8858	    _setupAudioHelper() {
8859	        if (!this._audioProcessorEventObserver) {
8860	            this._audioProcessorEventObserver = new AudioProcessorEventObserver();
8861	            this._audioProcessorEventObserver.on('event', ({ name, group }) => {
8862	                this._publisher.info(group, name, {}, this._activeCall);
8863	            });
8864	        }
8865	        const audioOptions = {
8866	            audioContext: Device.audioContext,
8867	            audioProcessorEventObserver: this._audioProcessorEventObserver,
8868	            beforeSetInputDevice: () => {
8869	                if (this._makeCallPromise) {
8870	                    this._log.debug('beforeSetInputDevice pause detected');
8871	                    return this._makeCallPromise;
8872	                }
8873	                else {
8874	                    this._log.debug('beforeSetInputDevice pause not detected, setting default');
8875	                    return Promise.resolve();
8876	                }
8877	            },
8878	            enumerateDevices: this._options.enumerateDevices,
8879	            getUserMedia: this._options.getUserMedia || getUserMedia,
8880	        };
8881	        if (this._audio) {
8882	            this._log.info('Found existing audio helper; updating options...');
8883	            this._audio._updateUserOptions(audioOptions);
8884	            return;
8885	        }
8886	        this._audio = new (this._options.AudioHelper || AudioHelper$1)(this._updateSinkIds, this._updateInputStream, audioOptions);
8887	        this._audio.on('deviceChange', (lostActiveDevices) => {
8888	            const activeCall = this._activeCall;
8889	            const deviceIds = lostActiveDevices.map((device) => device.deviceId);
8890	            this._publisher.info('audio', 'device-change', {
8891	                lost_active_device_ids: deviceIds,
8892	            }, activeCall);
8893	            if (activeCall) {
8894	                activeCall['_mediaHandler']._onInputDevicesChanged();
8895	            }
8896	        });
8897	    }
8898	    /**
8899	     * Setup logger's loglevel
8900	     */
8901	    _setupLoglevel(logLevel) {
8902	        const level = typeof logLevel === 'number' ||
8903	            typeof logLevel === 'string' ?
8904	            logLevel : loglevelExports.levels.ERROR;
8905	        this._log.setDefaultLevel(level);
8906	        this._log.info('Set logger default level to', level);
8907	    }
8908	    /**
8909	     * Create and set a publisher for the {@link Device} to use.
8910	     */
8911	    _setupPublisher() {
8912	        if (this._publisher) {
8913	            this._log.info('Found existing publisher; destroying...');
8914	            this._destroyPublisher();
8915	        }
8916	        const publisherOptions = {
8917	            defaultPayload: this._createDefaultPayload,
8918	            metadata: {
8919	                app_name: this._options.appName,
8920	                app_version: this._options.appVersion,
8921	            },
8922	        };
8923	        if (this._options.eventgw) {
8924	            publisherOptions.host = this._options.eventgw;
8925	        }
8926	        if (this._home) {
8927	            publisherOptions.host = createEventGatewayURI(this._home);
8928	        }
8929	        this._publisher = new (this._options.Publisher || EventPublisher)(PUBLISHER_PRODUCT_NAME, this.token, publisherOptions);
8930	        if (this._options.publishEvents === false) {
8931	            this._publisher.disable();
8932	        }
8933	        else {
8934	            this._publisher.on('error', (error) => {
8935	                this._log.warn('Cannot connect to insights.', error);
8936	            });
8937	        }
8938	        return this._publisher;
8939	    }
8940	    /**
8941	     * Set up the connection to the signaling server. Tears down an existing
8942	     * stream if called while a stream exists.
8943	     */
8944	    _setupStream() {
8945	        if (this._stream) {
8946	            this._log.info('Found existing stream; destroying...');
8947	            this._destroyStream();
8948	        }
8949	        this._log.info('Setting up VSP');
8950	        this._stream = new (this._options.PStream || PStream)(this.token, this._chunderURIs, {
8951	            backoffMaxMs: this._options.backoffMaxMs,
8952	            maxPreferredDurationMs: this._options.maxCallSignalingTimeoutMs,
8953	        });
8954	        this._stream.addListener('close', this._onSignalingClose);
8955	        this._stream.addListener('connected', this._onSignalingConnected);
8956	        this._stream.addListener('error', this._onSignalingError);
8957	        this._stream.addListener('invite', this._onSignalingInvite);
8958	        this._stream.addListener('offline', this._onSignalingOffline);
8959	        this._stream.addListener('ready', this._onSignalingReady);
8960	        return this._streamConnectedPromise =
8961	            promisifyEvents(this._stream, 'connected', 'close').then(() => this._stream);
8962	    }
8963	    /**
8964	     * Start playing the incoming ringtone, and subsequently emit the incoming event.
8965	     * @param call
8966	     * @param play - The function to be used to play the sound. Must return a Promise.
8967	     */
8968	    _showIncomingCall(call, play) {
8969	        let timeout;
8970	        return Promise.race([
8971	            play(),
8972	            new Promise((resolve, reject) => {
8973	                timeout = setTimeout(() => {
8974	                    const msg = 'Playing incoming ringtone took too long; it might not play. Continuing execution...';
8975	                    reject(new Error(msg));
8976	                }, RINGTONE_PLAY_TIMEOUT);
8977	            }),
8978	        ]).catch(reason => {
8979	            this._log.warn(reason.message);
8980	        }).then(() => {
8981	            clearTimeout(timeout);
8982	            this._log.debug('#incoming', JSON.stringify({
8983	                customParameters: call.customParameters,
8984	                parameters: call.parameters,
8985	            }));
8986	            this.emit(Device.EventName.Incoming, call);
8987	        });
8988	    }
8989	    /**
8990	     * Set a timeout to send another register message to the signaling server.
8991	     */
8992	    _startRegistrationTimer() {
8993	        this._stopRegistrationTimer();
8994	        this._regTimer = setTimeout(() => {
8995	            this._sendPresence(true);
8996	        }, REGISTRATION_INTERVAL);
8997	    }
8998	    /**
8999	     * Stop sending registration messages to the signaling server.
9000	     */
9001	    _stopRegistrationTimer() {
9002	        if (this._regTimer) {
9003	            clearTimeout(this._regTimer);
9004	        }
9005	    }
9006	    /**
9007	     * Throw an error if the {@link Device} is destroyed.
9008	     */
9009	    _throwIfDestroyed() {
9010	        if (this.state === Device.State.Destroyed) {
9011	            throw new InvalidStateError('Device has been destroyed.');
9012	        }
9013	    }
9014	    /**
9015	     * Update the device IDs of output devices being used to play the incoming ringtone through.
9016	     * @param sinkIds - An array of device IDs
9017	     */
9018	    _updateRingtoneSinkIds(sinkIds) {
9019	        return Promise.resolve(this._soundcache.get(Device.SoundName.Incoming).setSinkIds(sinkIds));
9020	    }
9021	    /**
9022	     * Update the device IDs of output devices being used to play the non-ringtone sounds
9023	     * and Call audio through.
9024	     * @param sinkIds - An array of device IDs
9025	     */
9026	    _updateSpeakerSinkIds(sinkIds) {
9027	        Array.from(this._soundcache.entries())
9028	            .filter(entry => entry[0] !== Device.SoundName.Incoming)
9029	            .forEach(entry => entry[1].setSinkIds(sinkIds));
9030	        this._callSinkIds = sinkIds;
9031	        const call = this._activeCall;
9032	        return call
9033	            ? call._setSinkIds(sinkIds)
9034	            : Promise.resolve();
9035	    }
9036	}
9037	Device._defaultSounds = {
9038	    disconnect: { filename: 'disconnect', maxDuration: 3000 },
9039	    dtmf0: { filename: 'dtmf-0', maxDuration: 1000 },
9040	    dtmf1: { filename: 'dtmf-1', maxDuration: 1000 },
9041	    dtmf2: { filename: 'dtmf-2', maxDuration: 1000 },
9042	    dtmf3: { filename: 'dtmf-3', maxDuration: 1000 },
9043	    dtmf4: { filename: 'dtmf-4', maxDuration: 1000 },
9044	    dtmf5: { filename: 'dtmf-5', maxDuration: 1000 },
9045	    dtmf6: { filename: 'dtmf-6', maxDuration: 1000 },
9046	    dtmf7: { filename: 'dtmf-7', maxDuration: 1000 },
9047	    dtmf8: { filename: 'dtmf-8', maxDuration: 1000 },
9048	    dtmf9: { filename: 'dtmf-9', maxDuration: 1000 },
9049	    dtmfh: { filename: 'dtmf-hash', maxDuration: 1000 },
9050	    dtmfs: { filename: 'dtmf-star', maxDuration: 1000 },
9051	    incoming: { filename: 'incoming', shouldLoop: true },
9052	    outgoing: { filename: 'outgoing', maxDuration: 3000 },
9053	};
9054	/**
9055	 * @mergeModuleWith Device
9056	 */
9057	(function (Device) {
9058	    (function (EventName) {
9059	        EventName["Error"] = "error";
9060	        EventName["Incoming"] = "incoming";
9061	        EventName["Destroyed"] = "destroyed";
9062	        EventName["Unregistered"] = "unregistered";
9063	        EventName["Registering"] = "registering";
9064	        EventName["Registered"] = "registered";
9065	        EventName["TokenWillExpire"] = "tokenWillExpire";
9066	    })(Device.EventName || (Device.EventName = {}));
9067	    (function (State) {
9068	        State["Destroyed"] = "destroyed";
9069	        State["Unregistered"] = "unregistered";
9070	        State["Registering"] = "registering";
9071	        State["Registered"] = "registered";
9072	    })(Device.State || (Device.State = {}));
9073	    (function (SoundName) {
9074	        SoundName["Incoming"] = "incoming";
9075	        SoundName["Outgoing"] = "outgoing";
9076	        SoundName["Disconnect"] = "disconnect";
9077	        SoundName["Dtmf0"] = "dtmf0";
9078	        SoundName["Dtmf1"] = "dtmf1";
9079	        SoundName["Dtmf2"] = "dtmf2";
9080	        SoundName["Dtmf3"] = "dtmf3";
9081	        SoundName["Dtmf4"] = "dtmf4";
9082	        SoundName["Dtmf5"] = "dtmf5";
9083	        SoundName["Dtmf6"] = "dtmf6";
9084	        SoundName["Dtmf7"] = "dtmf7";
9085	        SoundName["Dtmf8"] = "dtmf8";
9086	        SoundName["Dtmf9"] = "dtmf9";
9087	        SoundName["DtmfS"] = "dtmfs";
9088	        SoundName["DtmfH"] = "dtmfh";
9089	    })(Device.SoundName || (Device.SoundName = {}));
9090	})(Device || (Device = {}));
9091
9092	/**
9093	 * {@link RTCIceCandidate} parses an ICE candidate gathered by the browser
9094	 * and returns a IceCandidate object
9095	 */
9096	class IceCandidate {
9097	    /**
9098	     * @constructor
9099	     * @param iceCandidate RTCIceCandidate coming from the browser
9100	     */
9101	    constructor(iceCandidate, isRemote = false) {
9102	        /**
9103	         * Whether this is deleted from the list of candidate gathered
9104	         */
9105	        this.deleted = false;
9106	        let cost;
9107	        const parts = iceCandidate.candidate.split('network-cost ');
9108	        if (parts[1]) {
9109	            cost = parseInt(parts[1], 10);
9110	        }
9111	        this.candidateType = iceCandidate.type;
9112	        this.ip = iceCandidate.ip || iceCandidate.address;
9113	        this.isRemote = isRemote;
9114	        this.networkCost = cost;
9115	        this.port = iceCandidate.port;
9116	        this.priority = iceCandidate.priority;
9117	        this.protocol = iceCandidate.protocol;
9118	        this.relatedAddress = iceCandidate.relatedAddress;
9119	        this.relatedPort = iceCandidate.relatedPort;
9120	        this.tcpType = iceCandidate.tcpType;
9121	        this.transportId = iceCandidate.sdpMid;
9122	    }
9123	    /**
9124	     * Get the payload object for insights
9125	     */
9126	    toPayload() {
9127	        return {
9128	            'candidate_type': this.candidateType,
9129	            'deleted': this.deleted,
9130	            'ip': this.ip,
9131	            'is_remote': this.isRemote,
9132	            'network-cost': this.networkCost,
9133	            'port': this.port,
9134	            'priority': this.priority,
9135	            'protocol': this.protocol,
9136	            'related_address': this.relatedAddress,
9137	            'related_port': this.relatedPort,
9138	            'tcp_type': this.tcpType,
9139	            'transport_id': this.transportId,
9140	        };
9141	    }
9142	}
9143
9144	const r0 = 94.768; // Constant used in computing "rFactor".
9145	/**
9146	 * Calculate the mos score of a stats object
9147	 * @param {number} rtt
9148	 * @param {number} jitter
9149	 * @param {number} fractionLost - The fraction of packets that have been lost.
9150	 * Calculated by packetsLost / totalPackets
9151	 * @return {number | null} mos - Calculated MOS, `1.0` through roughly `4.5`.
9152	 * Returns `null` when any of the input parameters are not a `non-negative`
9153	 * number.
9154	 */
9155	function calculate(rtt, jitter, fractionLost) {
9156	    if (typeof rtt !== 'number' ||
9157	        typeof jitter !== 'number' ||
9158	        typeof fractionLost !== 'number' ||
9159	        !isNonNegativeNumber(rtt) ||
9160	        !isNonNegativeNumber(jitter) ||
9161	        !isNonNegativeNumber(fractionLost)) {
9162	        return null;
9163	    }
9164	    // Compute the effective latency.
9165	    const effectiveLatency = rtt + (jitter * 2) + 10;
9166	    // Compute the initial "rFactor" from effective latency.
9167	    let rFactor = 0;
9168	    switch (true) {
9169	        case effectiveLatency < 160:
9170	            rFactor = r0 - (effectiveLatency / 40);
9171	            break;
9172	        case effectiveLatency < 1000:
9173	            rFactor = r0 - ((effectiveLatency - 120) / 10);
9174	            break;
9175	    }
9176	    // Adjust "rFactor" with the fraction of packets lost.
9177	    switch (true) {
9178	        case fractionLost <= (rFactor / 2.5):
9179	            rFactor = Math.max(rFactor - fractionLost * 2.5, 6.52);
9180	            break;
9181	        default:
9182	            rFactor = 0;
9183	            break;
9184	    }
9185	    // Compute MOS from "rFactor".
9186	    const mos = 1 +
9187	        (0.035 * rFactor) +
9188	        (0.000007 * rFactor) *
9189	            (rFactor - 60) *
9190	            (100 - rFactor);
9191	    return mos;
9192	}
9193	/**
9194	 * Returns true if and only if the parameter passed is a number, is not `NaN`,
9195	 * is finite, and is greater than or equal to `0`.
9196	 * @param n
9197	 */
9198	function isNonNegativeNumber(n) {
9199	    return typeof n === 'number' && !isNaN(n) && isFinite(n) && n >= 0;
9200	}
9201	var Mos = {
9202	    calculate,
9203	    isNonNegativeNumber,
9204	};
9205
9206	// How many samples we use when testing metric thresholds
9207	const SAMPLE_COUNT_METRICS = 5;
9208	// How many samples that need to cross the threshold to
9209	// raise or clear a warning.
9210	const SAMPLE_COUNT_CLEAR = 0;
9211	const SAMPLE_COUNT_RAISE = 3;
9212	const SAMPLE_INTERVAL = 1000;
9213	const WARNING_TIMEOUT = 5 * 1000;
9214	const DEFAULT_THRESHOLDS = {
9215	    audioInputLevel: { minStandardDeviation: 327.67, sampleCount: 10 },
9216	    audioOutputLevel: { minStandardDeviation: 327.67, sampleCount: 10 },
9217	    bytesReceived: { clearCount: 2, min: 1, raiseCount: 3, sampleCount: 3 },
9218	    bytesSent: { clearCount: 2, min: 1, raiseCount: 3, sampleCount: 3 },
9219	    jitter: { max: 30 },
9220	    mos: { min: 3 },
9221	    packetsLostFraction: [{
9222	            max: 1,
9223	        }, {
9224	            clearValue: 1,
9225	            maxAverage: 3,
9226	            sampleCount: 7,
9227	        }],
9228	    rtt: { max: 400 },
9229	};
9230	/**
9231	 * Count the number of values that cross the max threshold.
9232	 * @private
9233	 * @param max - The max allowable value.
9234	 * @param values - The values to iterate over.
9235	 * @returns The amount of values in which the stat crossed the threshold.
9236	 */
9237	function countHigh(max, values) {
9238	    return values.reduce((highCount, value) => highCount += (value > max) ? 1 : 0, 0);
9239	}
9240	/**
9241	 * Count the number of values that cross the min threshold.
9242	 * @private
9243	 * @param min - The minimum allowable value.
9244	 * @param values - The values to iterate over.
9245	 * @returns The amount of values in which the stat crossed the threshold.
9246	 */
9247	function countLow(min, values) {
9248	    return values.reduce((lowCount, value) => lowCount += (value < min) ? 1 : 0, 0);
9249	}
9250	/**
9251	 * Calculate the standard deviation from a list of numbers.
9252	 * @private
9253	 * @param values The list of numbers to calculate the standard deviation from.
9254	 * @returns The standard deviation of a list of numbers.
9255	 */
9256	function calculateStandardDeviation(values) {
9257	    if (values.length <= 0) {
9258	        return null;
9259	    }
9260	    const valueAverage = values.reduce((partialSum, value) => partialSum + value, 0) / values.length;
9261	    const diffSquared = values.map((value) => Math.pow(value - valueAverage, 2));
9262	    const stdDev = Math.sqrt(diffSquared.reduce((partialSum, value) => partialSum + value, 0) / diffSquared.length);
9263	    return stdDev;
9264	}
9265	/**
9266	 * Flatten a set of numerical sample sets into a single array of samples.
9267	 * @param sampleSets
9268	 */
9269	function flattenSamples(sampleSets) {
9270	    return sampleSets.reduce((flat, current) => [...flat, ...current], []);
9271	}
9272	/**
9273	 * {@link StatsMonitor} polls a peerConnection via PeerConnection.getStats
9274	 * and emits warnings when stats cross the specified threshold values.
9275	 */
9276	class StatsMonitor extends eventsExports.EventEmitter {
9277	    /**
9278	     * @constructor
9279	     * @param [options] - Optional settings
9280	     */
9281	    constructor(options) {
9282	        super();
9283	        /**
9284	         * A map of warnings with their raised time
9285	         */
9286	        this._activeWarnings = new Map();
9287	        /**
9288	         * A map of stats with the number of exceeded thresholds
9289	         */
9290	        this._currentStreaks = new Map();
9291	        /**
9292	         * Keeps track of input volumes in the last second
9293	         */
9294	        this._inputVolumes = [];
9295	        /**
9296	         * Keeps track of output volumes in the last second
9297	         */
9298	        this._outputVolumes = [];
9299	        /**
9300	         * Sample buffer. Saves most recent samples
9301	         */
9302	        this._sampleBuffer = [];
9303	        /**
9304	         * Keeps track of supplemental sample values.
9305	         *
9306	         * Currently used for constant audio detection. Contains an array of volume
9307	         * samples for each sample interval.
9308	         */
9309	        this._supplementalSampleBuffers = {
9310	            audioInputLevel: [],
9311	            audioOutputLevel: [],
9312	        };
9313	        /**
9314	         * Whether warnings should be enabled
9315	         */
9316	        this._warningsEnabled = true;
9317	        options = options || {};
9318	        this._getRTCStats = options.getRTCStats || getRTCStats;
9319	        this._mos = options.Mos || Mos;
9320	        this._peerConnection = options.peerConnection;
9321	        this._thresholds = Object.assign(Object.assign({}, DEFAULT_THRESHOLDS), options.thresholds);
9322	        const thresholdSampleCounts = Object.values(this._thresholds)
9323	            .map((threshold) => threshold.sampleCount)
9324	            .filter((sampleCount) => !!sampleCount);
9325	        this._maxSampleCount = Math.max(SAMPLE_COUNT_METRICS, ...thresholdSampleCounts);
9326	        if (this._peerConnection) {
9327	            this.enable(this._peerConnection);
9328	        }
9329	    }
9330	    /**
9331	     * Called when a volume sample is available
9332	     * @param inputVolume - Input volume level from 0 to 32767
9333	     * @param outputVolume - Output volume level from 0 to 32767
9334	     */
9335	    addVolumes(inputVolume, outputVolume) {
9336	        this._inputVolumes.push(inputVolume);
9337	        this._outputVolumes.push(outputVolume);
9338	    }
9339	    /**
9340	     * Stop sampling RTC statistics for this {@link StatsMonitor}.
9341	     * @returns The current {@link StatsMonitor}.
9342	     */
9343	    disable() {
9344	        if (this._sampleInterval) {
9345	            clearInterval(this._sampleInterval);
9346	            delete this._sampleInterval;
9347	        }
9348	        return this;
9349	    }
9350	    /**
9351	     * Disable warnings for this {@link StatsMonitor}.
9352	     * @returns The current {@link StatsMonitor}.
9353	     */
9354	    disableWarnings() {
9355	        if (this._warningsEnabled) {
9356	            this._activeWarnings.clear();
9357	        }
9358	        this._warningsEnabled = false;
9359	        return this;
9360	    }
9361	    /**
9362	     * Start sampling RTC statistics for this {@link StatsMonitor}.
9363	     * @param peerConnection - A PeerConnection to monitor.
9364	     * @returns The current {@link StatsMonitor}.
9365	     */
9366	    enable(peerConnection) {
9367	        if (peerConnection) {
9368	            if (this._peerConnection && peerConnection !== this._peerConnection) {
9369	                throw new InvalidArgumentError('Attempted to replace an existing PeerConnection in StatsMonitor.enable');
9370	            }
9371	            this._peerConnection = peerConnection;
9372	        }
9373	        if (!this._peerConnection) {
9374	            throw new InvalidArgumentError('Can not enable StatsMonitor without a PeerConnection');
9375	        }
9376	        this._sampleInterval = this._sampleInterval ||
9377	            setInterval(this._fetchSample.bind(this), SAMPLE_INTERVAL);
9378	        return this;
9379	    }
9380	    /**
9381	     * Enable warnings for this {@link StatsMonitor}.
9382	     * @returns The current {@link StatsMonitor}.
9383	     */
9384	    enableWarnings() {
9385	        this._warningsEnabled = true;
9386	        return this;
9387	    }
9388	    /**
9389	     * Check if there is an active warning for a specific stat and threshold
9390	     * @param statName - The name of the stat to check
9391	     * @param thresholdName - The name of the threshold to check
9392	     * @returns Whether there is an active warning for a specific stat and threshold
9393	     */
9394	    hasActiveWarning(statName, thresholdName) {
9395	        const warningId = `${statName}:${thresholdName}`;
9396	        return !!this._activeWarnings.get(warningId);
9397	    }
9398	    /**
9399	     * Add a sample to our sample buffer and remove the oldest if we are over the limit.
9400	     * @param sample - Sample to add
9401	     */
9402	    _addSample(sample) {
9403	        const samples = this._sampleBuffer;
9404	        samples.push(sample);
9405	        // We store 1 extra sample so that we always have (current, previous)
9406	        // available for all {sampleBufferSize} threshold validations.
9407	        if (samples.length > this._maxSampleCount) {
9408	            samples.splice(0, samples.length - this._maxSampleCount);
9409	        }
9410	    }
9411	    /**
9412	     * Clear an active warning.
9413	     * @param statName - The name of the stat to clear.
9414	     * @param thresholdName - The name of the threshold to clear
9415	     * @param [data] - Any relevant sample data.
9416	     */
9417	    _clearWarning(statName, thresholdName, data) {
9418	        const warningId = `${statName}:${thresholdName}`;
9419	        const activeWarning = this._activeWarnings.get(warningId);
9420	        if (!activeWarning || Date.now() - activeWarning.timeRaised < WARNING_TIMEOUT) {
9421	            return;
9422	        }
9423	        this._activeWarnings.delete(warningId);
9424	        this.emit('warning-cleared', Object.assign(Object.assign({}, data), { name: statName, threshold: {
9425	                name: thresholdName,
9426	                value: this._thresholds[statName][thresholdName],
9427	            } }));
9428	    }
9429	    /**
9430	     * Create a sample object from a stats object using the previous sample, if available.
9431	     * @param stats - Stats retrieved from getStatistics
9432	     * @param [previousSample=null] - The previous sample to use to calculate deltas.
9433	     * @returns A universally-formatted version of RTC stats.
9434	     */
9435	    _createSample(stats, previousSample) {
9436	        const previousBytesSent = previousSample && previousSample.totals.bytesSent || 0;
9437	        const previousBytesReceived = previousSample && previousSample.totals.bytesReceived || 0;
9438	        const previousPacketsSent = previousSample && previousSample.totals.packetsSent || 0;
9439	        const previousPacketsReceived = previousSample && previousSample.totals.packetsReceived || 0;
9440	        const previousPacketsLost = previousSample && previousSample.totals.packetsLost || 0;
9441	        const currentBytesSent = stats.bytesSent - previousBytesSent;
9442	        const currentBytesReceived = stats.bytesReceived - previousBytesReceived;
9443	        const currentPacketsSent = stats.packetsSent - previousPacketsSent;
9444	        const currentPacketsReceived = stats.packetsReceived - previousPacketsReceived;
9445	        const currentPacketsLost = stats.packetsLost - previousPacketsLost;
9446	        const currentInboundPackets = currentPacketsReceived + currentPacketsLost;
9447	        const currentPacketsLostFraction = (currentInboundPackets > 0) ?
9448	            (currentPacketsLost / currentInboundPackets) * 100 : 0;
9449	        const totalInboundPackets = stats.packetsReceived + stats.packetsLost;
9450	        const totalPacketsLostFraction = (totalInboundPackets > 0) ?
9451	            (stats.packetsLost / totalInboundPackets) * 100 : 100;
9452	        const rttValue = (typeof stats.rtt === 'number' || !previousSample) ? stats.rtt : previousSample.rtt;
9453	        const audioInputLevelValues = this._inputVolumes.splice(0);
9454	        this._supplementalSampleBuffers.audioInputLevel.push(audioInputLevelValues);
9455	        const audioOutputLevelValues = this._outputVolumes.splice(0);
9456	        this._supplementalSampleBuffers.audioOutputLevel.push(audioOutputLevelValues);
9457	        return {
9458	            audioInputLevel: Math.round(average(audioInputLevelValues)),
9459	            audioOutputLevel: Math.round(average(audioOutputLevelValues)),
9460	            bytesReceived: currentBytesReceived,
9461	            bytesSent: currentBytesSent,
9462	            codecName: stats.codecName,
9463	            jitter: stats.jitter,
9464	            mos: this._mos.calculate(rttValue, stats.jitter, previousSample && currentPacketsLostFraction),
9465	            packetsLost: currentPacketsLost,
9466	            packetsLostFraction: currentPacketsLostFraction,
9467	            packetsReceived: currentPacketsReceived,
9468	            packetsSent: currentPacketsSent,
9469	            rtt: rttValue,
9470	            timestamp: stats.timestamp,
9471	            totals: {
9472	                bytesReceived: stats.bytesReceived,
9473	                bytesSent: stats.bytesSent,
9474	                packetsLost: stats.packetsLost,
9475	                packetsLostFraction: totalPacketsLostFraction,
9476	                packetsReceived: stats.packetsReceived,
9477	                packetsSent: stats.packetsSent,
9478	            },
9479	        };
9480	    }
9481	    /**
9482	     * Get stats from the PeerConnection and add it to our list of samples.
9483	     */
9484	    _fetchSample() {
9485	        this._getSample().then(sample => {
9486	            this._addSample(sample);
9487	            this._raiseWarnings();
9488	            this.emit('sample', sample);
9489	        }).catch(error => {
9490	            this.disable();
9491	            // We only bubble up any errors coming from pc.getStats()
9492	            // No need to attach a twilioError
9493	            this.emit('error', error);
9494	        });
9495	    }
9496	    /**
9497	     * Get stats from the PeerConnection.
9498	     * @returns A universally-formatted version of RTC stats.
9499	     */
9500	    _getSample() {
9501	        return this._getRTCStats(this._peerConnection).then((stats) => {
9502	            let previousSample = null;
9503	            if (this._sampleBuffer.length) {
9504	                previousSample = this._sampleBuffer[this._sampleBuffer.length - 1];
9505	            }
9506	            return this._createSample(stats, previousSample);
9507	        });
9508	    }
9509	    /**
9510	     * Raise a warning and log its raised time.
9511	     * @param statName - The name of the stat to raise.
9512	     * @param thresholdName - The name of the threshold to raise
9513	     * @param [data] - Any relevant sample data.
9514	     */
9515	    _raiseWarning(statName, thresholdName, data) {
9516	        const warningId = `${statName}:${thresholdName}`;
9517	        if (this._activeWarnings.has(warningId)) {
9518	            return;
9519	        }
9520	        this._activeWarnings.set(warningId, { timeRaised: Date.now() });
9521	        const thresholds = this._thresholds[statName];
9522	        let thresholdValue;
9523	        if (Array.isArray(thresholds)) {
9524	            const foundThreshold = thresholds.find(threshold => thresholdName in threshold);
9525	            if (foundThreshold) {
9526	                thresholdValue = foundThreshold[thresholdName];
9527	            }
9528	        }
9529	        else {
9530	            thresholdValue = this._thresholds[statName][thresholdName];
9531	        }
9532	        this.emit('warning', Object.assign(Object.assign({}, data), { name: statName, threshold: {
9533	                name: thresholdName,
9534	                value: thresholdValue,
9535	            } }));
9536	    }
9537	    /**
9538	     * Apply our thresholds to our array of RTCStat samples.
9539	     */
9540	    _raiseWarnings() {
9541	        if (!this._warningsEnabled) {
9542	            return;
9543	        }
9544	        Object.keys(this._thresholds).forEach(name => this._raiseWarningsForStat(name));
9545	    }
9546	    /**
9547	     * Apply thresholds for a given stat name to our array of
9548	     * RTCStat samples and raise or clear any associated warnings.
9549	     * @param statName - Name of the stat to compare.
9550	     */
9551	    _raiseWarningsForStat(statName) {
9552	        const limits = Array.isArray(this._thresholds[statName])
9553	            ? this._thresholds[statName]
9554	            : [this._thresholds[statName]];
9555	        limits.forEach((limit) => {
9556	            const samples = this._sampleBuffer;
9557	            const clearCount = limit.clearCount || SAMPLE_COUNT_CLEAR;
9558	            const raiseCount = limit.raiseCount || SAMPLE_COUNT_RAISE;
9559	            const sampleCount = limit.sampleCount || this._maxSampleCount;
9560	            let relevantSamples = samples.slice(-sampleCount);
9561	            const values = relevantSamples.map(sample => sample[statName]);
9562	            // (rrowland) If we have a bad or missing value in the set, we don't
9563	            // have enough information to throw or clear a warning. Bail out.
9564	            const containsNull = values.some(value => typeof value === 'undefined' || value === null);
9565	            if (containsNull) {
9566	                return;
9567	            }
9568	            let count;
9569	            if (typeof limit.max === 'number') {
9570	                count = countHigh(limit.max, values);
9571	                if (count >= raiseCount) {
9572	                    this._raiseWarning(statName, 'max', { values, samples: relevantSamples });
9573	                }
9574	                else if (count <= clearCount) {
9575	                    this._clearWarning(statName, 'max', { values, samples: relevantSamples });
9576	                }
9577	            }
9578	            if (typeof limit.min === 'number') {
9579	                count = countLow(limit.min, values);
9580	                if (count >= raiseCount) {
9581	                    this._raiseWarning(statName, 'min', { values, samples: relevantSamples });
9582	                }
9583	                else if (count <= clearCount) {
9584	                    this._clearWarning(statName, 'min', { values, samples: relevantSamples });
9585	                }
9586	            }
9587	            if (typeof limit.maxDuration === 'number' && samples.length > 1) {
9588	                relevantSamples = samples.slice(-2);
9589	                const prevValue = relevantSamples[0][statName];
9590	                const curValue = relevantSamples[1][statName];
9591	                const prevStreak = this._currentStreaks.get(statName) || 0;
9592	                const streak = (prevValue === curValue) ? prevStreak + 1 : 0;
9593	                this._currentStreaks.set(statName, streak);
9594	                if (streak >= limit.maxDuration) {
9595	                    this._raiseWarning(statName, 'maxDuration', { value: streak });
9596	                }
9597	                else if (streak === 0) {
9598	                    this._clearWarning(statName, 'maxDuration', { value: prevStreak });
9599	                }
9600	            }
9601	            if (typeof limit.minStandardDeviation === 'number') {
9602	                const sampleSets = this._supplementalSampleBuffers[statName];
9603	                if (!sampleSets || sampleSets.length < limit.sampleCount) {
9604	                    return;
9605	                }
9606	                if (sampleSets.length > limit.sampleCount) {
9607	                    sampleSets.splice(0, sampleSets.length - limit.sampleCount);
9608	                }
9609	                const flatSamples = flattenSamples(sampleSets.slice(-sampleCount));
9610	                const stdDev = calculateStandardDeviation(flatSamples);
9611	                if (typeof stdDev !== 'number') {
9612	                    return;
9613	                }
9614	                if (stdDev < limit.minStandardDeviation) {
9615	                    this._raiseWarning(statName, 'minStandardDeviation', { value: stdDev });
9616	                }
9617	                else {
9618	                    this._clearWarning(statName, 'minStandardDeviation', { value: stdDev });
9619	                }
9620	            }
9621	            [
9622	                ['maxAverage', (x, y) => x > y],
9623	                ['minAverage', (x, y) => x < y],
9624	            ].forEach(([thresholdName, comparator]) => {
9625	                if (typeof limit[thresholdName] === 'number' && values.length >
9625= sampleCount) {
9626	                    const avg = average(values);
9627	                    if (comparator(avg, limit[thresholdName])) {
9628	                        this._raiseWarning(statName, thresholdName, { values, samples: relevantSamples });
9629	                    }
9630	                    else if (!comparator(avg, limit.clearValue || limit[thresholdName])) {
9631	                        this._clearWarning(statName, thresholdName, { values, samples: relevantSamples });
9632	                    }
9633	                }
9634	            });
9635	        });
9636	    }
9637	}
9638
9639	const BACKOFF_CONFIG = {
9640	    factor: 1.1,
9641	    jitter: 0.5,
9642	    max: 30000,
9643	    min: 1,
9644	};
9645	const DTMF_INTER_TONE_GAP = 70;
9646	const DTMF_PAUSE_DURATION = 500;
9647	const DTMF_TONE_DURATION = 160;
9648	const METRICS_BATCH_SIZE = 10;
9649	const METRICS_DELAY = 5000;
9650	const MEDIA_DISCONNECT_ERROR = {
9651	    disconnect: true,
9652	    info: {
9653	        code: 31003,
9654	        message: 'Connection with Twilio was interrupted.',
9655	        twilioError: new MediaErrors.ConnectionError(),
9656	    },
9657	};
9658	const MULTIPLE_THRESHOLD_WARNING_NAMES = {
9659	    // The stat `packetsLostFraction` is monitored by two separate thresholds,
9660	    // `maxAverage` and `max`. Each threshold emits a different warning name.
9661	    packetsLostFraction: {
9662	        max: 'packet-loss',
9663	        maxAverage: 'packets-lost-fraction',
9664	    },
9665	};
9666	const WARNING_NAMES = {
9667	    audioInputLevel: 'audio-input-level',
9668	    audioOutputLevel: 'audio-output-level',
9669	    bytesReceived: 'bytes-received',
9670	    bytesSent: 'bytes-sent',
9671	    jitter: 'jitter',
9672	    mos: 'mos',
9673	    rtt: 'rtt',
9674	};
9675	const WARNING_PREFIXES = {
9676	    max: 'high-',
9677	    maxAverage: 'high-',
9678	    maxDuration: 'constant-',
9679	    min: 'low-',
9680	    minStandardDeviation: 'constant-',
9681	};
9682	/**
9683	 * A {@link Call} represents a media and signaling connection to a TwiML application.
9684	 */
9685	class Call extends eventsExports.EventEmitter {
9686	    /**
9687	     * Whether this {@link Call} is incoming or outgoing.
9688	     */
9689	    get direction() {
9690	        return this._direction;
9691	    }
9692	    /**
9693	     * Audio codec used for this {@link Call}. Expecting {@link Call.Codec} but
9694	     * will copy whatever we get from RTC stats.
9695	     */
9696	    get codec() {
9697	        return this._codec;
9698	    }
9699	    /**
9700	     * The connect token is available as soon as the call is established
9701	     * and connected to Twilio. Use this token to reconnect to a call via the {@link Device.connect}
9702	     * method.
9703	     *
9704	     * For incoming calls, it is available in the call object after the {@link Device.incomingEvent} is emitted.
9705	     * For outgoing calls, it is available after the {@link Call.acceptEvent} is emitted.
9706	     */
9707	    get connectToken() {
9708	        const signalingReconnectToken = this._signalingReconnectToken;
9709	        const callSid = this.parameters && this.parameters.CallSid ? this.parameters.CallSid : undefined;
9710	        if (!signalingReconnectToken || !callSid) {
9711	            return;
9712	        }
9713	        const customParameters = this.customParameters && typeof this.customParameters.keys === 'function' ?
9714	            Array.from(this.customParameters.keys()).reduce((result, key) => {
9715	                result[key] = this.customParameters.get(key);
9716	                return result;
9717	            }, {}) : {};
9718	        const parameters = this.parameters || {};
9719	        return btoa(encodeURIComponent(JSON.stringify({
9720	            customParameters,
9721	            parameters,
9722	            signalingReconnectToken,
9723	        })));
9724	    }
9725	    /**
9726	     * @internal
9727	     * @param config - Mandatory configuration options
9728	     * @param options - Optional settings
9729	     */
9730	    constructor(config, options) {
9731	        super();
9732	        /**
9733	         * Call parameters received from Twilio for an incoming call.
9734	         */
9735	        this.parameters = {};
9736	        /**
9737	         * The number of times input volume has been the same consecutively.
9738	         */
9739	        this._inputVolumeStreak = 0;
9740	        /**
9741	         * Whether the call has been answered.
9742	         */
9743	        this._isAnswered = false;
9744	        /**
9745	         * Whether the call has been cancelled.
9746	         */
9747	        this._isCancelled = false;
9748	        /**
9749	         * Whether the call has been rejected
9750	         */
9751	        this._isRejected = false;
9752	        /**
9753	         * The most recent public input volume value. 0 -> 1 representing -100 to -30 dB.
9754	         */
9755	        this._latestInputVolume = 0;
9756	        /**
9757	         * The most recent public output volume value. 0 -> 1 representing -100 to -30 dB.
9758	         */
9759	        this._latestOutputVolume = 0;
9760	        /**
9761	         * An instance of Logger to use.
9762	         */
9763	        this._log = new Log('Call');
9764	        /**
9765	         * State of the {@link Call}'s media.
9766	         */
9767	        this._mediaStatus = Call.State.Pending;
9768	        /**
9769	         * A map of messages sent via sendMessage API using voiceEventSid as the key.
9770	         * The message will be deleted once an 'ack' or an error is received from the server.
9771	         */
9772	        this._messages = new Map();
9773	        /**
9774	         * A batch of metrics samples to send to Insights. Gets cleared after
9775	         * each send and appended to on each new sample.
9776	         */
9777	        this._metricsSamples = [];
9778	        /**
9779	         * Options passed to this {@link Call}.
9780	         */
9781	        this._options = {
9782	            MediaHandler: PeerConnection,
9783	            MediaStream: null,
9784	            enableImprovedSignalingErrorPrecision: false,
9785	            offerSdp: null,
9786	            shouldPlayDisconnect: () => true,
9787	            voiceEventSidGenerator: generateVoiceEventSid,
9788	        };
9789	        /**
9790	         * The number of times output volume has been the same consecutively.
9791	         */
9792	        this._outputVolumeStreak = 0;
9793	        /**
9794	         * Whether the {@link Call} should send a hangup on disconnect.
9795	         */
9796	        this._shouldSendHangup = true;
9797	        /**
9798	         * State of the {@link Call}'s signaling.
9799	         */
9800	        this._signalingStatus = Call.State.Pending;
9801	        /**
9802	         * A Map of Sounds to play.
9803	         */
9804	        this._soundcache = new Map();
9805	        /**
9806	         * State of the {@link Call}.
9807	         */
9808	        this._status = Call.State.Pending;
9809	        /**
9810	         * Whether the {@link Call} has been connected. Used to determine if we are reconnected.
9811	         */
9812	        this._wasConnected = false;
9813	        /**
9814	         * String representation of {@link Call} instance.
9815	         * @internal
9816	         */
9817	        this.toString = () => '[Twilio.Call instance]';
9818	        this._emitWarning = (groupPrefix, warningName, threshold, value, wasCleared, warningData) => {
9819	            const groupSuffix = wasCleared ? '-cleared' : '-raised';
9820	            const groupName = `${groupPrefix}warning${groupSuffix}`;
9821	            // Ignore constant input if the Call is muted (Expected)
9822	            if (warningName === 'constant-audio-input-level' && this.isMuted()) {
9823	                return;
9824	            }
9825	            let level = wasCleared ? 'info' : 'warning';
9826	            // Avoid throwing false positives as warnings until we refactor volume metrics
9827	            if (warningName === 'constant-audio-output-level') {
9828	                level = 'info';
9829	            }
9830	            const payloadData = { threshold };
9831	            if (value) {
9832	                if (value instanceof Array) {
9833	                    payloadData.values = value.map((val) => {
9834	                        if (typeof val === 'number') {
9835	                            return Math.round(val * 100) / 100;
9836	                        }
9837	                        return value;
9838	                    });
9839	                }
9840	                else {
9841	                    payloadData.value = value;
9842	                }
9843	            }
9844	            this._publisher.post(level, groupName, warningName, { data: payloadData }, this);
9845	            if (warningName !== 'constant-audio-output-level') {
9846	                const emitName = wasCleared ? 'warning-cleared' : 'warning';
9847	                this._log.debug(`#${emitName}`, warningName);
9848	                this.emit(emitName, warningName, warningData && !wasCleared ? warningData : null);
9849	            }
9850	        };
9851	        /**
9852	         * Called when the {@link Call} receives an ack from signaling
9853	         * @param payload
9854	         */
9855	        this._onAck = (payload) => {
9856	            const { acktype, callsid, voiceeventsid } = payload;
9857	            if (this.parameters.CallSid !== callsid) {
9858	                this._log.warn(`Received ack from a different callsid: ${callsid}`);
9859	                return;
9860	            }
9861	            if (acktype === 'message') {
9862	                this._onMessageSent(voiceeventsid);
9863	            }
9864	        };
9865	        /**
9866	         * Called when the {@link Call} is answered.
9867	         * @param payload
9868	         */
9869	        this._onAnswer = (payload) => {
9870	            if (typeof payload.reconnect === 'string') {
9871	                this._signalingReconnectToken = payload.reconnect;
9872	            }
9873	            // answerOnBridge=false will send a 183 which we need to catch in _onRinging when
9874	            // the enableRingingState flag is disabled. In that case, we will receive a 200 after
9875	            // the callee accepts the call firing a second `accept` event if we don't
9876	            // short circuit here.
9877	            if (this._isAnswered && this._status !== Call.State.Reconnecting) {
9878	                return;
9879	            }
9880	            this._setCallSid(payload);
9881	            this._isAnswered = true;
9882	            this._maybeTransitionToOpen();
9883	        };
9884	        /**
9885	         * Called when the {@link Call} is cancelled.
9886	         * @param payload
9887	         */
9888	        this._onCancel = (payload) => {
9889	            // (rrowland) Is this check necessary? Verify, and if so move to pstream / VSP module.
9890	            const callsid = payload.callsid;
9891	            if (this.parameters.CallSid === callsid) {
9892	                this._isCancelled = true;
9893	                this._publisher.info('connection', 'cancel', null, this);
9894	                this._cleanupEventListeners();
9895	                this._mediaHandler.close();
9896	                this._status = Call.State.Closed;
9897	                this._log.debug('#cancel');
9898	                this.emit('cancel');
9899	                this._pstream.removeListener('cancel', this._onCancel);
9900	            }
9901	        };
9902	        /**
9903	         * Called when we receive a connected event from pstream.
9904	         * Re-emits the event.
9905	         */
9906	        this._onConnected = () => {
9907	            this._log.info('Received connected from pstream');
9908	            if (this._signalingReconnectToken && this._mediaHandler.version) {
9909	                this._pstream.reconnect(this._mediaHandler.version.getSDP(), this.parameters.CallSid, this._signalingReconnectToken);
9910	            }
9911	        };
9912	        /**
9913	         * Called when the {@link Call} is hung up.
9914	         * @param payload
9915	         */
9916	        this._onHangup = (payload) => {
9917	            if (this.status() === Call.State.Closed) {
9918	                return;
9919	            }
9920	            /**
9921	             *  see if callsid passed in message matches either callsid or outbound id
9922	             *  call should always have either callsid or outbound id
9923	             *  if no callsid passed hangup anyways
9924	             */
9925	            if (payload.callsid && (this.parameters.CallSid || this.outboundConnectionId)) {
9926	                if (payload.callsid !== this.parameters.CallSid
9927	                    && payload.callsid !== this.outboundConnectionId) {
9928	                    return;
9929	                }
9930	            }
9931	            else if (payload.callsid) {
9932	                // hangup is for another call
9933	                return;
9934	            }
9935	            this._log.info('Received HANGUP from gateway');
9936	            if (payload.error) {
9937	                const code = payload.error.code;
9938	                const errorConstructor = getPreciseSignalingErrorByCode(this._options.enableImprovedSignalingErrorPrecision, code);
9939	                const error = typeof errorConstructor !== 'undefined'
9940	                    ? new errorConstructor(payload.error.message)
9941	                    : new GeneralErrors.ConnectionError('Error sent from gateway in HANGUP', payload.error);
9942	                this._log.error('Received an error from the gateway:', error);
9943	                this._log.debug('#error', error);
9944	                this.emit('error', error);
9945	            }
9946	            this._shouldSendHangup = false;
9947	            this._publisher.info('connection', 'disconnected-by-remote', null, this);
9948	            this._disconnect(null, true);
9949	            this._cleanupEventListeners();
9950	        };
9951	        /**
9952	         * Called when there is a media failure.
9953	         * Manages all media-related states and takes action base on the states
9954	         * @param type - Type of media failure
9955	         */
9956	        this._onMediaFailure = (type) => {
9957	            const { ConnectionDisconnected, ConnectionFailed, IceGatheringFailed, LowBytes, } = Call.MediaFailure;
9958	            // These types signifies the end of a single ICE cycle
9959	            const isEndOfIceCycle = type === ConnectionFailed || type === IceGatheringFailed;
9960	            // All browsers except chrome doesn't update pc.iceConnectionState and pc.connectionState
9961	            // after issuing an ICE Restart, which we use to determine if ICE Restart is complete.
9962	            // Since we cannot detect if ICE Restart is complete, we will not retry.
9963	            if (!isChrome(window, window.navigator) && type === ConnectionFailed) {
9964	                return this._mediaHandler.onerror(MEDIA_DISCONNECT_ERROR);
9965	            }
9966	            // Ignore subsequent requests if ice restart is in progress
9967	            if (this._mediaStatus === Call.State.Reconnecting) {
9968	                // This is a retry. Previous ICE Restart failed
9969	                if (isEndOfIceCycle) {
9970	                    // We already exceeded max retry time.
9971	                    if (Date.now() - this._mediaReconnectStartTime > BACKOFF_CONFIG.max) {
9972	                        this._log.warn('Exceeded max ICE retries');
9973	                        return this._mediaHandler.onerror(MEDIA_DISCONNECT_ERROR);
9974	                    }
9975	                    // Issue ICE restart with backoff
9976	                    try {
9977	                        this._mediaReconnectBackoff.backoff();
9978	                    }
9979	                    catch (error) {
9980	                        // Catch and ignore 'Backoff in progress.' errors. If a backoff is
9981	                        // ongoing and we try to start another one, there shouldn't be a
9982	                        // problem.
9983	                        if (!(error.message && error.message === 'Backoff in progress.')) {
9984	                            throw error;
9985	                        }
9986	                    }
9987	                }
9988	                return;
9989	            }
9990	            const pc = this._mediaHandler.version.pc;
9991	            const isIceDisconnected = pc && pc.iceConnectionState === 'disconnected';
9992	            const hasLowBytesWarning = this._monitor.hasActiveWarning('bytesSent', 'min')
9993	                || this._monitor.hasActiveWarning('bytesReceived', 'min');
9994	            // Only certain conditions can trigger media reconnection
9995	            if ((type === LowBytes && isIceDisconnected)
9996	                || (type === ConnectionDisconnected && hasLowBytesWarning)
9997	                || isEndOfIceCycle) {
9998	                const mediaReconnectionError = new MediaErrors.ConnectionError('Media connection failed.');
9999	                this._log.warn('ICE Connection disconnected.');
10000	                this._publisher.warn('connection', 'error', mediaReconnectionError, this);
10001	                this._publisher.info('connection', 'reconnecting', null, this);
10002	                this._mediaReconnectStartTime = Date.now();
10003	                this._status = Call.State.Reconnecting;
10004	                this._mediaStatus = Call.State.Reconnecting;
10005	                this._mediaReconnectBackoff.reset();
10006	                this._mediaReconnectBackoff.backoff();
10007	                this._log.debug('#reconnecting');
10008	                this.emit('reconnecting', mediaReconnectionError);
10009	            }
10010	        };
10011	        /**
10012	         * Called when media call is restored
10013	         */
10014	        this._onMediaReconnected = () => {
10015	            // Only trigger once.
10016	            // This can trigger on pc.onIceConnectionChange and pc.onConnectionChange.
10017	            if (this._mediaStatus !== Call.State.Reconnecting) {
10018	                return;
10019	            }
10020	            this._log.info('ICE Connection reestablished.');
10021	            this._mediaStatus = Call.State.Open;
10022	            if (this._signalingStatus === Call.State.Open) {
10023	                this._publisher.info('connection', 'reconnected', null, this);
10024	                this._log.debug('#reconnected');
10025	                this.emit('reconnected');
10026	                this._status = Call.State.Open;
10027	            }
10028	        };
10029	        /**
10030	         * Raised when a Call receives a message from the backend.
10031	         * @param payload - A record representing the payload of the message from the
10032	         * Twilio backend.
10033	         */
10034	        this._onMessageReceived = (payload) => {
10035	            const { callsid, content, contenttype, messagetype, voiceeventsid } = payload;
10036	            if (this.parameters.CallSid !== callsid) {
10037	                this._log.warn(`Received a message from a different callsid: ${callsid}`);
10038	                return;
10039	            }
10040	            const data = {
10041	                content,
10042	                contentType: contenttype,
10043	                messageType: messagetype,
10044	                voiceEventSid: voiceeventsid,
10045	            };
10046	            this._publisher.info('call-message', messagetype, {
10047	                content_type: contenttype,
10048	                event_type: 'received',
10049	                voice_event_sid: voiceeventsid,
10050	            }, this);
10051	            this._log.debug('#messageReceived', JSON.stringify(data));
10052	            this.emit('messageReceived', data);
10053	        };
10054	        /**
10055	         * Raised when a Call receives an 'ack' with an 'acktype' of 'message.
10056	         * This means that the message sent via sendMessage API has been received by the signaling server.
10057	         * @param voiceEventSid
10058	         */
10059	        this._onMessageSent = (voiceEventSid) => {
10060	            if (!this._messages.has(voiceEventSid)) {
10061	                this._log.warn(`Received a messageSent with a voiceEventSid that doesn't exists: ${voiceEventSid}`);
10062	                return;
10063	            }
10064	            const message = this._messages.get(voiceEventSid);
10065	            this._messages.delete(voiceEventSid);
10066	            this._publisher.info('call-message', message === null || message === void 0 ? void 0 : message.messageType, {
10067	                content_type: message === null || message === void 0 ? void 0 : message.contentType,
10068	                event_type: 'sent',
10069	                voice_event_sid: voiceEventSid,
10070	            }, this);
10071	            this._log.debug('#messageSent', JSON.stringify(message));
10072	            this.emit('messageSent', message);
10073	        };
10074	        /**
10075	         * When we get a RINGING signal from PStream, update the {@link Call} status.
10076	         * @param payload
10077	         */
10078	        this._onRinging = (payload) => {
10079	            this._setCallSid(payload);
10080	            // If we're not in 'connecting' or 'ringing' state, this event was received out of order.
10081	            if (this._status !== Call.State.Connecting && this._status !== Call.State.Ringing) {
10082	                return;
10083	            }
10084	            const hasEarlyMedia = !!payload.sdp;
10085	            this._status = Call.State.Ringing;
10086	            this._publisher.info('connection', 'outgoing-ringing', { hasEarlyMedia }, this);
10087	            this._log.debug('#ringing');
10088	            this.emit('ringing', hasEarlyMedia);
10089	        };
10090	        /**
10091	         * Called each time StatsMonitor emits a sample.
10092	         * Emits stats event and batches the call stats metrics and sends them to Insights.
10093	         * @param sample
10094	         */
10095	        this._onRTCSample = (sample) => {
10096	            const callMetrics = Object.assign(Object.assign({}, sample), { inputVolume: this._latestInputVolume, outputVolume: this._latestOutputVolume });
10097	            this._codec = callMetrics.codecName;
10098	            this._metricsSamples.push(callMetrics);
10099	            if (this._metricsSamples.length >= METRICS_BATCH_SIZE) {
10100	                this._publishMetrics();
10101	            }
10102	            this.emit('sample', sample);
10103	        };
10104	        /**
10105	         * Called when an 'error' event is received from the signaling stream.
10106	         */
10107	        this._onSignalingError = (payload) => {
10108	            const { callsid, voiceeventsid, error } = payload;
10109	            if (this.parameters.CallSid !== callsid) {
10110	                this._log.warn(`Received an error from a different callsid: ${callsid}`);
10111	                return;
10112	            }
10113	            if (voiceeventsid && this._messages.has(voiceeventsid)) {
10114	                // Do not emit an error here. Device is handling all signaling related errors.
10115	                this._messages.delete(voiceeventsid);
10116	                this._log.warn(`Received an error while sending a message.`, payload);
10117	                this._publisher.error('call-message', 'error', {
10118	                    code: error.code,
10119	                    message: error.message,
10120	                    voice_event_sid: voiceeventsid,
10121	                }, this);
10122	                let twilioError;
10123	                const errorConstructor = getPreciseSignalingErrorByCode(!!this._options.enableImprovedSignalingErrorPrecision, error.code);
10124	                if (typeof errorConstructor !== 'undefined') {
10125	                    twilioError = new errorConstructor(error);
10126	                }
10127	                if (!twilioError) {
10128	                    this._log.error('Unknown Call Message Error: ', error);
10129	                    twilioError = new GeneralErrors.UnknownError(error.message, error);
10130	                }
10131	                this._log.debug('#error', error, twilioError);
10132	                this.emit('error', twilioError);
10133	            }
10134	        };
10135	        /**
10136	         * Called when signaling is restored
10137	         */
10138	        this._onSignalingReconnected = () => {
10139	            if (this._signalingStatus !== Call.State.Reconnecting) {
10140	                return;
10141	            }
10142	            this._log.info('Signaling Connection reestablished.');
10143	            this._signalingStatus = Call.State.Open;
10144	            if (this._mediaStatus === Call.State.Open) {
10145	                this._publisher.info('connection', 'reconnected', null, this);
10146	                this._log.debug('#reconnected');
10147	                this.emit('reconnected');
10148	                this._status = Call.State.Open;
10149	            }
10150	        };
10151	        /**
10152	         * Called when we receive a transportClose event from pstream.
10153	         * Re-emits the event.
10154	         */
10155	        this._onTransportClose = () => {
10156	            this._log.error('Received transportClose from pstream');
10157	            this._log.debug('#transportClose');
10158	            this.emit('transportClose');
10159	            if (this._signalingReconnectToken) {
10160	                this._status = Call.State.Reconnecting;
10161	                this._signalingStatus = Call.State.Reconnecting;
10162	                this._publisher.info('connection', 'reconnecting', null, this);
10163	                this._log.debug('#reconnecting');
10164	                this.emit('reconnecting', new SignalingErrors.ConnectionDisconnected());
10165	            }
10166	            else {
10167	                this._status = Call.State.Closed;
10168	                this._signalingStatus = Call.State.Closed;
10169	            }
10170	        };
10171	        /**
10172	         * Re-emit an StatsMonitor warning as a {@link Call}.warning or .warning-cleared event.
10173	         * @param warningData
10174	         * @param wasCleared - Whether this is a -cleared or -raised event.
10175	         */
10176	        this._reemitWarning = (warningData, wasCleared) => {
10177	            const groupPrefix = /^audio/.test(warningData.name) ?
10178	                'audio-level-' : 'network-quality-';
10179	            const warningPrefix = WARNING_PREFIXES[warningData.threshold.name];
10180	            /**
10181	             * NOTE: There are two "packet-loss" warnings: `high-packet-loss` and
10182	             * `high-packets-lost-fraction`, so in this case we need to use a different
10183	             * `WARNING_NAME` mapping.
10184	             */
10185	            let warningName;
10186	            if (warningData.name in MULTIPLE_THRESHOLD_WARNING_NAMES) {
10187	                warningName = MULTIPLE_THRESHOLD_WARNING_NAMES[warningData.name][warningData.threshold.name];
10188	            }
10189	            else if (warningData.name in WARNING_NAMES) {
10190	                warningName = WARNING_NAMES[warningData.name];
10191	            }
10192	            const warning = warningPrefix + warningName;
10193	            this._emitWarning(groupPrefix, warning, warningData.threshold.value, warningData.values || warningData.value, wasCleared, warningData);
10194	        };
10195	        /**
10196	         * Re-emit an StatsMonitor warning-cleared as a .warning-cleared event.
10197	         * @param warningData
10198	         */
10199	        this._reemitWarningCleared = (warningData) => {
10200	            this._reemitWarning(warningData, true);
10201	        };
10202	        this._soundcache = config.soundcache;
10203	        if (typeof config.onIgnore === 'function') {
10204	            this._onIgnore = config.onIgnore;
10205	        }
10206	        const message = options && options.twimlParams || {};
10207	        this.customParameters = new Map(Object.entries(message).map(([key, val]) => [key, String(val)]));
10208	        Object.assign(this._options, options);
10209	        if (this._options.callParameters) {
10210	            this.parameters = this._options.callParameters;
10211	        }
10212	        if (this._options.reconnectToken) {
10213	            this._signalingReconnectToken = this._options.reconnectToken;
10214	        }
10215	        this._voiceEventSidGenerator =
10216	            this._options.voiceEventSidGenerator || generateVoiceEventSid;
10217	        this._direction = this.parameters.CallSid && !this._options.reconnectCallSid ?
10218	            Call.CallDirection.Incoming : Call.CallDirection.Outgoing;
10219	        if (this.parameters) {
10220	            this.callerInfo = this.parameters.StirStatus
10221	                ? { isVerified: this.parameters.StirStatus === 'TN-Validation-Passed-A' }
10222	                : null;
10223	        }
10224	        else {
10225	            this.callerInfo = null;
10226	        }
10227	        this._mediaReconnectBackoff = new Backoff(BACKOFF_CONFIG);
10228	        this._mediaReconnectBackoff.on('ready', () => this._mediaHandler.iceRestart());
10229	        // temporary call sid to be used for outgoing calls
10230	        this.outboundConnectionId = generateTempCallSid();
10231	        const publisher = this._publisher = config.publisher;
10232	        if (this._direction === Call.CallDirection.Incoming) {
10233	            publisher.info('connection', 'incoming', null, this);
10234	        }
10235	        else {
10236	            publisher.info('connection', 'outgoing', {
10237	                preflight: this._options.preflight,
10238	                reconnect: !!this._options.reconnectCallSid,
10239	            }, this);
10240	        }
10241	        const monitor = this._monitor = new (this._options.StatsMonitor || StatsMonitor)();
10242	        monitor.on('sample', this._onRTCSample);
10243	        // First 20 seconds or so are choppy, so let's not bother with these warnings.
10244	        monitor.disableWarnings();
10245	        setTimeout(() => monitor.enableWarnings(), METRICS_DELAY);
10246	        monitor.on('warning', (data, wasCleared) => {
10247	            if (data.name === 'bytesSent' || data.name === 'bytesReceived') {
10248	                this._onMediaFailure(Call.MediaFailure.LowBytes);
10249	            }
10250	            this._reemitWarning(data, wasCleared);
10251	        });
10252	        monitor.on('warning-cleared', (data) => {
10253	            this._reemitWarningCleared(data);
10254	        });
10255	        this._mediaHandler = new (this._options.MediaHandler)(config.audioHelper, config.pstream, {
10256	            MediaStream: this._options.MediaStream,
10257	            RTCPeerConnection: this._options.RTCPeerConnection,
10258	            codecPreferences: this._options.codecPreferences,
10259	            dscp: this._options.dscp,
10260	            forceAggressiveIceNomination: this._options.forceAggressiveIceNomination,
10261	            maxAverageBitrate: this._options.maxAverageBitrate,
10262	        });
10263	        this.on('volume', (inputVolume, outputVolume) => {
10264	            this._inputVolumeStreak = this._checkVolume(inputVolume, this._inputVolumeStreak, this._latestInputVolume, 'input');
10265	            this._outputVolumeStreak = this._checkVolume(outputVolume, this._outputVolumeStreak, this._latestOutputVolume, 'output');
10266	            this._latestInputVolume = inputVolume;
10267	            this._latestOutputVolume = outputVolume;
10268	        });
10269	        this._mediaHandler.onaudio = (remoteAudio) => {
10270	            this._log.debug('#audio');
10271	            this.emit('audio', remoteAudio);
10272	        };
10273	        this._mediaHandler.onvolume = (inputVolume, outputVolume, internalInputVolume, internalOutputVolume) => {
10274	            // (rrowland) These values mock the 0 -> 32767 format used by legacy getStats. We should look into
10275	            // migrating to a newer standard, either 0.0 -> linear or -127 to 0 in dB, matching the range
10276	            // chosen below.
10277	            monitor.addVolumes((internalInputVolume / 255) * 32767, (internalOutputVolume / 255) * 32767);
10278	            // (rrowland) 0.0 -> 1.0 linear
10279	            this.emit('volume', inputVolume, outputVolume);
10280	        };
10281	        this._mediaHandler.ondtlstransportstatechange = (state) => {
10282	            const level = state === 'failed' ? 'error' : 'debug';
10283	            this._publisher.post(level, 'dtls-transport-state', state, null, this);
10284	        };
10285	        this._mediaHandler.onpcconnectionstatechange = (state) => {
10286	            let level = 'debug';
10287	            const dtlsTransport = this._mediaHandler.getRTCDtlsTransport();
10288	            if (state === 'failed') {
10289	                level = dtlsTransport && dtlsTransport.state === 'failed' ? 'error' : 'warning';
10290	            }
10291	            this._publisher.post(level, 'pc-connection-state', state, null, this);
10292	        };
10293	        this._mediaHandler.onicecandidate = (candidate) => {
10294	            const payload = new IceCandidate(candidate).toPayload();
10295	            this._publisher.debug('ice-candidate', 'ice-candidate', payload, this);
10296	        };
10297	        this._mediaHandler.onselectedcandidatepairchange = (pair) => {
10298	            const localCandidatePayload = new IceCandidate(pair.local).toPayload();
10299	            const remoteCandidatePayload = new IceCandidate(pair.remote, true).toPayload();
10300	            this._publisher.debug('ice-candidate', 'selected-ice-candidate-pair', {
10301	                local_candidate: localCandidatePayload,
10302	                remote_candidate: remoteCandidatePayload,
10303	            }, this);
10304	        };
10305	        this._mediaHandler.oniceconnectionstatechange = (state) => {
10306	            const level = state === 'failed' ? 'error' : 'debug';
10307	            this._publisher.post(level, 'ice-connection-state', state, null, this);
10308	        };
10309	        this._mediaHandler.onicegatheringfailure = (type) => {
10310	            this._publisher.warn('ice-gathering-state', type, null, this);
10311	            this._onMediaFailure(Call.MediaFailure.IceGatheringFailed);
10312	        };
10313	        this._mediaHandler.onicegatheringstatechange = (state) => {
10314	            this._publisher.debug('ice-gathering-state', state, null, this);
10315	        };
10316	        this._mediaHandler.onsignalingstatechange = (state) => {
10317	            this._publisher.debug('signaling-state', state, null, this);
10318	        };
10319	        this._mediaHandler.ondisconnected = (msg) => {
10320	            this._log.warn(msg);
10321	            this._publisher.warn('network-quality-warning-raised', 'ice-connectivity-lost', {
10322	                message: msg,
10323	            }, this);
10324	            this._log.debug('#warning', 'ice-connectivity-lost');
10325	            this.emit('warning', 'ice-connectivity-lost');
10326	            this._onMediaFailure(Call.MediaFailure.ConnectionDisconnected);
10327	        };
10328	        this._mediaHandler.onfailed = (msg) => {
10329	            this._onMediaFailure(Call.MediaFailure.ConnectionFailed);
10330	        };
10331	        this._mediaHandler.onconnected = () => {
10332	            // First time _mediaHandler is connected, but ICE Gathering issued an ICE restart and succeeded.
10333	            if (this._status === Call.State.Reconnecting) {
10334	                this._onMediaReconnected();
10335	            }
10336	        };
10337	        this._mediaHandler.onreconnected = (msg) => {
10338	            this._log.info(msg);
10339	            this._publisher.info('network-quality-warning-cleared', 'ice-connectivity-lost', {
10340	                message: msg,
10341	            }, this);
10342	            this._log.debug('#warning-cleared', 'ice-connectivity-lost');
10343	            this.emit('warning-cleared', 'ice-connectivity-lost');
10344	            this._onMediaReconnected();
10345	        };
10346	        this._mediaHandler.onerror = (e) => {
10347	            if (e.disconnect === true) {
10348	                this._disconnect(e.info && e.info.message);
10349	            }
10350	            const error = e.info.twilioError || new GeneralErrors.UnknownError(e.info.message);
10351	            this._log.error('Received an error from MediaStream:', e);
10352	            this._log.debug('#error', error);
10353	            this.emit('error', error);
10354	        };
10355	        this._mediaHandler.onopen = () => {
10356	            // NOTE(mroberts): While this may have been happening in previous
10357	            // versions of Chrome, since Chrome 45 we have seen the
10358	            // PeerConnection's onsignalingstatechange handler invoked multiple
10359	            // times in the same signalingState 'stable'. When this happens, we
10360	            // invoke this onopen function. If we invoke it twice without checking
10361	            // for _status 'open', we'd accidentally close the PeerConnection.
10362	            //
10363	            // See <https://code.google.com/p/webrtc/issues/detail?id=4996>.
10364	            if (this._status === Call.State.Open || this._status === Call.State.Reconnecting) {
10365	                return;
10366	            }
10367	            else if (this._status === Call.State.Ringing || this._status === Call.State.Connecting) {
10368	                this.mute(this._mediaHandler.isMuted);
10369	                this._mediaStatus = Call.State.Open;
10370	                this._maybeTransitionToOpen();
10371	            }
10372	            else {
10373	                // call was probably canceled sometime before this
10374	                this._mediaHandler.close();
10375	            }
10376	        };
10377	        this._mediaHandler.onclose = () => {
10378	            this._status = Call.State.Closed;
10379	            if (this._options.shouldPlayDisconnect && this._options.shouldPlayDisconnect()
10380	                // Don't play disconnect sound if this was from a cancel event. i.e. the call
10381	                // was ignored or hung up even before it was answered.
10382	                // Similarly, don't play disconnect sound if the call was rejected.
10383	                && !this._isCancelled && !this._isRejected) {
10384	                this._soundcache.get(Device.SoundName.Disconnect).play();
10385	            }
10386	            monitor.disable();
10387	            this._publishMetrics();
10388	            if (!this._isCancelled && !this._isRejected) {
10389	                // tslint:disable no-console
10390	                this._log.debug('#disconnect');
10391	                this.emit('disconnect', this);
10392	            }
10393	        };
10394	        this._pstream = config.pstream;
10395	        this._pstream.on('ack', this._onAck);
10396	        this._pstream.on('cancel', this._onCancel);
10397	        this._pstream.on('error', this._onSignalingError);
10398	        this._pstream.on('ringing', this._onRinging);
10399	        this._pstream.on('transportClose', this._onTransportClose);
10400	        this._pstream.on('connected', this._onConnected);
10401	        this._pstream.on('message', this._onMessageReceived);
10402	        this.on('error', error => {
10403	            this._publisher.error('connection', 'error', {
10404	                code: error.code, message: error.message,
10405	            }, this);
10406	            if (this._pstream && this._pstream.status === 'disconnected') {
10407	                this._cleanupEventListeners();
10408	            }
10409	        });
10410	        this.on('disconnect', () => {
10411	            this._cleanupEventListeners();
10412	        });
10413	    }
10414	    /**
10415	     * Set the audio input tracks from a given stream.
10416	     * @internal
10417	     * @param stream
10418	     */
10419	    _setInputTracksFromStream(stream) {
10420	        return this._mediaHandler.setInputTracksFromStream(stream);
10421	    }
10422	    /**
10423	     * Set the audio output sink IDs.
10424	     * @internal
10425	     * @param sinkIds
10426	     */
10427	    _setSinkIds(sinkIds) {
10428	        return this._mediaHandler._setSinkIds(sinkIds);
10429	    }
10430	    /**
10431	     * Accept the incoming {@link Call}.
10432	     * @param [options]
10433	     */
10434	    accept(options) {
10435	        this._log.debug('.accept', options);
10436	        if (this._status !== Call.State.Pending) {
10437	            this._log.debug(`.accept noop. status is '${this._status}'`);
10438	            return;
10439	        }
10440	        options = options || {};
10441	        const rtcConfiguration = options.rtcConfiguration || this._options.rtcConfiguration;
10442	        const rtcConstraints = options.rtcConstraints || this._options.rtcConstraints || {};
10443	        const audioConstraints = {
10444	            audio: typeof rtcConstraints.audio !== 'undefined' ? rtcConstraints.audio : true,
10445	        };
10446	        this._status = Call.State.Connecting;
10447	        const connect = () => {
10448	            if (this._status !== Call.State.Connecting) {
10449	                // call must have been canceled
10450	                this._cleanupEventListeners();
10451	                this._mediaHandler.close();
10452	                return;
10453	            }
10454	            const onAnswer = (pc) => {
10455	                // Report that the call was answered, and directionality
10456	                const eventName = this._direction === Call.CallDirection.Incoming
10457	                    ? 'accepted-by-local'
10458	                    : 'accepted-by-remote';
10459	                this._publisher.info('connection', eventName, null, this);
10460	                // Report the preferred codec and params as they appear in the SDP
10461	                const { codecName, codecParams } = getPreferredCodecInfo(this._mediaHandler.version.getSDP());
10462	                this._publisher.info('settings', 'codec', {
10463	                    codec_params: codecParams,
10464	                    selected_codec: codecName,
10465	                }, this);
10466	                // Enable RTC monitoring
10467	                this._monitor.enable(pc);
10468	            };
10469	            const sinkIds = typeof this._options.getSinkIds === 'function' && this._options.getSinkIds();
10470	            if (Array.isArray(sinkIds)) {
10471	                this._mediaHandler._setSinkIds(sinkIds).catch(() => {
10472	                    // (rrowland) We don't want this to throw to console since the customer
10473	                    // can't control this. This will most commonly be rejected on browsers
10474	                    // that don't support setting sink IDs.
10475	                });
10476	            }
10477	            this._pstream.addListener('hangup', this._onHangup);
10478	            if (this._direction === Call.CallDirection.Incoming) {
10479	                this._isAnswered = true;
10480	                this._pstream.on('answer', this._onAnswer);
10481	                this._mediaHandler.answerIncomingCall(this.parameters.CallSid, this._options.offerSdp, rtcConfiguration, onAnswer);
10482	            }
10483	            else {
10484	                const params = Array.from(this.customParameters.entr
10484ies()).map(pair => `${encodeURIComponent(pair[0])}=${encodeURIComponent(pair[1])}`).join('&');
10485	                this._pstream.on('answer', this._onAnswer);
10486	                this._mediaHandler.makeOutgoingCall(params, this._signalingReconnectToken, this._options.reconnectCallSid || this.outboundConnectionId, rtcConfiguration, onAnswer);
10487	            }
10488	        };
10489	        if (this._options.beforeAccept) {
10490	            this._options.beforeAccept(this);
10491	        }
10492	        const inputStream = typeof this._options.getInputStream === 'function' && this._options.getInputStream();
10493	        const promise = inputStream
10494	            ? this._mediaHandler.setInputTracksFromStream(inputStream)
10495	            : this._mediaHandler.openDefaultDeviceWithConstraints(audioConstraints);
10496	        promise.then(() => {
10497	            this._publisher.info('get-user-media', 'succeeded', {
10498	                data: { audioConstraints },
10499	            }, this);
10500	            connect();
10501	        }, (error) => {
10502	            let twilioError;
10503	            if (error.code === 31208
10504	                || ['PermissionDeniedError', 'NotAllowedError'].indexOf(error.name) !== -1) {
10505	                twilioError = new UserMediaErrors.PermissionDeniedError();
10506	                this._publisher.error('get-user-media', 'denied', {
10507	                    data: {
10508	                        audioConstraints,
10509	                        error,
10510	                    },
10511	                }, this);
10512	            }
10513	            else {
10514	                twilioError = new UserMediaErrors.AcquisitionFailedError();
10515	                this._publisher.error('get-user-media', 'failed', {
10516	                    data: {
10517	                        audioConstraints,
10518	                        error,
10519	                    },
10520	                }, this);
10521	            }
10522	            this._disconnect();
10523	            this._log.debug('#error', error);
10524	            this.emit('error', twilioError);
10525	        });
10526	    }
10527	    /**
10528	     * Disconnect from the {@link Call}.
10529	     */
10530	    disconnect() {
10531	        this._log.debug('.disconnect');
10532	        this._disconnect();
10533	    }
10534	    /**
10535	     * Get the local MediaStream, if set.
10536	     */
10537	    getLocalStream() {
10538	        return this._mediaHandler && this._mediaHandler.stream;
10539	    }
10540	    /**
10541	     * Get the remote MediaStream, if set.
10542	     */
10543	    getRemoteStream() {
10544	        return this._mediaHandler && this._mediaHandler._remoteStream;
10545	    }
10546	    /**
10547	     * Ignore the incoming {@link Call}.
10548	     */
10549	    ignore() {
10550	        this._log.debug('.ignore');
10551	        if (this._status !== Call.State.Pending) {
10552	            this._log.debug(`.ignore noop. status is '${this._status}'`);
10553	            return;
10554	        }
10555	        this._status = Call.State.Closed;
10556	        this._mediaHandler.ignore(this.parameters.CallSid);
10557	        this._publisher.info('connection', 'ignored-by-local', null, this);
10558	        if (this._onIgnore) {
10559	            this._onIgnore();
10560	        }
10561	    }
10562	    /**
10563	     * Check whether call is muted
10564	     */
10565	    isMuted() {
10566	        return this._mediaHandler.isMuted;
10567	    }
10568	    /**
10569	     * Mute incoming audio.
10570	     * @param shouldMute - Whether the incoming audio should be muted. Defaults to true.
10571	     */
10572	    mute(shouldMute = true) {
10573	        this._log.debug('.mute', shouldMute);
10574	        const wasMuted = this._mediaHandler.isMuted;
10575	        this._mediaHandler.mute(shouldMute);
10576	        const isMuted = this._mediaHandler.isMuted;
10577	        if (wasMuted !== isMuted) {
10578	            this._publisher.info('connection', isMuted ? 'muted' : 'unmuted', null, this);
10579	            this._log.debug('#mute', isMuted);
10580	            this.emit('mute', isMuted, this);
10581	        }
10582	    }
10583	    /**
10584	     * Post an event to Endpoint Analytics indicating that the end user
10585	     *   has given call quality feedback. Called without a score, this
10586	     *   will report that the customer declined to give feedback.
10587	     * @param score - The end-user's rating of the call; an
10588	     *   integer 1 through 5. Or undefined if the user declined to give
10589	     *   feedback.
10590	     * @param issue - The primary issue the end user
10591	     *   experienced on the call. Can be: ['one-way-audio', 'choppy-audio',
10592	     *   'dropped-call', 'audio-latency', 'noisy-call', 'echo']
10593	     */
10594	    postFeedback(score, issue) {
10595	        if (typeof score === 'undefined' || score === null) {
10596	            return this._postFeedbackDeclined();
10597	        }
10598	        if (!Object.values(Call.FeedbackScore).includes(score)) {
10599	            throw new InvalidArgumentError(`Feedback score must be one of: ${Object.values(Call.FeedbackScore)}`);
10600	        }
10601	        if (typeof issue !== 'undefined' && issue !== null && !Object.values(Call.FeedbackIssue).includes(issue)) {
10602	            throw new InvalidArgumentError(`Feedback issue must be one of: ${Object.values(Call.FeedbackIssue)}`);
10603	        }
10604	        return this._publisher.info('feedback', 'received', {
10605	            issue_name: issue,
10606	            quality_score: score,
10607	        }, this, true);
10608	    }
10609	    /**
10610	     * Reject the incoming {@link Call}.
10611	     */
10612	    reject() {
10613	        this._log.debug('.reject');
10614	        if (this._status !== Call.State.Pending) {
10615	            this._log.debug(`.reject noop. status is '${this._status}'`);
10616	            return;
10617	        }
10618	        this._isRejected = true;
10619	        this._pstream.reject(this.parameters.CallSid);
10620	        this._mediaHandler.reject(this.parameters.CallSid);
10621	        this._publisher.info('connection', 'rejected-by-local', null, this);
10622	        this._cleanupEventListeners();
10623	        this._mediaHandler.close();
10624	        this._status = Call.State.Closed;
10625	        this._log.debug('#reject');
10626	        this.emit('reject');
10627	    }
10628	    /**
10629	     * Send a string of digits.
10630	     * @param digits
10631	     */
10632	    sendDigits(digits) {
10633	        this._log.debug('.sendDigits', digits);
10634	        if (digits.match(/[^0-9*#w]/)) {
10635	            throw new InvalidArgumentError('Illegal character passed into sendDigits');
10636	        }
10637	        const customSounds = this._options.customSounds || {};
10638	        const sequence = [];
10639	        digits.split('').forEach((digit) => {
10640	            let dtmf = (digit !== 'w') ? `dtmf${digit}` : '';
10641	            if (dtmf === 'dtmf*') {
10642	                dtmf = 'dtmfs';
10643	            }
10644	            if (dtmf === 'dtmf#') {
10645	                dtmf = 'dtmfh';
10646	            }
10647	            sequence.push(dtmf);
10648	        });
10649	        const playNextDigit = () => {
10650	            const digit = sequence.shift();
10651	            if (digit) {
10652	                if (this._options.dialtonePlayer && !customSounds[digit]) {
10653	                    this._options.dialtonePlayer.play(digit);
10654	                }
10655	                else {
10656	                    this._soundcache.get(digit).play();
10657	                }
10658	            }
10659	            if (sequence.length) {
10660	                setTimeout(() => playNextDigit(), 200);
10661	            }
10662	        };
10663	        playNextDigit();
10664	        const dtmfSender = this._mediaHandler.getOrCreateDTMFSender();
10665	        function insertDTMF(dtmfs) {
10666	            if (!dtmfs.length) {
10667	                return;
10668	            }
10669	            const dtmf = dtmfs.shift();
10670	            if (dtmf && dtmf.length) {
10671	                dtmfSender.insertDTMF(dtmf, DTMF_TONE_DURATION, DTMF_INTER_TONE_GAP);
10672	            }
10673	            setTimeout(insertDTMF.bind(null, dtmfs), DTMF_PAUSE_DURATION);
10674	        }
10675	        if (dtmfSender) {
10676	            if (!('canInsertDTMF' in dtmfSender) || dtmfSender.canInsertDTMF) {
10677	                this._log.info('Sending digits using RTCDTMFSender');
10678	                // NOTE(mroberts): We can't just map 'w' to ',' since
10679	                // RTCDTMFSender's pause duration is 2 s and Twilio's is more
10680	                // like 500 ms. Instead, we will fudge it with setTimeout.
10681	                insertDTMF(digits.split('w'));
10682	                return;
10683	            }
10684	            this._log.info('RTCDTMFSender cannot insert DTMF');
10685	        }
10686	        // send pstream message to send DTMF
10687	        this._log.info('Sending digits over PStream');
10688	        if (this._pstream !== null && this._pstream.status !== 'disconnected') {
10689	            this._pstream.dtmf(this.parameters.CallSid, digits);
10690	        }
10691	        else {
10692	            const error = new GeneralErrors.ConnectionError('Could not send DTMF: Signaling channel is disconnected');
10693	            this._log.debug('#error', error);
10694	            this.emit('error', error);
10695	        }
10696	    }
10697	    /**
10698	     * Send a message to Twilio. Your backend application can listen for these
10699	     * messages to allow communication between your frontend and backend applications.
10700	     * <br/><br/>This feature is currently in Beta.
10701	     * @param message - The message object to send.
10702	     * @returns A voice event sid that uniquely identifies the message that was sent.
10703	     */
10704	    sendMessage(message) {
10705	        this._log.debug('.sendMessage', JSON.stringify(message));
10706	        const { content, contentType, messageType } = message;
10707	        if (typeof content === 'undefined' || content === null) {
10708	            throw new InvalidArgumentError('`content` is empty');
10709	        }
10710	        if (typeof messageType !== 'string') {
10711	            throw new InvalidArgumentError('`messageType` must be a string.');
10712	        }
10713	        if (messageType.length === 0) {
10714	            throw new InvalidArgumentError('`messageType` must be a non-empty string.');
10715	        }
10716	        if (this._pstream === null) {
10717	            throw new InvalidStateError('Could not send CallMessage; Signaling channel is disconnected');
10718	        }
10719	        const callSid = this.parameters.CallSid;
10720	        if (typeof this.parameters.CallSid === 'undefined') {
10721	            throw new InvalidStateError('Could not send CallMessage; Call has no CallSid');
10722	        }
10723	        const voiceEventSid = this._voiceEventSidGenerator();
10724	        this._messages.set(voiceEventSid, { content, contentType, messageType, voiceEventSid });
10725	        this._pstream.sendMessage(callSid, content, contentType, messageType, voiceEventSid);
10726	        return voiceEventSid;
10727	    }
10728	    /**
10729	     * Get the current {@link Call} status.
10730	     */
10731	    status() {
10732	        return this._status;
10733	    }
10734	    /**
10735	     * Check the volume passed, emitting a warning if one way audio is detected or cleared.
10736	     * @param currentVolume - The current volume for this direction
10737	     * @param streakFieldName - The name of the field on the {@link Call} object that tracks how many times the
10738	     *   current value has been repeated consecutively.
10739	     * @param lastValueFieldName - The name of the field on the {@link Call} object that tracks the most recent
10740	     *   volume for this direction
10741	     * @param direction - The directionality of this audio track, either 'input' or 'output'
10742	     * @returns The current streak; how many times in a row the same value has been polled.
10743	     */
10744	    _checkVolume(currentVolume, currentStreak, lastValue, direction) {
10745	        const wasWarningRaised = currentStreak >= 10;
10746	        let newStreak = 0;
10747	        if (lastValue === currentVolume) {
10748	            newStreak = currentStreak;
10749	        }
10750	        if (newStreak >= 10) {
10751	            this._emitWarning('audio-level-', `constant-audio-${direction}-level`, 10, newStreak, false);
10752	        }
10753	        else if (wasWarningRaised) {
10754	            this._emitWarning('audio-level-', `constant-audio-${direction}-level`, 10, newStreak, true);
10755	        }
10756	        return newStreak;
10757	    }
10758	    /**
10759	     * Clean up event listeners.
10760	     */
10761	    _cleanupEventListeners() {
10762	        const cleanup = () => {
10763	            if (!this._pstream) {
10764	                return;
10765	            }
10766	            this._pstream.removeListener('ack', this._onAck);
10767	            this._pstream.removeListener('answer', this._onAnswer);
10768	            this._pstream.removeListener('cancel', this._onCancel);
10769	            this._pstream.removeListener('error', this._onSignalingError);
10770	            this._pstream.removeListener('hangup', this._onHangup);
10771	            this._pstream.removeListener('ringing', this._onRinging);
10772	            this._pstream.removeListener('transportClose', this._onTransportClose);
10773	            this._pstream.removeListener('connected', this._onConnected);
10774	            this._pstream.removeListener('message', this._onMessageReceived);
10775	        };
10776	        // This is kind of a hack, but it lets us avoid rewriting more code.
10777	        // Basically, there's a sequencing problem with the way PeerConnection raise
10777s
10778	        // the
10779	        //
10780	        //   Cannot establish call. SDK is disconnected
10781	        //
10782	        // error in Call#accept. It calls PeerConnection#onerror, which emits
10783	        // the error event on Call. An error handler on Call then calls
10784	        // cleanupEventListeners, but then control returns to Call#accept. It's
10785	        // at this point that we add a listener for the answer event that never gets
10786	        // removed. setTimeout will allow us to rerun cleanup again, _after_
10787	        // Call#accept returns.
10788	        cleanup();
10789	        setTimeout(cleanup, 0);
10790	    }
10791	    /**
10792	     * Create the payload wrapper for a batch of metrics to be sent to Insights.
10793	     */
10794	    _createMetricPayload() {
10795	        const payload = {
10796	            call_sid: this.parameters.CallSid,
10797	            dscp: !!this._options.dscp,
10798	            sdk_version: RELEASE_VERSION,
10799	        };
10800	        if (this._options.gateway) {
10801	            payload.gateway = this._options.gateway;
10802	        }
10803	        payload.direction = this._direction;
10804	        return payload;
10805	    }
10806	    /**
10807	     * Disconnect the {@link Call}.
10808	     * @param message - A message explaining why the {@link Call} is being disconnected.
10809	     * @param wasRemote - Whether the disconnect was triggered locally or remotely.
10810	     */
10811	    _disconnect(message, wasRemote) {
10812	        message = typeof message === 'string' ? message : null;
10813	        if (this._status !== Call.State.Open
10814	            && this._status !== Call.State.Connecting
10815	            && this._status !== Call.State.Reconnecting
10816	            && this._status !== Call.State.Ringing) {
10817	            return;
10818	        }
10819	        this._log.info('Disconnecting...');
10820	        // send pstream hangup message
10821	        if (this._pstream !== null && this._pstream.status !== 'disconnected' && this._shouldSendHangup) {
10822	            const callsid = this.parameters.CallSid || this.outboundConnectionId;
10823	            if (callsid) {
10824	                this._pstream.hangup(callsid, message);
10825	            }
10826	        }
10827	        this._cleanupEventListeners();
10828	        this._mediaHandler.close();
10829	        if (!wasRemote) {
10830	            this._publisher.info('connection', 'disconnected-by-local', null, this);
10831	        }
10832	    }
10833	    /**
10834	     * Transition to {@link CallStatus.Open} if criteria is met.
10835	     */
10836	    _maybeTransitionToOpen() {
10837	        this._wasConnected;
10838	        if (this._isAnswered) {
10839	            this._onSignalingReconnected();
10840	            this._signalingStatus = Call.State.Open;
10841	            if (this._mediaHandler && this._mediaHandler.status === 'open') {
10842	                this._status = Call.State.Open;
10843	                if (!this._wasConnected) {
10844	                    this._wasConnected = true;
10845	                    this._log.debug('#accept');
10846	                    this.emit('accept', this);
10847	                }
10848	            }
10849	        }
10850	    }
10851	    /**
10852	     * Post an event to Endpoint Analytics indicating that the end user
10853	     *   has ignored a request for feedback.
10854	     */
10855	    _postFeedbackDeclined() {
10856	        return this._publisher.info('feedback', 'received-none', null, this, true);
10857	    }
10858	    /**
10859	     * Publish the current set of queued metrics samples to Insights.
10860	     */
10861	    _publishMetrics() {
10862	        if (this._metricsSamples.length === 0) {
10863	            return;
10864	        }
10865	        this._publisher.postMetrics('quality-metrics-samples', 'metrics-sample', this._metricsSamples.splice(0), this._createMetricPayload(), this).catch((e) => {
10866	            this._log.warn('Unable to post metrics to Insights. Received error:', e);
10867	        });
10868	    }
10869	    /**
10870	     * Set the CallSid
10871	     * @param payload
10872	     */
10873	    _setCallSid(payload) {
10874	        const callSid = payload.callsid;
10875	        if (!callSid) {
10876	            return;
10877	        }
10878	        this.parameters.CallSid = callSid;
10879	        this._mediaHandler.callSid = callSid;
10880	    }
10881	}
10882	/**
10883	 * String representation of the {@link Call} class.
10884	 */
10885	Call.toString = () => '[Twilio.Call class]';
10886	/**
10887	 * @mergeModuleWith Call
10888	 */
10889	(function (Call) {
10890	    (function (State) {
10891	        State["Closed"] = "closed";
10892	        State["Connecting"] = "connecting";
10893	        State["Open"] = "open";
10894	        State["Pending"] = "pending";
10895	        State["Reconnecting"] = "reconnecting";
10896	        State["Ringing"] = "ringing";
10897	    })(Call.State || (Call.State = {}));
10898	    (function (FeedbackIssue) {
10899	        FeedbackIssue["AudioLatency"] = "audio-latency";
10900	        FeedbackIssue["ChoppyAudio"] = "choppy-audio";
10901	        FeedbackIssue["DroppedCall"] = "dropped-call";
10902	        FeedbackIssue["Echo"] = "echo";
10903	        FeedbackIssue["NoisyCall"] = "noisy-call";
10904	        FeedbackIssue["OneWayAudio"] = "one-way-audio";
10905	    })(Call.FeedbackIssue || (Call.FeedbackIssue = {}));
10906	    (function (FeedbackScore) {
10907	        FeedbackScore[FeedbackScore["One"] = 1] = "One";
10908	        FeedbackScore[FeedbackScore["Two"] = 2] = "Two";
10909	        FeedbackScore[FeedbackScore["Three"] = 3] = "Three";
10910	        FeedbackScore[FeedbackScore["Four"] = 4] = "Four";
10911	        FeedbackScore[FeedbackScore["Five"] = 5] = "Five";
10912	    })(Call.FeedbackScore || (Call.FeedbackScore = {}));
10913	    (function (CallDirection) {
10914	        CallDirection["Incoming"] = "INCOMING";
10915	        CallDirection["Outgoing"] = "OUTGOING";
10916	    })(Call.CallDirection || (Call.CallDirection = {}));
10917	    (function (Codec) {
10918	        Codec["Opus"] = "opus";
10919	        Codec["PCMU"] = "pcmu";
10920	    })(Call.Codec || (Call.Codec = {}));
10921	    (function (IceGatheringFailureReason) {
10922	        IceGatheringFailureReason["None"] = "none";
10923	        IceGatheringFailureReason["Timeout"] = "timeout";
10924	    })(Call.IceGatheringFailureReason || (Call.IceGatheringFailureReason = {}));
10925	    (function (MediaFailure) {
10926	        MediaFailure["ConnectionDisconnected"] = "ConnectionDisconnected";
10927	        MediaFailure["ConnectionFailed"] = "ConnectionFailed";
10928	        MediaFailure["IceGatheringFailed"] = "IceGatheringFailed";
10929	        MediaFailure["LowBytes"] = "LowBytes";
10930	    })(Call.MediaFailure || (Call.MediaFailure = {}));
10931	})(Call || (Call = {}));
10932	function generateTempCallSid() {
10933	    return 'TJSxxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
10934	        /* tslint:disable:no-bitwise */
10935	        const r = Math.random() * 16 | 0;
10936	        const v = c === 'x' ? r : (r & 0x3 | 0x8);
10937	        /* tslint:enable:no-bitwise */
10938	        return v.toString(16);
10939	    });
10940	}
10941
10942	// goxee-voice.js
10943
10944	/**
10945	 * A wrapper that exposes simple global functions:
10946	 * - GoxeeVoice.createDevice(token)
10947	 * - GoxeeVoice.getDevice()
10948	 *
10949	 * This makes the new Twilio Voice SDK v2 act similar to Twilio.Device from v1.
10950	 */
10951	window.GoxeeVoice = (function () {
10952	  let device = null;
10953
10954	  function createDevice(token, options = {}) {
10955	    if (!device) {
10956	      device = new Device(token, options);
10957	      device.register(); // Registers for incoming calls
10958	      window.twilioDevice = device; // for debugging (optional)
10959	    } else {
10960	      device.updateToken(token);
10961	    }
10962	    return device;
10963	  }
10964
10965	  function getDevice() {
10966	    return device;
10967	  }
10968
10969	  return {
10970	    createDevice,
10971	    getDevice,
10972	  };
10973	})();
10974
10975})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.