From 3ebdf2931b18f0ee6bf473bd929a27aa3123d629 Mon Sep 17 00:00:00 2001 From: Song367 <601337784@qq.com> Date: Tue, 17 Jun 2025 20:43:31 +0800 Subject: [PATCH] first commit --- duix/duix.js | 20132 +++++++++++++++++++++++++++++++++++++++++++++++++ simple.html | 379 + 2 files changed, 20511 insertions(+) create mode 100644 duix/duix.js create mode 100644 simple.html diff --git a/duix/duix.js b/duix/duix.js new file mode 100644 index 0000000..95a2b5f --- /dev/null +++ b/duix/duix.js @@ -0,0 +1,20132 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.DUIX = factory()); +})(this, (function () { 'use strict'; + + function _mergeNamespaces(n, m) { + m.forEach(function (e) { + e && typeof e !== 'string' && !Array.isArray(e) && Object.keys(e).forEach(function (k) { + if (k !== 'default' && !(k in n)) { + var d = Object.getOwnPropertyDescriptor(e, k); + Object.defineProperty(n, k, d.get ? d : { + enumerable: true, + get: function () { return e[k]; } + }); + } + }); + }); + return Object.freeze(n); + } + + function _iterableToArrayLimit(arr, i) { + var _i = null == arr ? null : "undefined" != typeof Symbol && arr[Symbol.iterator] || arr["@@iterator"]; + if (null != _i) { + var _s, + _e, + _x, + _r, + _arr = [], + _n = !0, + _d = !1; + try { + if (_x = (_i = _i.call(arr)).next, 0 === i) { + if (Object(_i) !== _i) return; + _n = !1; + } else for (; !(_n = (_s = _x.call(_i)).done) && (_arr.push(_s.value), _arr.length !== i); _n = !0); + } catch (err) { + _d = !0, _e = err; + } finally { + try { + if (!_n && null != _i.return && (_r = _i.return(), Object(_r) !== _r)) return; + } finally { + if (_d) throw _e; + } + } + return _arr; + } + } + function ownKeys(object, enumerableOnly) { + var keys = Object.keys(object); + if (Object.getOwnPropertySymbols) { + var symbols = Object.getOwnPropertySymbols(object); + enumerableOnly && (symbols = symbols.filter(function (sym) { + return Object.getOwnPropertyDescriptor(object, sym).enumerable; + })), keys.push.apply(keys, symbols); + } + return keys; + } + function _objectSpread2(target) { + for (var i = 1; i < arguments.length; i++) { + var source = null != arguments[i] ? arguments[i] : {}; + i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { + _defineProperty(target, key, source[key]); + }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { + Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); + }); + } + return target; + } + function _regeneratorRuntime() { + _regeneratorRuntime = function () { + return exports; + }; + var exports = {}, + Op = Object.prototype, + hasOwn = Op.hasOwnProperty, + defineProperty = Object.defineProperty || function (obj, key, desc) { + obj[key] = desc.value; + }, + $Symbol = "function" == typeof Symbol ? Symbol : {}, + iteratorSymbol = $Symbol.iterator || "@@iterator", + asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator", + toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag"; + function define(obj, key, value) { + return Object.defineProperty(obj, key, { + value: value, + enumerable: !0, + configurable: !0, + writable: !0 + }), obj[key]; + } + try { + define({}, ""); + } catch (err) { + define = function (obj, key, value) { + return obj[key] = value; + }; + } + function wrap(innerFn, outerFn, self, tryLocsList) { + var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator, + generator = Object.create(protoGenerator.prototype), + context = new Context(tryLocsList || []); + return defineProperty(generator, "_invoke", { + value: makeInvokeMethod(innerFn, self, context) + }), generator; + } + function tryCatch(fn, obj, arg) { + try { + return { + type: "normal", + arg: fn.call(obj, arg) + }; + } catch (err) { + return { + type: "throw", + arg: err + }; + } + } + exports.wrap = wrap; + var ContinueSentinel = {}; + function Generator() {} + function GeneratorFunction() {} + function GeneratorFunctionPrototype() {} + var IteratorPrototype = {}; + define(IteratorPrototype, iteratorSymbol, function () { + return this; + }); + var getProto = Object.getPrototypeOf, + NativeIteratorPrototype = getProto && getProto(getProto(values([]))); + NativeIteratorPrototype && NativeIteratorPrototype !== Op && hasOwn.call(NativeIteratorPrototype, iteratorSymbol) && (IteratorPrototype = NativeIteratorPrototype); + var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype); + function defineIteratorMethods(prototype) { + ["next", "throw", "return"].forEach(function (method) { + define(prototype, method, function (arg) { + return this._invoke(method, arg); + }); + }); + } + function AsyncIterator(generator, PromiseImpl) { + function invoke(method, arg, resolve, reject) { + var record = tryCatch(generator[method], generator, arg); + if ("throw" !== record.type) { + var result = record.arg, + value = result.value; + return value && "object" == typeof value && hasOwn.call(value, "__await") ? PromiseImpl.resolve(value.__await).then(function (value) { + invoke("next", value, resolve, reject); + }, function (err) { + invoke("throw", err, resolve, reject); + }) : PromiseImpl.resolve(value).then(function (unwrapped) { + result.value = unwrapped, resolve(result); + }, function (error) { + return invoke("throw", error, resolve, reject); + }); + } + reject(record.arg); + } + var previousPromise; + defineProperty(this, "_invoke", { + value: function (method, arg) { + function callInvokeWithMethodAndArg() { + return new PromiseImpl(function (resolve, reject) { + invoke(method, arg, resolve, reject); + }); + } + return previousPromise = previousPromise ? previousPromise.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg(); + } + }); + } + function makeInvokeMethod(innerFn, self, context) { + var state = "suspendedStart"; + return function (method, arg) { + if ("executing" === state) throw new Error("Generator is already running"); + if ("completed" === state) { + if ("throw" === method) throw arg; + return { + value: void 0, + done: !0 + }; + } + for (context.method = method, context.arg = arg;;) { + var delegate = context.delegate; + if (delegate) { + var delegateResult = maybeInvokeDelegate(delegate, context); + if (delegateResult) { + if (delegateResult === ContinueSentinel) continue; + return delegateResult; + } + } + if ("next" === context.method) context.sent = context._sent = context.arg;else if ("throw" === context.method) { + if ("suspendedStart" === state) throw state = "completed", context.arg; + context.dispatchException(context.arg); + } else "return" === context.method && context.abrupt("return", context.arg); + state = "executing"; + var record = tryCatch(innerFn, self, context); + if ("normal" === record.type) { + if (state = context.done ? "completed" : "suspendedYield", record.arg === ContinueSentinel) continue; + return { + value: record.arg, + done: context.done + }; + } + "throw" === record.type && (state = "completed", context.method = "throw", context.arg = record.arg); + } + }; + } + function maybeInvokeDelegate(delegate, context) { + var methodName = context.method, + method = delegate.iterator[methodName]; + if (undefined === method) return context.delegate = null, "throw" === methodName && delegate.iterator.return && (context.method = "return", context.arg = undefined, maybeInvokeDelegate(delegate, context), "throw" === context.method) || "return" !== methodName && (context.method = "throw", context.arg = new TypeError("The iterator does not provide a '" + methodName + "' method")), ContinueSentinel; + var record = tryCatch(method, delegate.iterator, context.arg); + if ("throw" === record.type) return context.method = "throw", context.arg = record.arg, context.delegate = null, ContinueSentinel; + var info = record.arg; + return info ? info.done ? (context[delegate.resultName] = info.value, context.next = delegate.nextLoc, "return" !== context.method && (context.method = "next", context.arg = undefined), context.delegate = null, ContinueSentinel) : info : (context.method = "throw", context.arg = new TypeError("iterator result is not an object"), context.delegate = null, ContinueSentinel); + } + function pushTryEntry(locs) { + var entry = { + tryLoc: locs[0] + }; + 1 in locs && (entry.catchLoc = locs[1]), 2 in locs && (entry.finallyLoc = locs[2], entry.afterLoc = locs[3]), this.tryEntries.push(entry); + } + function resetTryEntry(entry) { + var record = entry.completion || {}; + record.type = "normal", delete record.arg, entry.completion = record; + } + function Context(tryLocsList) { + this.tryEntries = [{ + tryLoc: "root" + }], tryLocsList.forEach(pushTryEntry, this), this.reset(!0); + } + function values(iterable) { + if (iterable || "" === iterable) { + var iteratorMethod = iterable[iteratorSymbol]; + if (iteratorMethod) return iteratorMethod.call(iterable); + if ("function" == typeof iterable.next) return iterable; + if (!isNaN(iterable.length)) { + var i = -1, + next = function next() { + for (; ++i < iterable.length;) if (hasOwn.call(iterable, i)) return next.value = iterable[i], next.done = !1, next; + return next.value = undefined, next.done = !0, next; + }; + return next.next = next; + } + } + throw new TypeError(typeof iterable + " is not iterable"); + } + return GeneratorFunction.prototype = GeneratorFunctionPrototype, defineProperty(Gp, "constructor", { + value: GeneratorFunctionPrototype, + configurable: !0 + }), defineProperty(GeneratorFunctionPrototype, "constructor", { + value: GeneratorFunction, + configurable: !0 + }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, toStringTagSymbol, "GeneratorFunction"), exports.isGeneratorFunction = function (genFun) { + var ctor = "function" == typeof genFun && genFun.constructor; + return !!ctor && (ctor === GeneratorFunction || "GeneratorFunction" === (ctor.displayName || ctor.name)); + }, exports.mark = function (genFun) { + return Object.setPrototypeOf ? Object.setPrototypeOf(genFun, GeneratorFunctionPrototype) : (genFun.__proto__ = GeneratorFunctionPrototype, define(genFun, toStringTagSymbol, "GeneratorFunction")), genFun.prototype = Object.create(Gp), genFun; + }, exports.awrap = function (arg) { + return { + __await: arg + }; + }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, asyncIteratorSymbol, function () { + return this; + }), exports.AsyncIterator = AsyncIterator, exports.async = function (innerFn, outerFn, self, tryLocsList, PromiseImpl) { + void 0 === PromiseImpl && (PromiseImpl = Promise); + var iter = new AsyncIterator(wrap(innerFn, outerFn, self, tryLocsList), PromiseImpl); + return exports.isGeneratorFunction(outerFn) ? iter : iter.next().then(function (result) { + return result.done ? result.value : iter.next(); + }); + }, defineIteratorMethods(Gp), define(Gp, toStringTagSymbol, "Generator"), define(Gp, iteratorSymbol, function () { + return this; + }), define(Gp, "toString", function () { + return "[object Generator]"; + }), exports.keys = function (val) { + var object = Object(val), + keys = []; + for (var key in object) keys.push(key); + return keys.reverse(), function next() { + for (; keys.length;) { + var key = keys.pop(); + if (key in object) return next.value = key, next.done = !1, next; + } + return next.done = !0, next; + }; + }, exports.values = values, Context.prototype = { + constructor: Context, + reset: function (skipTempReset) { + if (this.prev = 0, this.next = 0, this.sent = this._sent = undefined, this.done = !1, this.delegate = null, this.method = "next", this.arg = undefined, this.tryEntries.forEach(resetTryEntry), !skipTempReset) for (var name in this) "t" === name.charAt(0) && hasOwn.call(this, name) && !isNaN(+name.slice(1)) && (this[name] = undefined); + }, + stop: function () { + this.done = !0; + var rootRecord = this.tryEntries[0].completion; + if ("throw" === rootRecord.type) throw rootRecord.arg; + return this.rval; + }, + dispatchException: function (exception) { + if (this.done) throw exception; + var context = this; + function handle(loc, caught) { + return record.type = "throw", record.arg = exception, context.next = loc, caught && (context.method = "next", context.arg = undefined), !!caught; + } + for (var i = this.tryEntries.length - 1; i >= 0; --i) { + var entry = this.tryEntries[i], + record = entry.completion; + if ("root" === entry.tryLoc) return handle("end"); + if (entry.tryLoc <= this.prev) { + var hasCatch = hasOwn.call(entry, "catchLoc"), + hasFinally = hasOwn.call(entry, "finallyLoc"); + if (hasCatch && hasFinally) { + if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0); + if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc); + } else if (hasCatch) { + if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0); + } else { + if (!hasFinally) throw new Error("try statement without catch or finally"); + if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc); + } + } + } + }, + abrupt: function (type, arg) { + for (var i = this.tryEntries.length - 1; i >= 0; --i) { + var entry = this.tryEntries[i]; + if (entry.tryLoc <= this.prev && hasOwn.call(entry, "finallyLoc") && this.prev < entry.finallyLoc) { + var finallyEntry = entry; + break; + } + } + finallyEntry && ("break" === type || "continue" === type) && finallyEntry.tryLoc <= arg && arg <= finallyEntry.finallyLoc && (finallyEntry = null); + var record = finallyEntry ? finallyEntry.completion : {}; + return record.type = type, record.arg = arg, finallyEntry ? (this.method = "next", this.next = finallyEntry.finallyLoc, ContinueSentinel) : this.complete(record); + }, + complete: function (record, afterLoc) { + if ("throw" === record.type) throw record.arg; + return "break" === record.type || "continue" === record.type ? this.next = record.arg : "return" === record.type ? (this.rval = this.arg = record.arg, this.method = "return", this.next = "end") : "normal" === record.type && afterLoc && (this.next = afterLoc), ContinueSentinel; + }, + finish: function (finallyLoc) { + for (var i = this.tryEntries.length - 1; i >= 0; --i) { + var entry = this.tryEntries[i]; + if (entry.finallyLoc === finallyLoc) return this.complete(entry.completion, entry.afterLoc), resetTryEntry(entry), ContinueSentinel; + } + }, + catch: function (tryLoc) { + for (var i = this.tryEntries.length - 1; i >= 0; --i) { + var entry = this.tryEntries[i]; + if (entry.tryLoc === tryLoc) { + var record = entry.completion; + if ("throw" === record.type) { + var thrown = record.arg; + resetTryEntry(entry); + } + return thrown; + } + } + throw new Error("illegal catch attempt"); + }, + delegateYield: function (iterable, resultName, nextLoc) { + return this.delegate = { + iterator: values(iterable), + resultName: resultName, + nextLoc: nextLoc + }, "next" === this.method && (this.arg = undefined), ContinueSentinel; + } + }, exports; + } + function _typeof(obj) { + "@babel/helpers - typeof"; + + return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { + return typeof obj; + } : function (obj) { + return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }, _typeof(obj); + } + function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error) { + reject(error); + return; + } + if (info.done) { + resolve(value); + } else { + Promise.resolve(value).then(_next, _throw); + } + } + function _asyncToGenerator(fn) { + return function () { + var self = this, + args = arguments; + return new Promise(function (resolve, reject) { + var gen = fn.apply(self, args); + function _next(value) { + asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); + } + function _throw(err) { + asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); + } + _next(undefined); + }); + }; + } + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + function _defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); + } + } + function _createClass(Constructor, protoProps, staticProps) { + if (protoProps) _defineProperties(Constructor.prototype, protoProps); + if (staticProps) _defineProperties(Constructor, staticProps); + Object.defineProperty(Constructor, "prototype", { + writable: false + }); + return Constructor; + } + function _defineProperty(obj, key, value) { + key = _toPropertyKey(key); + if (key in obj) { + Object.defineProperty(obj, key, { + value: value, + enumerable: true, + configurable: true, + writable: true + }); + } else { + obj[key] = value; + } + return obj; + } + function _inherits(subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError("Super expression must either be null or a function"); + } + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + writable: true, + configurable: true + } + }); + Object.defineProperty(subClass, "prototype", { + writable: false + }); + if (superClass) _setPrototypeOf(subClass, superClass); + } + function _getPrototypeOf(o) { + _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { + return o.__proto__ || Object.getPrototypeOf(o); + }; + return _getPrototypeOf(o); + } + function _setPrototypeOf(o, p) { + _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { + o.__proto__ = p; + return o; + }; + return _setPrototypeOf(o, p); + } + function _isNativeReflectConstruct() { + if (typeof Reflect === "undefined" || !Reflect.construct) return false; + if (Reflect.construct.sham) return false; + if (typeof Proxy === "function") return true; + try { + Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); + return true; + } catch (e) { + return false; + } + } + function _assertThisInitialized(self) { + if (self === void 0) { + throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + } + return self; + } + function _possibleConstructorReturn(self, call) { + if (call && (typeof call === "object" || typeof call === "function")) { + return call; + } else if (call !== void 0) { + throw new TypeError("Derived constructors may only return object or undefined"); + } + return _assertThisInitialized(self); + } + function _createSuper(Derived) { + var hasNativeReflectConstruct = _isNativeReflectConstruct(); + return function _createSuperInternal() { + var Super = _getPrototypeOf(Derived), + result; + if (hasNativeReflectConstruct) { + var NewTarget = _getPrototypeOf(this).constructor; + result = Reflect.construct(Super, arguments, NewTarget); + } else { + result = Super.apply(this, arguments); + } + return _possibleConstructorReturn(this, result); + }; + } + function _superPropBase(object, property) { + while (!Object.prototype.hasOwnProperty.call(object, property)) { + object = _getPrototypeOf(object); + if (object === null) break; + } + return object; + } + function _get() { + if (typeof Reflect !== "undefined" && Reflect.get) { + _get = Reflect.get.bind(); + } else { + _get = function _get(target, property, receiver) { + var base = _superPropBase(target, property); + if (!base) return; + var desc = Object.getOwnPropertyDescriptor(base, property); + if (desc.get) { + return desc.get.call(arguments.length < 3 ? target : receiver); + } + return desc.value; + }; + } + return _get.apply(this, arguments); + } + function _slicedToArray(arr, i) { + return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); + } + function _arrayWithHoles(arr) { + if (Array.isArray(arr)) return arr; + } + function _unsupportedIterableToArray(o, minLen) { + if (!o) return; + if (typeof o === "string") return _arrayLikeToArray(o, minLen); + var n = Object.prototype.toString.call(o).slice(8, -1); + if (n === "Object" && o.constructor) n = o.constructor.name; + if (n === "Map" || n === "Set") return Array.from(o); + if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); + } + function _arrayLikeToArray(arr, len) { + if (len == null || len > arr.length) len = arr.length; + for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; + return arr2; + } + function _nonIterableRest() { + throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); + } + function _createForOfIteratorHelper(o, allowArrayLike) { + var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; + if (!it) { + if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { + if (it) o = it; + var i = 0; + var F = function () {}; + return { + s: F, + n: function () { + if (i >= o.length) return { + done: true + }; + return { + done: false, + value: o[i++] + }; + }, + e: function (e) { + throw e; + }, + f: F + }; + } + throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); + } + var normalCompletion = true, + didErr = false, + err; + return { + s: function () { + it = it.call(o); + }, + n: function () { + var step = it.next(); + normalCompletion = step.done; + return step; + }, + e: function (e) { + didErr = true; + err = e; + }, + f: function () { + try { + if (!normalCompletion && it.return != null) it.return(); + } finally { + if (didErr) throw err; + } + } + }; + } + function _toPrimitive(input, hint) { + if (typeof input !== "object" || input === null) return input; + var prim = input[Symbol.toPrimitive]; + if (prim !== undefined) { + var res = prim.call(input, hint || "default"); + if (typeof res !== "object") return res; + throw new TypeError("@@toPrimitive must return a primitive value."); + } + return (hint === "string" ? String : Number)(input); + } + function _toPropertyKey(arg) { + var key = _toPrimitive(arg, "string"); + return typeof key === "symbol" ? key : String(key); + } + function _classPrivateMethodGet(receiver, privateSet, fn) { + if (!privateSet.has(receiver)) { + throw new TypeError("attempted to get private field on non-instance"); + } + return fn; + } + function _checkPrivateRedeclaration(obj, privateCollection) { + if (privateCollection.has(obj)) { + throw new TypeError("Cannot initialize the same private elements twice on an object"); + } + } + function _classPrivateMethodInitSpec(obj, privateSet) { + _checkPrivateRedeclaration(obj, privateSet); + privateSet.add(obj); + } + + /* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ + /* eslint-env node */ + + let logDisabled_ = true; + let deprecationWarnings_ = true; + + /** + * Extract browser version out of the provided user agent string. + * + * @param {!string} uastring userAgent string. + * @param {!string} expr Regular expression used as match criteria. + * @param {!number} pos position in the version string to be returned. + * @return {!number} browser version. + */ + function extractVersion(uastring, expr, pos) { + const match = uastring.match(expr); + return match && match.length >= pos && parseInt(match[pos], 10); + } + + // Wraps the peerconnection event eventNameToWrap in a function + // which returns the modified event object (or false to prevent + // the event). + function wrapPeerConnectionEvent(window, eventNameToWrap, wrapper) { + if (!window.RTCPeerConnection) { + return; + } + const proto = window.RTCPeerConnection.prototype; + const nativeAddEventListener = proto.addEventListener; + proto.addEventListener = function (nativeEventName, cb) { + if (nativeEventName !== eventNameToWrap) { + return nativeAddEventListener.apply(this, arguments); + } + const wrappedCallback = e => { + const modifiedEvent = wrapper(e); + if (modifiedEvent) { + if (cb.handleEvent) { + cb.handleEvent(modifiedEvent); + } else { + cb(modifiedEvent); + } + } + }; + this._eventMap = this._eventMap || {}; + if (!this._eventMap[eventNameToWrap]) { + this._eventMap[eventNameToWrap] = new Map(); + } + this._eventMap[eventNameToWrap].set(cb, wrappedCallback); + return nativeAddEventListener.apply(this, [nativeEventName, wrappedCallback]); + }; + const nativeRemoveEventListener = proto.removeEventListener; + proto.removeEventListener = function (nativeEventName, cb) { + if (nativeEventName !== eventNameToWrap || !this._eventMap || !this._eventMap[eventNameToWrap]) { + return nativeRemoveEventListener.apply(this, arguments); + } + if (!this._eventMap[eventNameToWrap].has(cb)) { + return nativeRemoveEventListener.apply(this, arguments); + } + const unwrappedCb = this._eventMap[eventNameToWrap].get(cb); + this._eventMap[eventNameToWrap].delete(cb); + if (this._eventMap[eventNameToWrap].size === 0) { + delete this._eventMap[eventNameToWrap]; + } + if (Object.keys(this._eventMap).length === 0) { + delete this._eventMap; + } + return nativeRemoveEventListener.apply(this, [nativeEventName, unwrappedCb]); + }; + Object.defineProperty(proto, 'on' + eventNameToWrap, { + get() { + return this['_on' + eventNameToWrap]; + }, + set(cb) { + if (this['_on' + eventNameToWrap]) { + this.removeEventListener(eventNameToWrap, this['_on' + eventNameToWrap]); + delete this['_on' + eventNameToWrap]; + } + if (cb) { + this.addEventListener(eventNameToWrap, this['_on' + eventNameToWrap] = cb); + } + }, + enumerable: true, + configurable: true + }); + } + function disableLog(bool) { + if (typeof bool !== 'boolean') { + return new Error('Argument type: ' + typeof bool + '. Please use a boolean.'); + } + logDisabled_ = bool; + return bool ? 'adapter.js logging disabled' : 'adapter.js logging enabled'; + } + + /** + * Disable or enable deprecation warnings + * @param {!boolean} bool set to true to disable warnings. + */ + function disableWarnings(bool) { + if (typeof bool !== 'boolean') { + return new Error('Argument type: ' + typeof bool + '. Please use a boolean.'); + } + deprecationWarnings_ = !bool; + return 'adapter.js deprecation warnings ' + (bool ? 'disabled' : 'enabled'); + } + function log() { + if (typeof window === 'object') { + if (logDisabled_) { + return; + } + if (typeof console !== 'undefined' && typeof console.log === 'function') { + console.log.apply(console, arguments); + } + } + } + + /** + * Shows a deprecation warning suggesting the modern and spec-compatible API. + */ + function deprecated(oldMethod, newMethod) { + if (!deprecationWarnings_) { + return; + } + console.warn(oldMethod + ' is deprecated, please use ' + newMethod + ' instead.'); + } + + /** + * Browser detector. + * + * @return {object} result containing browser and version + * properties. + */ + function detectBrowser(window) { + // Returned result object. + const result = { + browser: null, + version: null + }; + + // Fail early if it's not a browser + if (typeof window === 'undefined' || !window.navigator || !window.navigator.userAgent) { + result.browser = 'Not a browser.'; + return result; + } + const { + navigator + } = window; + if (navigator.mozGetUserMedia) { + // Firefox. + result.browser = 'firefox'; + result.version = extractVersion(navigator.userAgent, /Firefox\/(\d+)\./, 1); + } else if (navigator.webkitGetUserMedia || window.isSecureContext === false && window.webkitRTCPeerConnection) { + // Chrome, Chromium, Webview, Opera. + // Version matches Chrome/WebRTC version. + // Chrome 74 removed webkitGetUserMedia on http as well so we need the + // more complicated fallback to webkitRTCPeerConnection. + result.browser = 'chrome'; + result.version = extractVersion(navigator.userAgent, /Chrom(e|ium)\/(\d+)\./, 2); + } else if (window.RTCPeerConnection && navigator.userAgent.match(/AppleWebKit\/(\d+)\./)) { + // Safari. + result.browser = 'safari'; + result.version = extractVersion(navigator.userAgent, /AppleWebKit\/(\d+)\./, 1); + result.supportsUnifiedPlan = window.RTCRtpTransceiver && 'currentDirection' in window.RTCRtpTransceiver.prototype; + } else { + // Default fallthrough: not supported. + result.browser = 'Not a supported browser.'; + return result; + } + return result; + } + + /** + * Checks if something is an object. + * + * @param {*} val The something you want to check. + * @return true if val is an object, false otherwise. + */ + function isObject$1(val) { + return Object.prototype.toString.call(val) === '[object Object]'; + } + + /** + * Remove all empty objects and undefined values + * from a nested object -- an enhanced and vanilla version + * of Lodash's `compact`. + */ + function compactObject(data) { + if (!isObject$1(data)) { + return data; + } + return Object.keys(data).reduce(function (accumulator, key) { + const isObj = isObject$1(data[key]); + const value = isObj ? compactObject(data[key]) : data[key]; + const isEmptyObject = isObj && !Object.keys(value).length; + if (value === undefined || isEmptyObject) { + return accumulator; + } + return Object.assign(accumulator, { + [key]: value + }); + }, {}); + } + + /* iterates the stats graph recursively. */ + function walkStats(stats, base, resultSet) { + if (!base || resultSet.has(base.id)) { + return; + } + resultSet.set(base.id, base); + Object.keys(base).forEach(name => { + if (name.endsWith('Id')) { + walkStats(stats, stats.get(base[name]), resultSet); + } else if (name.endsWith('Ids')) { + base[name].forEach(id => { + walkStats(stats, stats.get(id), resultSet); + }); + } + }); + } + + /* filter getStats for a sender/receiver track. */ + function filterStats(result, track, outbound) { + const streamStatsType = outbound ? 'outbound-rtp' : 'inbound-rtp'; + const filteredResult = new Map(); + if (track === null) { + return filteredResult; + } + const trackStats = []; + result.forEach(value => { + if (value.type === 'track' && value.trackIdentifier === track.id) { + trackStats.push(value); + } + }); + trackStats.forEach(trackStat => { + result.forEach(stats => { + if (stats.type === streamStatsType && stats.trackId === trackStat.id) { + walkStats(result, stats, filteredResult); + } + }); + }); + return filteredResult; + } + + /* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ + /* eslint-env node */ + const logging = log; + function shimGetUserMedia$2(window, browserDetails) { + const navigator = window && window.navigator; + if (!navigator.mediaDevices) { + return; + } + const constraintsToChrome_ = function (c) { + if (typeof c !== 'object' || c.mandatory || c.optional) { + return c; + } + const cc = {}; + Object.keys(c).forEach(key => { + if (key === 'require' || key === 'advanced' || key === 'mediaSource') { + return; + } + const r = typeof c[key] === 'object' ? c[key] : { + ideal: c[key] + }; + if (r.exact !== undefined && typeof r.exact === 'number') { + r.min = r.max = r.exact; + } + const oldname_ = function (prefix, name) { + if (prefix) { + return prefix + name.charAt(0).toUpperCase() + name.slice(1); + } + return name === 'deviceId' ? 'sourceId' : name; + }; + if (r.ideal !== undefined) { + cc.optional = cc.optional || []; + let oc = {}; + if (typeof r.ideal === 'number') { + oc[oldname_('min', key)] = r.ideal; + cc.optional.push(oc); + oc = {}; + oc[oldname_('max', key)] = r.ideal; + cc.optional.push(oc); + } else { + oc[oldname_('', key)] = r.ideal; + cc.optional.push(oc); + } + } + if (r.exact !== undefined && typeof r.exact !== 'number') { + cc.mandatory = cc.mandatory || {}; + cc.mandatory[oldname_('', key)] = r.exact; + } else { + ['min', 'max'].forEach(mix => { + if (r[mix] !== undefined) { + cc.mandatory = cc.mandatory || {}; + cc.mandatory[oldname_(mix, key)] = r[mix]; + } + }); + } + }); + if (c.advanced) { + cc.optional = (cc.optional || []).concat(c.advanced); + } + return cc; + }; + const shimConstraints_ = function (constraints, func) { + if (browserDetails.version >= 61) { + return func(constraints); + } + constraints = JSON.parse(JSON.stringify(constraints)); + if (constraints && typeof constraints.audio === 'object') { + const remap = function (obj, a, b) { + if (a in obj && !(b in obj)) { + obj[b] = obj[a]; + delete obj[a]; + } + }; + constraints = JSON.parse(JSON.stringify(constraints)); + remap(constraints.audio, 'autoGainControl', 'googAutoGainControl'); + remap(constraints.audio, 'noiseSuppression', 'googNoiseSuppression'); + constraints.audio = constraintsToChrome_(constraints.audio); + } + if (constraints && typeof constraints.video === 'object') { + // Shim facingMode for mobile & surface pro. + let face = constraints.video.facingMode; + face = face && (typeof face === 'object' ? face : { + ideal: face + }); + const getSupportedFacingModeLies = browserDetails.version < 66; + if (face && (face.exact === 'user' || face.exact === 'environment' || face.ideal === 'user' || face.ideal === 'environment') && !(navigator.mediaDevices.getSupportedConstraints && navigator.mediaDevices.getSupportedConstraints().facingMode && !getSupportedFacingModeLies)) { + delete constraints.video.facingMode; + let matches; + if (face.exact === 'environment' || face.ideal === 'environment') { + matches = ['back', 'rear']; + } else if (face.exact === 'user' || face.ideal === 'user') { + matches = ['front']; + } + if (matches) { + // Look for matches in label, or use last cam for back (typical). + return navigator.mediaDevices.enumerateDevices().then(devices => { + devices = devices.filter(d => d.kind === 'videoinput'); + let dev = devices.find(d => matches.some(match => d.label.toLowerCase().includes(match))); + if (!dev && devices.length && matches.includes('back')) { + dev = devices[devices.length - 1]; // more likely the back cam + } + + if (dev) { + constraints.video.deviceId = face.exact ? { + exact: dev.deviceId + } : { + ideal: dev.deviceId + }; + } + constraints.video = constraintsToChrome_(constraints.video); + logging('chrome: ' + JSON.stringify(constraints)); + return func(constraints); + }); + } + } + constraints.video = constraintsToChrome_(constraints.video); + } + logging('chrome: ' + JSON.stringify(constraints)); + return func(constraints); + }; + const shimError_ = function (e) { + if (browserDetails.version >= 64) { + return e; + } + return { + name: { + PermissionDeniedError: 'NotAllowedError', + PermissionDismissedError: 'NotAllowedError', + InvalidStateError: 'NotAllowedError', + DevicesNotFoundError: 'NotFoundError', + ConstraintNotSatisfiedError: 'OverconstrainedError', + TrackStartError: 'NotReadableError', + MediaDeviceFailedDueToShutdown: 'NotAllowedError', + MediaDeviceKillSwitchOn: 'NotAllowedError', + TabCaptureError: 'AbortError', + ScreenCaptureError: 'AbortError', + DeviceCaptureError: 'AbortError' + }[e.name] || e.name, + message: e.message, + constraint: e.constraint || e.constraintName, + toString() { + return this.name + (this.message && ': ') + this.message; + } + }; + }; + const getUserMedia_ = function (constraints, onSuccess, onError) { + shimConstraints_(constraints, c => { + navigator.webkitGetUserMedia(c, onSuccess, e => { + if (onError) { + onError(shimError_(e)); + } + }); + }); + }; + navigator.getUserMedia = getUserMedia_.bind(navigator); + + // Even though Chrome 45 has navigator.mediaDevices and a getUserMedia + // function which returns a Promise, it does not accept spec-style + // constraints. + if (navigator.mediaDevices.getUserMedia) { + const origGetUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices); + navigator.mediaDevices.getUserMedia = function (cs) { + return shimConstraints_(cs, c => origGetUserMedia(c).then(stream => { + if (c.audio && !stream.getAudioTracks().length || c.video && !stream.getVideoTracks().length) { + stream.getTracks().forEach(track => { + track.stop(); + }); + throw new DOMException('', 'NotFoundError'); + } + return stream; + }, e => Promise.reject(shimError_(e)))); + }; + } + } + + /* + * Copyright (c) 2018 The adapter.js project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ + /* eslint-env node */ + + function shimGetDisplayMedia$1(window, getSourceId) { + if (window.navigator.mediaDevices && 'getDisplayMedia' in window.navigator.mediaDevices) { + return; + } + if (!window.navigator.mediaDevices) { + return; + } + // getSourceId is a function that returns a promise resolving with + // the sourceId of the screen/window/tab to be shared. + if (typeof getSourceId !== 'function') { + console.error('shimGetDisplayMedia: getSourceId argument is not ' + 'a function'); + return; + } + window.navigator.mediaDevices.getDisplayMedia = function getDisplayMedia(constraints) { + return getSourceId(constraints).then(sourceId => { + const widthSpecified = constraints.video && constraints.video.width; + const heightSpecified = constraints.video && constraints.video.height; + const frameRateSpecified = constraints.video && constraints.video.frameRate; + constraints.video = { + mandatory: { + chromeMediaSource: 'desktop', + chromeMediaSourceId: sourceId, + maxFrameRate: frameRateSpecified || 3 + } + }; + if (widthSpecified) { + constraints.video.mandatory.maxWidth = widthSpecified; + } + if (heightSpecified) { + constraints.video.mandatory.maxHeight = heightSpecified; + } + return window.navigator.mediaDevices.getUserMedia(constraints); + }); + }; + } + + /* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ + /* eslint-env node */ + function shimMediaStream(window) { + window.MediaStream = window.MediaStream || window.webkitMediaStream; + } + function shimOnTrack$1(window) { + if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in window.RTCPeerConnection.prototype)) { + Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', { + get() { + return this._ontrack; + }, + set(f) { + if (this._ontrack) { + this.removeEventListener('track', this._ontrack); + } + this.addEventListener('track', this._ontrack = f); + }, + enumerable: true, + configurable: true + }); + const origSetRemoteDescription = window.RTCPeerConnection.prototype.setRemoteDescription; + window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription() { + if (!this._ontrackpoly) { + this._ontrackpoly = e => { + // onaddstream does not fire when a track is added to an existing + // stream. But stream.onaddtrack is implemented so we use that. + e.stream.addEventListener('addtrack', te => { + let receiver; + if (window.RTCPeerConnection.prototype.getReceivers) { + receiver = this.getReceivers().find(r => r.track && r.track.id === te.track.id); + } else { + receiver = { + track: te.track + }; + } + const event = new Event('track'); + event.track = te.track; + event.receiver = receiver; + event.transceiver = { + receiver + }; + event.streams = [e.stream]; + this.dispatchEvent(event); + }); + e.stream.getTracks().forEach(track => { + let receiver; + if (window.RTCPeerConnection.prototype.getReceivers) { + receiver = this.getReceivers().find(r => r.track && r.track.id === track.id); + } else { + receiver = { + track + }; + } + const event = new Event('track'); + event.track = track; + event.receiver = receiver; + event.transceiver = { + receiver + }; + event.streams = [e.stream]; + this.dispatchEvent(event); + }); + }; + this.addEventListener('addstream', this._ontrackpoly); + } + return origSetRemoteDescription.apply(this, arguments); + }; + } else { + // even if RTCRtpTransceiver is in window, it is only used and + // emitted in unified-plan. Unfortunately this means we need + // to unconditionally wrap the event. + wrapPeerConnectionEvent(window, 'track', e => { + if (!e.transceiver) { + Object.defineProperty(e, 'transceiver', { + value: { + receiver: e.receiver + } + }); + } + return e; + }); + } + } + function shimGetSendersWithDtmf(window) { + // Overrides addTrack/removeTrack, depends on shimAddTrackRemoveTrack. + if (typeof window === 'object' && window.RTCPeerConnection && !('getSenders' in window.RTCPeerConnection.prototype) && 'createDTMFSender' in window.RTCPeerConnection.prototype) { + const shimSenderWithDtmf = function (pc, track) { + return { + track, + get dtmf() { + if (this._dtmf === undefined) { + if (track.kind === 'audio') { + this._dtmf = pc.createDTMFSender(track); + } else { + this._dtmf = null; + } + } + return this._dtmf; + }, + _pc: pc + }; + }; + + // augment addTrack when getSenders is not available. + if (!window.RTCPeerConnection.prototype.getSenders) { + window.RTCPeerConnection.prototype.getSenders = function getSenders() { + this._senders = this._senders || []; + return this._senders.slice(); // return a copy of the internal state. + }; + + const origAddTrack = window.RTCPeerConnection.prototype.addTrack; + window.RTCPeerConnection.prototype.addTrack = function addTrack(track, stream) { + let sender = origAddTrack.apply(this, arguments); + if (!sender) { + sender = shimSenderWithDtmf(this, track); + this._senders.push(sender); + } + return sender; + }; + const origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack; + window.RTCPeerConnection.prototype.removeTrack = function removeTrack(sender) { + origRemoveTrack.apply(this, arguments); + const idx = this._senders.indexOf(sender); + if (idx !== -1) { + this._senders.splice(idx, 1); + } + }; + } + const origAddStream = window.RTCPeerConnection.prototype.addStream; + window.RTCPeerConnection.prototype.addStream = function addStream(stream) { + this._senders = this._senders || []; + origAddStream.apply(this, [stream]); + stream.getTracks().forEach(track => { + this._senders.push(shimSenderWithDtmf(this, track)); + }); + }; + const origRemoveStream = window.RTCPeerConnection.prototype.removeStream; + window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { + this._senders = this._senders || []; + origRemoveStream.apply(this, [stream]); + stream.getTracks().forEach(track => { + const sender = this._senders.find(s => s.track === track); + if (sender) { + // remove sender + this._senders.splice(this._senders.indexOf(sender), 1); + } + }); + }; + } else if (typeof window === 'object' && window.RTCPeerConnection && 'getSenders' in window.RTCPeerConnection.prototype && 'createDTMFSender' in window.RTCPeerConnection.prototype && window.RTCRtpSender && !('dtmf' in window.RTCRtpSender.prototype)) { + const origGetSenders = window.RTCPeerConnection.prototype.getSenders; + window.RTCPeerConnection.prototype.getSenders = function getSenders() { + const senders = origGetSenders.apply(this, []); + senders.forEach(sender => sender._pc = this); + return senders; + }; + Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', { + get() { + if (this._dtmf === undefined) { + if (this.track.kind === 'audio') { + this._dtmf = this._pc.createDTMFSender(this.track); + } else { + this._dtmf = null; + } + } + return this._dtmf; + } + }); + } + } + function shimGetStats(window) { + if (!window.RTCPeerConnection) { + return; + } + const origGetStats = window.RTCPeerConnection.prototype.getStats; + window.RTCPeerConnection.prototype.getStats = function getStats() { + const [selector, onSucc, onErr] = arguments; + + // If selector is a function then we are in the old style stats so just + // pass back the original getStats format to avoid breaking old users. + if (arguments.length > 0 && typeof selector === 'function') { + return origGetStats.apply(this, arguments); + } + + // When spec-style getStats is supported, return those when called with + // either no arguments or the selector argument is null. + if (origGetStats.length === 0 && (arguments.length === 0 || typeof selector !== 'function')) { + return origGetStats.apply(this, []); + } + const fixChromeStats_ = function (response) { + const standardReport = {}; + const reports = response.result(); + reports.forEach(report => { + const standardStats = { + id: report.id, + timestamp: report.timestamp, + type: { + localcandidate: 'local-candidate', + remotecandidate: 'remote-candidate' + }[report.type] || report.type + }; + report.names().forEach(name => { + standardStats[name] = report.stat(name); + }); + standardReport[standardStats.id] = standardStats; + }); + return standardReport; + }; + + // shim getStats with maplike support + const makeMapStats = function (stats) { + return new Map(Object.keys(stats).map(key => [key, stats[key]])); + }; + if (arguments.length >= 2) { + const successCallbackWrapper_ = function (response) { + onSucc(makeMapStats(fixChromeStats_(response))); + }; + return origGetStats.apply(this, [successCallbackWrapper_, selector]); + } + + // promise-support + return new Promise((resolve, reject) => { + origGetStats.apply(this, [function (response) { + resolve(makeMapStats(fixChromeStats_(response))); + }, reject]); + }).then(onSucc, onErr); + }; + } + function shimSenderReceiverGetStats(window) { + if (!(typeof window === 'object' && window.RTCPeerConnection && window.RTCRtpSender && window.RTCRtpReceiver)) { + return; + } + + // shim sender stats. + if (!('getStats' in window.RTCRtpSender.prototype)) { + const origGetSenders = window.RTCPeerConnection.prototype.getSenders; + if (origGetSenders) { + window.RTCPeerConnection.prototype.getSenders = function getSenders() { + const senders = origGetSenders.apply(this, []); + senders.forEach(sender => sender._pc = this); + return senders; + }; + } + const origAddTrack = window.RTCPeerConnection.prototype.addTrack; + if (origAddTrack) { + window.RTCPeerConnection.prototype.addTrack = function addTrack() { + const sender = origAddTrack.apply(this, arguments); + sender._pc = this; + return sender; + }; + } + window.RTCRtpSender.prototype.getStats = function getStats() { + const sender = this; + return this._pc.getStats().then(result => + /* Note: this will include stats of all senders that + * send a track with the same id as sender.track as + * it is not possible to identify the RTCRtpSender. + */ + filterStats(result, sender.track, true)); + }; + } + + // shim receiver stats. + if (!('getStats' in window.RTCRtpReceiver.prototype)) { + const origGetReceivers = window.RTCPeerConnection.prototype.getReceivers; + if (origGetReceivers) { + window.RTCPeerConnection.prototype.getReceivers = function getReceivers() { + const receivers = origGetReceivers.apply(this, []); + receivers.forEach(receiver => receiver._pc = this); + return receivers; + }; + } + wrapPeerConnectionEvent(window, 'track', e => { + e.receiver._pc = e.srcElement; + return e; + }); + window.RTCRtpReceiver.prototype.getStats = function getStats() { + const receiver = this; + return this._pc.getStats().then(result => filterStats(result, receiver.track, false)); + }; + } + if (!('getStats' in window.RTCRtpSender.prototype && 'getStats' in window.RTCRtpReceiver.prototype)) { + return; + } + + // shim RTCPeerConnection.getStats(track). + const origGetStats = window.RTCPeerConnection.prototype.getStats; + window.RTCPeerConnection.prototype.getStats = function getStats() { + if (arguments.length > 0 && arguments[0] instanceof window.MediaStreamTrack) { + const track = arguments[0]; + let sender; + let receiver; + let err; + this.getSenders().forEach(s => { + if (s.track === track) { + if (sender) { + err = true; + } else { + sender = s; + } + } + }); + this.getReceivers().forEach(r => { + if (r.track === track) { + if (receiver) { + err = true; + } else { + receiver = r; + } + } + return r.track === track; + }); + if (err || sender && receiver) { + return Promise.reject(new DOMException('There are more than one sender or receiver for the track.', 'InvalidAccessError')); + } else if (sender) { + return sender.getStats(); + } else if (receiver) { + return receiver.getStats(); + } + return Promise.reject(new DOMException('There is no sender or receiver for the track.', 'InvalidAccessError')); + } + return origGetStats.apply(this, arguments); + }; + } + function shimAddTrackRemoveTrackWithNative(window) { + // shim addTrack/removeTrack with native variants in order to make + // the interactions with legacy getLocalStreams behave as in other browsers. + // Keeps a mapping stream.id => [stream, rtpsenders...] + window.RTCPeerConnection.prototype.getLocalStreams = function getLocalStreams() { + this._shimmedLocalStreams = this._shimmedLocalStreams || {}; + return Object.keys(this._shimmedLocalStreams).map(streamId => this._shimmedLocalStreams[streamId][0]); + }; + const origAddTrack = window.RTCPeerConnection.prototype.addTrack; + window.RTCPeerConnection.prototype.addTrack = function addTrack(track, stream) { + if (!stream) { + return origAddTrack.apply(this, arguments); + } + this._shimmedLocalStreams = this._shimmedLocalStreams || {}; + const sender = origAddTrack.apply(this, arguments); + if (!this._shimmedLocalStreams[stream.id]) { + this._shimmedLocalStreams[stream.id] = [stream, sender]; + } else if (this._shimmedLocalStreams[stream.id].indexOf(sender) === -1) { + this._shimmedLocalStreams[stream.id].push(sender); + } + return sender; + }; + const origAddStream = window.RTCPeerConnection.prototype.addStream; + window.RTCPeerConnection.prototype.addStream = function addStream(stream) { + this._shimmedLocalStreams = this._shimmedLocalStreams || {}; + stream.getTracks().forEach(track => { + const alreadyExists = this.getSenders().find(s => s.track === track); + if (alreadyExists) { + throw new DOMException('Track already exists.', 'InvalidAccessError'); + } + }); + const existingSenders = this.getSenders(); + origAddStream.apply(this, arguments); + const newSenders = this.getSenders().filter(newSender => existingSenders.indexOf(newSender) === -1); + this._shimmedLocalStreams[stream.id] = [stream].concat(newSenders); + }; + const origRemoveStream = window.RTCPeerConnection.prototype.removeStream; + window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { + this._shimmedLocalStreams = this._shimmedLocalStreams || {}; + delete this._shimmedLocalStreams[stream.id]; + return origRemoveStream.apply(this, arguments); + }; + const origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack; + window.RTCPeerConnection.prototype.removeTrack = function removeTrack(sender) { + this._shimmedLocalStreams = this._shimmedLocalStreams || {}; + if (sender) { + Object.keys(this._shimmedLocalStreams).forEach(streamId => { + const idx = this._shimmedLocalStreams[streamId].indexOf(sender); + if (idx !== -1) { + this._shimmedLocalStreams[streamId].splice(idx, 1); + } + if (this._shimmedLocalStreams[streamId].length === 1) { + delete this._shimmedLocalStreams[streamId]; + } + }); + } + return origRemoveTrack.apply(this, arguments); + }; + } + function shimAddTrackRemoveTrack(window, browserDetails) { + if (!window.RTCPeerConnection) { + return; + } + // shim addTrack and removeTrack. + if (window.RTCPeerConnection.prototype.addTrack && browserDetails.version >= 65) { + return shimAddTrackRemoveTrackWithNative(window); + } + + // also shim pc.getLocalStreams when addTrack is shimmed + // to return the original streams. + const origGetLocalStreams = window.RTCPeerConnection.prototype.getLocalStreams; + window.RTCPeerConnection.prototype.getLocalStreams = function getLocalStreams() { + const nativeStreams = origGetLocalStreams.apply(this); + this._reverseStreams = this._reverseStreams || {}; + return nativeStreams.map(stream => this._reverseStreams[stream.id]); + }; + const origAddStream = window.RTCPeerConnection.prototype.addStream; + window.RTCPeerConnection.prototype.addStream = function addStream(stream) { + this._streams = this._streams || {}; + this._reverseStreams = this._reverseStreams || {}; + stream.getTracks().forEach(track => { + const alreadyExists = this.getSenders().find(s => s.track === track); + if (alreadyExists) { + throw new DOMException('Track already exists.', 'InvalidAccessError'); + } + }); + // Add identity mapping for consistency with addTrack. + // Unless this is being used with a stream from addTrack. + if (!this._reverseStreams[stream.id]) { + const newStream = new window.MediaStream(stream.getTracks()); + this._streams[stream.id] = newStream; + this._reverseStreams[newStream.id] = stream; + stream = newStream; + } + origAddStream.apply(this, [stream]); + }; + const origRemoveStream = window.RTCPeerConnection.prototype.removeStream; + window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { + this._streams = this._streams || {}; + this._reverseStreams = this._reverseStreams || {}; + origRemoveStream.apply(this, [this._streams[stream.id] || stream]); + delete this._reverseStreams[this._streams[stream.id] ? this._streams[stream.id].id : stream.id]; + delete this._streams[stream.id]; + }; + window.RTCPeerConnection.prototype.addTrack = function addTrack(track, stream) { + if (this.signalingState === 'closed') { + throw new DOMException('The RTCPeerConnection\'s signalingState is \'closed\'.', 'InvalidStateError'); + } + const streams = [].slice.call(arguments, 1); + if (streams.length !== 1 || !streams[0].getTracks().find(t => t === track)) { + // this is not fully correct but all we can manage without + // [[associated MediaStreams]] internal slot. + throw new DOMException('The adapter.js addTrack polyfill only supports a single ' + ' stream which is associated with the specified track.', 'NotSupportedError'); + } + const alreadyExists = this.getSenders().find(s => s.track === track); + if (alreadyExists) { + throw new DOMException('Track already exists.', 'InvalidAccessError'); + } + this._streams = this._streams || {}; + this._reverseStreams = this._reverseStreams || {}; + const oldStream = this._streams[stream.id]; + if (oldStream) { + // this is using odd Chrome behaviour, use with caution: + // https://bugs.chromium.org/p/webrtc/issues/detail?id=7815 + // Note: we rely on the high-level addTrack/dtmf shim to + // create the sender with a dtmf sender. + oldStream.addTrack(track); + + // Trigger ONN async. + Promise.resolve().then(() => { + this.dispatchEvent(new Event('negotiationneeded')); + }); + } else { + const newStream = new window.MediaStream([track]); + this._streams[stream.id] = newStream; + this._reverseStreams[newStream.id] = stream; + this.addStream(newStream); + } + return this.getSenders().find(s => s.track === track); + }; + + // replace the internal stream id with the external one and + // vice versa. + function replaceInternalStreamId(pc, description) { + let sdp = description.sdp; + Object.keys(pc._reverseStreams || []).forEach(internalId => { + const externalStream = pc._reverseStreams[internalId]; + const internalStream = pc._streams[externalStream.id]; + sdp = sdp.replace(new RegExp(internalStream.id, 'g'), externalStream.id); + }); + return new RTCSessionDescription({ + type: description.type, + sdp + }); + } + function replaceExternalStreamId(pc, description) { + let sdp = description.sdp; + Object.keys(pc._reverseStreams || []).forEach(internalId => { + const externalStream = pc._reverseStreams[internalId]; + const internalStream = pc._streams[externalStream.id]; + sdp = sdp.replace(new RegExp(externalStream.id, 'g'), internalStream.id); + }); + return new RTCSessionDescription({ + type: description.type, + sdp + }); + } + ['createOffer', 'createAnswer'].forEach(function (method) { + const nativeMethod = window.RTCPeerConnection.prototype[method]; + const methodObj = { + [method]() { + const args = arguments; + const isLegacyCall = arguments.length && typeof arguments[0] === 'function'; + if (isLegacyCall) { + return nativeMethod.apply(this, [description => { + const desc = replaceInternalStreamId(this, description); + args[0].apply(null, [desc]); + }, err => { + if (args[1]) { + args[1].apply(null, err); + } + }, arguments[2]]); + } + return nativeMethod.apply(this, arguments).then(description => replaceInternalStreamId(this, description)); + } + }; + window.RTCPeerConnection.prototype[method] = methodObj[method]; + }); + const origSetLocalDescription = window.RTCPeerConnection.prototype.setLocalDescription; + window.RTCPeerConnection.prototype.setLocalDescription = function setLocalDescription() { + if (!arguments.length || !arguments[0].type) { + return origSetLocalDescription.apply(this, arguments); + } + arguments[0] = replaceExternalStreamId(this, arguments[0]); + return origSetLocalDescription.apply(this, arguments); + }; + + // TODO: mangle getStats: https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamstats-streamidentifier + + const origLocalDescription = Object.getOwnPropertyDescriptor(window.RTCPeerConnection.prototype, 'localDescription'); + Object.defineProperty(window.RTCPeerConnection.prototype, 'localDescription', { + get() { + const description = origLocalDescription.get.apply(this); + if (description.type === '') { + return description; + } + return replaceInternalStreamId(this, description); + } + }); + window.RTCPeerConnection.prototype.removeTrack = function removeTrack(sender) { + if (this.signalingState === 'closed') { + throw new DOMException('The RTCPeerConnection\'s signalingState is \'closed\'.', 'InvalidStateError'); + } + // We can not yet check for sender instanceof RTCRtpSender + // since we shim RTPSender. So we check if sender._pc is set. + if (!sender._pc) { + throw new DOMException('Argument 1 of RTCPeerConnection.removeTrack ' + 'does not implement interface RTCRtpSender.', 'TypeError'); + } + const isLocal = sender._pc === this; + if (!isLocal) { + throw new DOMException('Sender was not created by this connection.', 'InvalidAccessError'); + } + + // Search for the native stream the senders track belongs to. + this._streams = this._streams || {}; + let stream; + Object.keys(this._streams).forEach(streamid => { + const hasTrack = this._streams[streamid].getTracks().find(track => sender.track === track); + if (hasTrack) { + stream = this._streams[streamid]; + } + }); + if (stream) { + if (stream.getTracks().length === 1) { + // if this is the last track of the stream, remove the stream. This + // takes care of any shimmed _senders. + this.removeStream(this._reverseStreams[stream.id]); + } else { + // relying on the same odd chrome behaviour as above. + stream.removeTrack(sender.track); + } + this.dispatchEvent(new Event('negotiationneeded')); + } + }; + } + function shimPeerConnection$1(window, browserDetails) { + if (!window.RTCPeerConnection && window.webkitRTCPeerConnection) { + // very basic support for old versions. + window.RTCPeerConnection = window.webkitRTCPeerConnection; + } + if (!window.RTCPeerConnection) { + return; + } + + // shim implicit creation of RTCSessionDescription/RTCIceCandidate + if (browserDetails.version < 53) { + ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'].forEach(function (method) { + const nativeMethod = window.RTCPeerConnection.prototype[method]; + const methodObj = { + [method]() { + arguments[0] = new (method === 'addIceCandidate' ? window.RTCIceCandidate : window.RTCSessionDescription)(arguments[0]); + return nativeMethod.apply(this, arguments); + } + }; + window.RTCPeerConnection.prototype[method] = methodObj[method]; + }); + } + } + + // Attempt to fix ONN in plan-b mode. + function fixNegotiationNeeded(window, browserDetails) { + wrapPeerConnectionEvent(window, 'negotiationneeded', e => { + const pc = e.target; + if (browserDetails.version < 72 || pc.getConfiguration && pc.getConfiguration().sdpSemantics === 'plan-b') { + if (pc.signalingState !== 'stable') { + return; + } + } + return e; + }); + } + + var chromeShim = /*#__PURE__*/Object.freeze({ + __proto__: null, + fixNegotiationNeeded: fixNegotiationNeeded, + shimAddTrackRemoveTrack: shimAddTrackRemoveTrack, + shimAddTrackRemoveTrackWithNative: shimAddTrackRemoveTrackWithNative, + shimGetDisplayMedia: shimGetDisplayMedia$1, + shimGetSendersWithDtmf: shimGetSendersWithDtmf, + shimGetStats: shimGetStats, + shimGetUserMedia: shimGetUserMedia$2, + shimMediaStream: shimMediaStream, + shimOnTrack: shimOnTrack$1, + shimPeerConnection: shimPeerConnection$1, + shimSenderReceiverGetStats: shimSenderReceiverGetStats + }); + + /* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ + /* eslint-env node */ + function shimGetUserMedia$1(window, browserDetails) { + const navigator = window && window.navigator; + const MediaStreamTrack = window && window.MediaStreamTrack; + navigator.getUserMedia = function (constraints, onSuccess, onError) { + // Replace Firefox 44+'s deprecation warning with unprefixed version. + deprecated('navigator.getUserMedia', 'navigator.mediaDevices.getUserMedia'); + navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError); + }; + if (!(browserDetails.version > 55 && 'autoGainControl' in navigator.mediaDevices.getSupportedConstraints())) { + const remap = function (obj, a, b) { + if (a in obj && !(b in obj)) { + obj[b] = obj[a]; + delete obj[a]; + } + }; + const nativeGetUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices); + navigator.mediaDevices.getUserMedia = function (c) { + if (typeof c === 'object' && typeof c.audio === 'object') { + c = JSON.parse(JSON.stringify(c)); + remap(c.audio, 'autoGainControl', 'mozAutoGainControl'); + remap(c.audio, 'noiseSuppression', 'mozNoiseSuppression'); + } + return nativeGetUserMedia(c); + }; + if (MediaStreamTrack && MediaStreamTrack.prototype.getSettings) { + const nativeGetSettings = MediaStreamTrack.prototype.getSettings; + MediaStreamTrack.prototype.getSettings = function () { + const obj = nativeGetSettings.apply(this, arguments); + remap(obj, 'mozAutoGainControl', 'autoGainControl'); + remap(obj, 'mozNoiseSuppression', 'noiseSuppression'); + return obj; + }; + } + if (MediaStreamTrack && MediaStreamTrack.prototype.applyConstraints) { + const nativeApplyConstraints = MediaStreamTrack.prototype.applyConstraints; + MediaStreamTrack.prototype.applyConstraints = function (c) { + if (this.kind === 'audio' && typeof c === 'object') { + c = JSON.parse(JSON.stringify(c)); + remap(c, 'autoGainControl', 'mozAutoGainControl'); + remap(c, 'noiseSuppression', 'mozNoiseSuppression'); + } + return nativeApplyConstraints.apply(this, [c]); + }; + } + } + } + + /* + * Copyright (c) 2018 The adapter.js project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ + /* eslint-env node */ + + function shimGetDisplayMedia(window, preferredMediaSource) { + if (window.navigator.mediaDevices && 'getDisplayMedia' in window.navigator.mediaDevices) { + return; + } + if (!window.navigator.mediaDevices) { + return; + } + window.navigator.mediaDevices.getDisplayMedia = function getDisplayMedia(constraints) { + if (!(constraints && constraints.video)) { + const err = new DOMException('getDisplayMedia without video ' + 'constraints is undefined'); + err.name = 'NotFoundError'; + // from https://heycam.github.io/webidl/#idl-DOMException-error-names + err.code = 8; + return Promise.reject(err); + } + if (constraints.video === true) { + constraints.video = { + mediaSource: preferredMediaSource + }; + } else { + constraints.video.mediaSource = preferredMediaSource; + } + return window.navigator.mediaDevices.getUserMedia(constraints); + }; + } + + /* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ + /* eslint-env node */ + function shimOnTrack(window) { + if (typeof window === 'object' && window.RTCTrackEvent && 'receiver' in window.RTCTrackEvent.prototype && !('transceiver' in window.RTCTrackEvent.prototype)) { + Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', { + get() { + return { + receiver: this.receiver + }; + } + }); + } + } + function shimPeerConnection(window, browserDetails) { + if (typeof window !== 'object' || !(window.RTCPeerConnection || window.mozRTCPeerConnection)) { + return; // probably media.peerconnection.enabled=false in about:config + } + + if (!window.RTCPeerConnection && window.mozRTCPeerConnection) { + // very basic support for old versions. + window.RTCPeerConnection = window.mozRTCPeerConnection; + } + if (browserDetails.version < 53) { + // shim away need for obsolete RTCIceCandidate/RTCSessionDescription. + ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'].forEach(function (method) { + const nativeMethod = window.RTCPeerConnection.prototype[method]; + const methodObj = { + [method]() { + arguments[0] = new (method === 'addIceCandidate' ? window.RTCIceCandidate : window.RTCSessionDescription)(arguments[0]); + return nativeMethod.apply(this, arguments); + } + }; + window.RTCPeerConnection.prototype[method] = methodObj[method]; + }); + } + const modernStatsTypes = { + inboundrtp: 'inbound-rtp', + outboundrtp: 'outbound-rtp', + candidatepair: 'candidate-pair', + localcandidate: 'local-candidate', + remotecandidate: 'remote-candidate' + }; + const nativeGetStats = window.RTCPeerConnection.prototype.getStats; + window.RTCPeerConnection.prototype.getStats = function getStats() { + const [selector, onSucc, onErr] = arguments; + return nativeGetStats.apply(this, [selector || null]).then(stats => { + if (browserDetails.version < 53 && !onSucc) { + // Shim only promise getStats with spec-hyphens in type names + // Leave callback version alone; misc old uses of forEach before Map + try { + stats.forEach(stat => { + stat.type = modernStatsTypes[stat.type] || stat.type; + }); + } catch (e) { + if (e.name !== 'TypeError') { + throw e; + } + // Avoid TypeError: "type" is read-only, in old versions. 34-43ish + stats.forEach((stat, i) => { + stats.set(i, Object.assign({}, stat, { + type: modernStatsTypes[stat.type] || stat.type + })); + }); + } + } + return stats; + }).then(onSucc, onErr); + }; + } + function shimSenderGetStats(window) { + if (!(typeof window === 'object' && window.RTCPeerConnection && window.RTCRtpSender)) { + return; + } + if (window.RTCRtpSender && 'getStats' in window.RTCRtpSender.prototype) { + return; + } + const origGetSenders = window.RTCPeerConnection.prototype.getSenders; + if (origGetSenders) { + window.RTCPeerConnection.prototype.getSenders = function getSenders() { + const senders = origGetSenders.apply(this, []); + senders.forEach(sender => sender._pc = this); + return senders; + }; + } + const origAddTrack = window.RTCPeerConnection.prototype.addTrack; + if (origAddTrack) { + window.RTCPeerConnection.prototype.addTrack = function addTrack() { + const sender = origAddTrack.apply(this, arguments); + sender._pc = this; + return sender; + }; + } + window.RTCRtpSender.prototype.getStats = function getStats() { + return this.track ? this._pc.getStats(this.track) : Promise.resolve(new Map()); + }; + } + function shimReceiverGetStats(window) { + if (!(typeof window === 'object' && window.RTCPeerConnection && window.RTCRtpSender)) { + return; + } + if (window.RTCRtpSender && 'getStats' in window.RTCRtpReceiver.prototype) { + return; + } + const origGetReceivers = window.RTCPeerConnection.prototype.getReceivers; + if (origGetReceivers) { + window.RTCPeerConnection.prototype.getReceivers = function getReceivers() { + const receivers = origGetReceivers.apply(this, []); + receivers.forEach(receiver => receiver._pc = this); + return receivers; + }; + } + wrapPeerConnectionEvent(window, 'track', e => { + e.receiver._pc = e.srcElement; + return e; + }); + window.RTCRtpReceiver.prototype.getStats = function getStats() { + return this._pc.getStats(this.track); + }; + } + function shimRemoveStream(window) { + if (!window.RTCPeerConnection || 'removeStream' in window.RTCPeerConnection.prototype) { + return; + } + window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { + deprecated('removeStream', 'removeTrack'); + this.getSenders().forEach(sender => { + if (sender.track && stream.getTracks().includes(sender.track)) { + this.removeTrack(sender); + } + }); + }; + } + function shimRTCDataChannel(window) { + // rename DataChannel to RTCDataChannel (native fix in FF60): + // https://bugzilla.mozilla.org/show_bug.cgi?id=1173851 + if (window.DataChannel && !window.RTCDataChannel) { + window.RTCDataChannel = window.DataChannel; + } + } + function shimAddTransceiver(window) { + // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647 + // Firefox ignores the init sendEncodings options passed to addTransceiver + // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918 + if (!(typeof window === 'object' && window.RTCPeerConnection)) { + return; + } + const origAddTransceiver = window.RTCPeerConnection.prototype.addTransceiver; + if (origAddTransceiver) { + window.RTCPeerConnection.prototype.addTransceiver = function addTransceiver() { + this.setParametersPromises = []; + // WebIDL input coercion and validation + let sendEncodings = arguments[1] && arguments[1].sendEncodings; + if (sendEncodings === undefined) { + sendEncodings = []; + } + sendEncodings = [...sendEncodings]; + const shouldPerformCheck = sendEncodings.length > 0; + if (shouldPerformCheck) { + // If sendEncodings params are provided, validate grammar + sendEncodings.forEach(encodingParam => { + if ('rid' in encodingParam) { + const ridRegex = /^[a-z0-9]{0,16}$/i; + if (!ridRegex.test(encodingParam.rid)) { + throw new TypeError('Invalid RID value provided.'); + } + } + if ('scaleResolutionDownBy' in encodingParam) { + if (!(parseFloat(encodingParam.scaleResolutionDownBy) >= 1.0)) { + throw new RangeError('scale_resolution_down_by must be >= 1.0'); + } + } + if ('maxFramerate' in encodingParam) { + if (!(parseFloat(encodingParam.maxFramerate) >= 0)) { + throw new RangeError('max_framerate must be >= 0.0'); + } + } + }); + } + const transceiver = origAddTransceiver.apply(this, arguments); + if (shouldPerformCheck) { + // Check if the init options were applied. If not we do this in an + // asynchronous way and save the promise reference in a global object. + // This is an ugly hack, but at the same time is way more robust than + // checking the sender parameters before and after the createOffer + // Also note that after the createoffer we are not 100% sure that + // the params were asynchronously applied so we might miss the + // opportunity to recreate offer. + const { + sender + } = transceiver; + const params = sender.getParameters(); + if (!('encodings' in params) || + // Avoid being fooled by patched getParameters() below. + params.encodings.length === 1 && Object.keys(params.encodings[0]).length === 0) { + params.encodings = sendEncodings; + sender.sendEncodings = sendEncodings; + this.setParametersPromises.push(sender.setParameters(params).then(() => { + delete sender.sendEncodings; + }).catch(() => { + delete sender.sendEncodings; + })); + } + } + return transceiver; + }; + } + } + function shimGetParameters(window) { + if (!(typeof window === 'object' && window.RTCRtpSender)) { + return; + } + const origGetParameters = window.RTCRtpSender.prototype.getParameters; + if (origGetParameters) { + window.RTCRtpSender.prototype.getParameters = function getParameters() { + const params = origGetParameters.apply(this, arguments); + if (!('encodings' in params)) { + params.encodings = [].concat(this.sendEncodings || [{}]); + } + return params; + }; + } + } + function shimCreateOffer(window) { + // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647 + // Firefox ignores the init sendEncodings options passed to addTransceiver + // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918 + if (!(typeof window === 'object' && window.RTCPeerConnection)) { + return; + } + const origCreateOffer = window.RTCPeerConnection.prototype.createOffer; + window.RTCPeerConnection.prototype.createOffer = function createOffer() { + if (this.setParametersPromises && this.setParametersPromises.length) { + return Promise.all(this.setParametersPromises).then(() => { + return origCreateOffer.apply(this, arguments); + }).finally(() => { + this.setParametersPromises = []; + }); + } + return origCreateOffer.apply(this, arguments); + }; + } + function shimCreateAnswer(window) { + // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647 + // Firefox ignores the init sendEncodings options passed to addTransceiver + // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918 + if (!(typeof window === 'object' && window.RTCPeerConnection)) { + return; + } + const origCreateAnswer = window.RTCPeerConnection.prototype.createAnswer; + window.RTCPeerConnection.prototype.createAnswer = function createAnswer() { + if (this.setParametersPromises && this.setParametersPromises.length) { + return Promise.all(this.setParametersPromises).then(() => { + return origCreateAnswer.apply(this, arguments); + }).finally(() => { + this.setParametersPromises = []; + }); + } + return origCreateAnswer.apply(this, arguments); + }; + } + + var firefoxShim = /*#__PURE__*/Object.freeze({ + __proto__: null, + shimAddTransceiver: shimAddTransceiver, + shimCreateAnswer: shimCreateAnswer, + shimCreateOffer: shimCreateOffer, + shimGetDisplayMedia: shimGetDisplayMedia, + shimGetParameters: shimGetParameters, + shimGetUserMedia: shimGetUserMedia$1, + shimOnTrack: shimOnTrack, + shimPeerConnection: shimPeerConnection, + shimRTCDataChannel: shimRTCDataChannel, + shimReceiverGetStats: shimReceiverGetStats, + shimRemoveStream: shimRemoveStream, + shimSenderGetStats: shimSenderGetStats + }); + + /* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ + function shimLocalStreamsAPI(window) { + if (typeof window !== 'object' || !window.RTCPeerConnection) { + return; + } + if (!('getLocalStreams' in window.RTCPeerConnection.prototype)) { + window.RTCPeerConnection.prototype.getLocalStreams = function getLocalStreams() { + if (!this._localStreams) { + this._localStreams = []; + } + return this._localStreams; + }; + } + if (!('addStream' in window.RTCPeerConnection.prototype)) { + const _addTrack = window.RTCPeerConnection.prototype.addTrack; + window.RTCPeerConnection.prototype.addStream = function addStream(stream) { + if (!this._localStreams) { + this._localStreams = []; + } + if (!this._localStreams.includes(stream)) { + this._localStreams.push(stream); + } + // Try to emulate Chrome's behaviour of adding in audio-video order. + // Safari orders by track id. + stream.getAudioTracks().forEach(track => _addTrack.call(this, track, stream)); + stream.getVideoTracks().forEach(track => _addTrack.call(this, track, stream)); + }; + window.RTCPeerConnection.prototype.addTrack = function addTrack(track, ...streams) { + if (streams) { + streams.forEach(stream => { + if (!this._localStreams) { + this._localStreams = [stream]; + } else if (!this._localStreams.includes(stream)) { + this._localStreams.push(stream); + } + }); + } + return _addTrack.apply(this, arguments); + }; + } + if (!('removeStream' in window.RTCPeerConnection.prototype)) { + window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { + if (!this._localStreams) { + this._localStreams = []; + } + const index = this._localStreams.indexOf(stream); + if (index === -1) { + return; + } + this._localStreams.splice(index, 1); + const tracks = stream.getTracks(); + this.getSenders().forEach(sender => { + if (tracks.includes(sender.track)) { + this.removeTrack(sender); + } + }); + }; + } + } + function shimRemoteStreamsAPI(window) { + if (typeof window !== 'object' || !window.RTCPeerConnection) { + return; + } + if (!('getRemoteStreams' in window.RTCPeerConnection.prototype)) { + window.RTCPeerConnection.prototype.getRemoteStreams = function getRemoteStreams() { + return this._remoteStreams ? this._remoteStreams : []; + }; + } + if (!('onaddstream' in window.RTCPeerConnection.prototype)) { + Object.defineProperty(window.RTCPeerConnection.prototype, 'onaddstream', { + get() { + return this._onaddstream; + }, + set(f) { + if (this._onaddstream) { + this.removeEventListener('addstream', this._onaddstream); + this.removeEventListener('track', this._onaddstreampoly); + } + this.addEventListener('addstream', this._onaddstream = f); + this.addEventListener('track', this._onaddstreampoly = e => { + e.streams.forEach(stream => { + if (!this._remoteStreams) { + this._remoteStreams = []; + } + if (this._remoteStreams.includes(stream)) { + return; + } + this._remoteStreams.push(stream); + const event = new Event('addstream'); + event.stream = stream; + this.dispatchEvent(event); + }); + }); + } + }); + const origSetRemoteDescription = window.RTCPeerConnection.prototype.setRemoteDescription; + window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription() { + const pc = this; + if (!this._onaddstreampoly) { + this.addEventListener('track', this._onaddstreampoly = function (e) { + e.streams.forEach(stream => { + if (!pc._remoteStreams) { + pc._remoteStreams = []; + } + if (pc._remoteStreams.indexOf(stream) >= 0) { + return; + } + pc._remoteStreams.push(stream); + const event = new Event('addstream'); + event.stream = stream; + pc.dispatchEvent(event); + }); + }); + } + return origSetRemoteDescription.apply(pc, arguments); + }; + } + } + function shimCallbacksAPI(window) { + if (typeof window !== 'object' || !window.RTCPeerConnection) { + return; + } + const prototype = window.RTCPeerConnection.prototype; + const origCreateOffer = prototype.createOffer; + const origCreateAnswer = prototype.createAnswer; + const setLocalDescription = prototype.setLocalDescription; + const setRemoteDescription = prototype.setRemoteDescription; + const addIceCandidate = prototype.addIceCandidate; + prototype.createOffer = function createOffer(successCallback, failureCallback) { + const options = arguments.length >= 2 ? arguments[2] : arguments[0]; + const promise = origCreateOffer.apply(this, [options]); + if (!failureCallback) { + return promise; + } + promise.then(successCallback, failureCallback); + return Promise.resolve(); + }; + prototype.createAnswer = function createAnswer(successCallback, failureCallback) { + const options = arguments.length >= 2 ? arguments[2] : arguments[0]; + const promise = origCreateAnswer.apply(this, [options]); + if (!failureCallback) { + return promise; + } + promise.then(successCallback, failureCallback); + return Promise.resolve(); + }; + let withCallback = function (description, successCallback, failureCallback) { + const promise = setLocalDescription.apply(this, [description]); + if (!failureCallback) { + return promise; + } + promise.then(successCallback, failureCallback); + return Promise.resolve(); + }; + prototype.setLocalDescription = withCallback; + withCallback = function (description, successCallback, failureCallback) { + const promise = setRemoteDescription.apply(this, [description]); + if (!failureCallback) { + return promise; + } + promise.then(successCallback, failureCallback); + return Promise.resolve(); + }; + prototype.setRemoteDescription = withCallback; + withCallback = function (candidate, successCallback, failureCallback) { + const promise = addIceCandidate.apply(this, [candidate]); + if (!failureCallback) { + return promise; + } + promise.then(successCallback, failureCallback); + return Promise.resolve(); + }; + prototype.addIceCandidate = withCallback; + } + function shimGetUserMedia(window) { + const navigator = window && window.navigator; + if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { + // shim not needed in Safari 12.1 + const mediaDevices = navigator.mediaDevices; + const _getUserMedia = mediaDevices.getUserMedia.bind(mediaDevices); + navigator.mediaDevices.getUserMedia = constraints => { + return _getUserMedia(shimConstraints(constraints)); + }; + } + if (!navigator.getUserMedia && navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { + navigator.getUserMedia = function getUserMedia(constraints, cb, errcb) { + navigator.mediaDevices.getUserMedia(constraints).then(cb, errcb); + }.bind(navigator); + } + } + function shimConstraints(constraints) { + if (constraints && constraints.video !== undefined) { + return Object.assign({}, constraints, { + video: compactObject(constraints.video) + }); + } + return constraints; + } + function shimRTCIceServerUrls(window) { + if (!window.RTCPeerConnection) { + return; + } + // migrate from non-spec RTCIceServer.url to RTCIceServer.urls + const OrigPeerConnection = window.RTCPeerConnection; + window.RTCPeerConnection = function RTCPeerConnection(pcConfig, pcConstraints) { + if (pcConfig && pcConfig.iceServers) { + const newIceServers = []; + for (let i = 0; i < pcConfig.iceServers.length; i++) { + let server = pcConfig.iceServers[i]; + if (server.urls === undefined && server.url) { + deprecated('RTCIceServer.url', 'RTCIceServer.urls'); + server = JSON.parse(JSON.stringify(server)); + server.urls = server.url; + delete server.url; + newIceServers.push(server); + } else { + newIceServers.push(pcConfig.iceServers[i]); + } + } + pcConfig.iceServers = newIceServers; + } + return new OrigPeerConnection(pcConfig, pcConstraints); + }; + window.RTCPeerConnection.prototype = OrigPeerConnection.prototype; + // wrap static methods. Currently just generateCertificate. + if ('generateCertificate' in OrigPeerConnection) { + Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { + get() { + return OrigPeerConnection.generateCertificate; + } + }); + } + } + function shimTrackEventTransceiver(window) { + // Add event.transceiver member over deprecated event.receiver + if (typeof window === 'object' && window.RTCTrackEvent && 'receiver' in window.RTCTrackEvent.prototype && !('transceiver' in window.RTCTrackEvent.prototype)) { + Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', { + get() { + return { + receiver: this.receiver + }; + } + }); + } + } + function shimCreateOfferLegacy(window) { + const origCreateOffer = window.RTCPeerConnection.prototype.createOffer; + window.RTCPeerConnection.prototype.createOffer = function createOffer(offerOptions) { + if (offerOptions) { + if (typeof offerOptions.offerToReceiveAudio !== 'undefined') { + // support bit values + offerOptions.offerToReceiveAudio = !!offerOptions.offerToReceiveAudio; + } + const audioTransceiver = this.getTransceivers().find(transceiver => transceiver.receiver.track.kind === 'audio'); + if (offerOptions.offerToReceiveAudio === false && audioTransceiver) { + if (audioTransceiver.direction === 'sendrecv') { + if (audioTransceiver.setDirection) { + audioTransceiver.setDirection('sendonly'); + } else { + audioTransceiver.direction = 'sendonly'; + } + } else if (audioTransceiver.direction === 'recvonly') { + if (audioTransceiver.setDirection) { + audioTransceiver.setDirection('inactive'); + } else { + audioTransceiver.direction = 'inactive'; + } + } + } else if (offerOptions.offerToReceiveAudio === true && !audioTransceiver) { + this.addTransceiver('audio', { + direction: 'recvonly' + }); + } + if (typeof offerOptions.offerToReceiveVideo !== 'undefined') { + // support bit values + offerOptions.offerToReceiveVideo = !!offerOptions.offerToReceiveVideo; + } + const videoTransceiver = this.getTransceivers().find(transceiver => transceiver.receiver.track.kind === 'video'); + if (offerOptions.offerToReceiveVideo === false && videoTransceiver) { + if (videoTransceiver.direction === 'sendrecv') { + if (videoTransceiver.setDirection) { + videoTransceiver.setDirection('sendonly'); + } else { + videoTransceiver.direction = 'sendonly'; + } + } else if (videoTransceiver.direction === 'recvonly') { + if (videoTransceiver.setDirection) { + videoTransceiver.setDirection('inactive'); + } else { + videoTransceiver.direction = 'inactive'; + } + } + } else if (offerOptions.offerToReceiveVideo === true && !videoTransceiver) { + this.addTransceiver('video', { + direction: 'recvonly' + }); + } + } + return origCreateOffer.apply(this, arguments); + }; + } + function shimAudioContext(window) { + if (typeof window !== 'object' || window.AudioContext) { + return; + } + window.AudioContext = window.webkitAudioContext; + } + + var safariShim = /*#__PURE__*/Object.freeze({ + __proto__: null, + shimAudioContext: shimAudioContext, + shimCallbacksAPI: shimCallbacksAPI, + shimConstraints: shimConstraints, + shimCreateOfferLegacy: shimCreateOfferLegacy, + shimGetUserMedia: shimGetUserMedia, + shimLocalStreamsAPI: shimLocalStreamsAPI, + shimRTCIceServerUrls: shimRTCIceServerUrls, + shimRemoteStreamsAPI: shimRemoteStreamsAPI, + shimTrackEventTransceiver: shimTrackEventTransceiver + }); + + var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; + + function getDefaultExportFromCjs (x) { + return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; + } + + var sdp$1 = {exports: {}}; + + /* eslint-env node */ + (function (module) { + + // SDP helpers. + const SDPUtils = {}; + + // Generate an alphanumeric identifier for cname or mids. + // TODO: use UUIDs instead? https://gist.github.com/jed/982883 + SDPUtils.generateIdentifier = function () { + return Math.random().toString(36).substring(2, 12); + }; + + // The RTCP CNAME used by all peerconnections from the same JS. + SDPUtils.localCName = SDPUtils.generateIdentifier(); + + // Splits SDP into lines, dealing with both CRLF and LF. + SDPUtils.splitLines = function (blob) { + return blob.trim().split('\n').map(line => line.trim()); + }; + // Splits SDP into sessionpart and mediasections. Ensures CRLF. + SDPUtils.splitSections = function (blob) { + const parts = blob.split('\nm='); + return parts.map((part, index) => (index > 0 ? 'm=' + part : part).trim() + '\r\n'); + }; + + // Returns the session description. + SDPUtils.getDescription = function (blob) { + const sections = SDPUtils.splitSections(blob); + return sections && sections[0]; + }; + + // Returns the individual media sections. + SDPUtils.getMediaSections = function (blob) { + const sections = SDPUtils.splitSections(blob); + sections.shift(); + return sections; + }; + + // Returns lines that start with a certain prefix. + SDPUtils.matchPrefix = function (blob, prefix) { + return SDPUtils.splitLines(blob).filter(line => line.indexOf(prefix) === 0); + }; + + // Parses an ICE candidate line. Sample input: + // candidate:702786350 2 udp 41819902 8.8.8.8 60769 typ relay raddr 8.8.8.8 + // rport 55996" + // Input can be prefixed with a=. + SDPUtils.parseCandidate = function (line) { + let parts; + // Parse both variants. + if (line.indexOf('a=candidate:') === 0) { + parts = line.substring(12).split(' '); + } else { + parts = line.substring(10).split(' '); + } + const candidate = { + foundation: parts[0], + component: { + 1: 'rtp', + 2: 'rtcp' + }[parts[1]] || parts[1], + protocol: parts[2].toLowerCase(), + priority: parseInt(parts[3], 10), + ip: parts[4], + address: parts[4], + // address is an alias for ip. + port: parseInt(parts[5], 10), + // skip parts[6] == 'typ' + type: parts[7] + }; + for (let i = 8; i < parts.length; i += 2) { + switch (parts[i]) { + case 'raddr': + candidate.relatedAddress = parts[i + 1]; + break; + case 'rport': + candidate.relatedPort = parseInt(parts[i + 1], 10); + break; + case 'tcptype': + candidate.tcpType = parts[i + 1]; + break; + case 'ufrag': + candidate.ufrag = parts[i + 1]; // for backward compatibility. + candidate.usernameFragment = parts[i + 1]; + break; + default: + // extension handling, in particular ufrag. Don't overwrite. + if (candidate[parts[i]] === undefined) { + candidate[parts[i]] = parts[i + 1]; + } + break; + } + } + return candidate; + }; + + // Translates a candidate object into SDP candidate attribute. + // This does not include the a= prefix! + SDPUtils.writeCandidate = function (candidate) { + const sdp = []; + sdp.push(candidate.foundation); + const component = candidate.component; + if (component === 'rtp') { + sdp.push(1); + } else if (component === 'rtcp') { + sdp.push(2); + } else { + sdp.push(component); + } + sdp.push(candidate.protocol.toUpperCase()); + sdp.push(candidate.priority); + sdp.push(candidate.address || candidate.ip); + sdp.push(candidate.port); + const type = candidate.type; + sdp.push('typ'); + sdp.push(type); + if (type !== 'host' && candidate.relatedAddress && candidate.relatedPort) { + sdp.push('raddr'); + sdp.push(candidate.relatedAddress); + sdp.push('rport'); + sdp.push(candidate.relatedPort); + } + if (candidate.tcpType && candidate.protocol.toLowerCase() === 'tcp') { + sdp.push('tcptype'); + sdp.push(candidate.tcpType); + } + if (candidate.usernameFragment || candidate.ufrag) { + sdp.push('ufrag'); + sdp.push(candidate.usernameFragment || candidate.ufrag); + } + return 'candidate:' + sdp.join(' '); + }; + + // Parses an ice-options line, returns an array of option tags. + // Sample input: + // a=ice-options:foo bar + SDPUtils.parseIceOptions = function (line) { + return line.substring(14).split(' '); + }; + + // Parses a rtpmap line, returns RTCRtpCoddecParameters. Sample input: + // a=rtpmap:111 opus/48000/2 + SDPUtils.parseRtpMap = function (line) { + let parts = line.substring(9).split(' '); + const parsed = { + payloadType: parseInt(parts.shift(), 10) // was: id + }; + + parts = parts[0].split('/'); + parsed.name = parts[0]; + parsed.clockRate = parseInt(parts[1], 10); // was: clockrate + parsed.channels = parts.length === 3 ? parseInt(parts[2], 10) : 1; + // legacy alias, got renamed back to channels in ORTC. + parsed.numChannels = parsed.channels; + return parsed; + }; + + // Generates a rtpmap line from RTCRtpCodecCapability or + // RTCRtpCodecParameters. + SDPUtils.writeRtpMap = function (codec) { + let pt = codec.payloadType; + if (codec.preferredPayloadType !== undefined) { + pt = codec.preferredPayloadType; + } + const channels = codec.channels || codec.numChannels || 1; + return 'a=rtpmap:' + pt + ' ' + codec.name + '/' + codec.clockRate + (channels !== 1 ? '/' + channels : '') + '\r\n'; + }; + + // Parses a extmap line (headerextension from RFC 5285). Sample input: + // a=extmap:2 urn:ietf:params:rtp-hdrext:toffset + // a=extmap:2/sendonly urn:ietf:params:rtp-hdrext:toffset + SDPUtils.parseExtmap = function (line) { + const parts = line.substring(9).split(' '); + return { + id: parseInt(parts[0], 10), + direction: parts[0].indexOf('/') > 0 ? parts[0].split('/')[1] : 'sendrecv', + uri: parts[1], + attributes: parts.slice(2).join(' ') + }; + }; + + // Generates an extmap line from RTCRtpHeaderExtensionParameters or + // RTCRtpHeaderExtension. + SDPUtils.writeExtmap = function (headerExtension) { + return 'a=extmap:' + (headerExtension.id || headerExtension.preferredId) + (headerExtension.direction && headerExtension.direction !== 'sendrecv' ? '/' + headerExtension.direction : '') + ' ' + headerExtension.uri + (headerExtension.attributes ? ' ' + headerExtension.attributes : '') + '\r\n'; + }; + + // Parses a fmtp line, returns dictionary. Sample input: + // a=fmtp:96 vbr=on;cng=on + // Also deals with vbr=on; cng=on + SDPUtils.parseFmtp = function (line) { + const parsed = {}; + let kv; + const parts = line.substring(line.indexOf(' ') + 1).split(';'); + for (let j = 0; j < parts.length; j++) { + kv = parts[j].trim().split('='); + parsed[kv[0].trim()] = kv[1]; + } + return parsed; + }; + + // Generates a fmtp line from RTCRtpCodecCapability or RTCRtpCodecParameters. + SDPUtils.writeFmtp = function (codec) { + let line = ''; + let pt = codec.payloadType; + if (codec.preferredPayloadType !== undefined) { + pt = codec.preferredPayloadType; + } + if (codec.parameters && Object.keys(codec.parameters).length) { + const params = []; + Object.keys(codec.parameters).forEach(param => { + if (codec.parameters[param] !== undefined) { + params.push(param + '=' + codec.parameters[param]); + } else { + params.push(param); + } + }); + line += 'a=fmtp:' + pt + ' ' + params.join(';') + '\r\n'; + } + return line; + }; + + // Parses a rtcp-fb line, returns RTCPRtcpFeedback object. Sample input: + // a=rtcp-fb:98 nack rpsi + SDPUtils.parseRtcpFb = function (line) { + const parts = line.substring(line.indexOf(' ') + 1).split(' '); + return { + type: parts.shift(), + parameter: parts.join(' ') + }; + }; + + // Generate a=rtcp-fb lines from RTCRtpCodecCapability or RTCRtpCodecParameters. + SDPUtils.writeRtcpFb = function (codec) { + let lines = ''; + let pt = codec.payloadType; + if (codec.preferredPayloadType !== undefined) { + pt = codec.preferredPayloadType; + } + if (codec.rtcpFeedback && codec.rtcpFeedback.length) { + // FIXME: special handling for trr-int? + codec.rtcpFeedback.forEach(fb => { + lines += 'a=rtcp-fb:' + pt + ' ' + fb.type + (fb.parameter && fb.parameter.length ? ' ' + fb.parameter : '') + '\r\n'; + }); + } + return lines; + }; + + // Parses a RFC 5576 ssrc media attribute. Sample input: + // a=ssrc:3735928559 cname:something + SDPUtils.parseSsrcMedia = function (line) { + const sp = line.indexOf(' '); + const parts = { + ssrc: parseInt(line.substring(7, sp), 10) + }; + const colon = line.indexOf(':', sp); + if (colon > -1) { + parts.attribute = line.substring(sp + 1, colon); + parts.value = line.substring(colon + 1); + } else { + parts.attribute = line.substring(sp + 1); + } + return parts; + }; + + // Parse a ssrc-group line (see RFC 5576). Sample input: + // a=ssrc-group:semantics 12 34 + SDPUtils.parseSsrcGroup = function (line) { + const parts = line.substring(13).split(' '); + return { + semantics: parts.shift(), + ssrcs: parts.map(ssrc => parseInt(ssrc, 10)) + }; + }; + + // Extracts the MID (RFC 5888) from a media section. + // Returns the MID or undefined if no mid line was found. + SDPUtils.getMid = function (mediaSection) { + const mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:')[0]; + if (mid) { + return mid.substring(6); + } + }; + + // Parses a fingerprint line for DTLS-SRTP. + SDPUtils.parseFingerprint = function (line) { + const parts = line.substring(14).split(' '); + return { + algorithm: parts[0].toLowerCase(), + // algorithm is case-sensitive in Edge. + value: parts[1].toUpperCase() // the definition is upper-case in RFC 4572. + }; + }; + + // Extracts DTLS parameters from SDP media section or sessionpart. + // FIXME: for consistency with other functions this should only + // get the fingerprint line as input. See also getIceParameters. + SDPUtils.getDtlsParameters = function (mediaSection, sessionpart) { + const lines = SDPUtils.matchPrefix(mediaSection + sessionpart, 'a=fingerprint:'); + // Note: a=setup line is ignored since we use the 'auto' role in Edge. + return { + role: 'auto', + fingerprints: lines.map(SDPUtils.parseFingerprint) + }; + }; + + // Serializes DTLS parameters to SDP. + SDPUtils.writeDtlsParameters = function (params, setupType) { + let sdp = 'a=setup:' + setupType + '\r\n'; + params.fingerprints.forEach(fp => { + sdp += 'a=fingerprint:' + fp.algorithm + ' ' + fp.value + '\r\n'; + }); + return sdp; + }; + + // Parses a=crypto lines into + // https://rawgit.com/aboba/edgertc/master/msortc-rs4.html#dictionary-rtcsrtpsdesparameters-members + SDPUtils.parseCryptoLine = function (line) { + const parts = line.substring(9).split(' '); + return { + tag: parseInt(parts[0], 10), + cryptoSuite: parts[1], + keyParams: parts[2], + sessionParams: parts.slice(3) + }; + }; + SDPUtils.writeCryptoLine = function (parameters) { + return 'a=crypto:' + parameters.tag + ' ' + parameters.cryptoSuite + ' ' + (typeof parameters.keyParams === 'object' ? SDPUtils.writeCryptoKeyParams(parameters.keyParams) : parameters.keyParams) + (parameters.sessionParams ? ' ' + parameters.sessionParams.join(' ') : '') + '\r\n'; + }; + + // Parses the crypto key parameters into + // https://rawgit.com/aboba/edgertc/master/msortc-rs4.html#rtcsrtpkeyparam* + SDPUtils.parseCryptoKeyParams = function (keyParams) { + if (keyParams.indexOf('inline:') !== 0) { + return null; + } + const parts = keyParams.substring(7).split('|'); + return { + keyMethod: 'inline', + keySalt: parts[0], + lifeTime: parts[1], + mkiValue: parts[2] ? parts[2].split(':')[0] : undefined, + mkiLength: parts[2] ? parts[2].split(':')[1] : undefined + }; + }; + SDPUtils.writeCryptoKeyParams = function (keyParams) { + return keyParams.keyMethod + ':' + keyParams.keySalt + (keyParams.lifeTime ? '|' + keyParams.lifeTime : '') + (keyParams.mkiValue && keyParams.mkiLength ? '|' + keyParams.mkiValue + ':' + keyParams.mkiLength : ''); + }; + + // Extracts all SDES parameters. + SDPUtils.getCryptoParameters = function (mediaSection, sessionpart) { + const lines = SDPUtils.matchPrefix(mediaSection + sessionpart, 'a=crypto:'); + return lines.map(SDPUtils.parseCryptoLine); + }; + + // Parses ICE information from SDP media section or sessionpart. + // FIXME: for consistency with other functions this should only + // get the ice-ufrag and ice-pwd lines as input. + SDPUtils.getIceParameters = function (mediaSection, sessionpart) { + const ufrag = SDPUtils.matchPrefix(mediaSection + sessionpart, 'a=ice-ufrag:')[0]; + const pwd = SDPUtils.matchPrefix(mediaSection + sessionpart, 'a=ice-pwd:')[0]; + if (!(ufrag && pwd)) { + return null; + } + return { + usernameFragment: ufrag.substring(12), + password: pwd.substring(10) + }; + }; + + // Serializes ICE parameters to SDP. + SDPUtils.writeIceParameters = function (params) { + let sdp = 'a=ice-ufrag:' + params.usernameFragment + '\r\n' + 'a=ice-pwd:' + params.password + '\r\n'; + if (params.iceLite) { + sdp += 'a=ice-lite\r\n'; + } + return sdp; + }; + + // Parses the SDP media section and returns RTCRtpParameters. + SDPUtils.parseRtpParameters = function (mediaSection) { + const description = { + codecs: [], + headerExtensions: [], + fecMechanisms: [], + rtcp: [] + }; + const lines = SDPUtils.splitLines(mediaSection); + const mline = lines[0].split(' '); + description.profile = mline[2]; + for (let i = 3; i < mline.length; i++) { + // find all codecs from mline[3..] + const pt = mline[i]; + const rtpmapline = SDPUtils.matchPrefix(mediaSection, 'a=rtpmap:' + pt + ' ')[0]; + if (rtpmapline) { + const codec = SDPUtils.parseRtpMap(rtpmapline); + const fmtps = SDPUtils.matchPrefix(mediaSection, 'a=fmtp:' + pt + ' '); + // Only the first a=fmtp: is considered. + codec.parameters = fmtps.length ? SDPUtils.parseFmtp(fmtps[0]) : {}; + codec.rtcpFeedback = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-fb:' + pt + ' ').map(SDPUtils.parseRtcpFb); + description.codecs.push(codec); + // parse FEC mechanisms from rtpmap lines. + switch (codec.name.toUpperCase()) { + case 'RED': + case 'ULPFEC': + description.fecMechanisms.push(codec.name.toUpperCase()); + break; + } + } + } + SDPUtils.matchPrefix(mediaSection, 'a=extmap:').forEach(line => { + description.headerExtensions.push(SDPUtils.parseExtmap(line)); + }); + const wildcardRtcpFb = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-fb:* ').map(SDPUtils.parseRtcpFb); + description.codecs.forEach(codec => { + wildcardRtcpFb.forEach(fb => { + const duplicate = codec.rtcpFeedback.find(existingFeedback => { + return existingFeedback.type === fb.type && existingFeedback.parameter === fb.parameter; + }); + if (!duplicate) { + codec.rtcpFeedback.push(fb); + } + }); + }); + // FIXME: parse rtcp. + return description; + }; + + // Generates parts of the SDP media section describing the capabilities / + // parameters. + SDPUtils.writeRtpDescription = function (kind, caps) { + let sdp = ''; + + // Build the mline. + sdp += 'm=' + kind + ' '; + sdp += caps.codecs.length > 0 ? '9' : '0'; // reject if no codecs. + sdp += ' ' + (caps.profile || 'UDP/TLS/RTP/SAVPF') + ' '; + sdp += caps.codecs.map(codec => { + if (codec.preferredPayloadType !== undefined) { + return codec.preferredPayloadType; + } + return codec.payloadType; + }).join(' ') + '\r\n'; + sdp += 'c=IN IP4 0.0.0.0\r\n'; + sdp += 'a=rtcp:9 IN IP4 0.0.0.0\r\n'; + + // Add a=rtpmap lines for each codec. Also fmtp and rtcp-fb. + caps.codecs.forEach(codec => { + sdp += SDPUtils.writeRtpMap(codec); + sdp += SDPUtils.writeFmtp(codec); + sdp += SDPUtils.writeRtcpFb(codec); + }); + let maxptime = 0; + caps.codecs.forEach(codec => { + if (codec.maxptime > maxptime) { + maxptime = codec.maxptime; + } + }); + if (maxptime > 0) { + sdp += 'a=maxptime:' + maxptime + '\r\n'; + } + if (caps.headerExtensions) { + caps.headerExtensions.forEach(extension => { + sdp += SDPUtils.writeExtmap(extension); + }); + } + // FIXME: write fecMechanisms. + return sdp; + }; + + // Parses the SDP media section and returns an array of + // RTCRtpEncodingParameters. + SDPUtils.parseRtpEncodingParameters = function (mediaSection) { + const encodingParameters = []; + const description = SDPUtils.parseRtpParameters(mediaSection); + const hasRed = description.fecMechanisms.indexOf('RED') !== -1; + const hasUlpfec = description.fecMechanisms.indexOf('ULPFEC') !== -1; + + // filter a=ssrc:... cname:, ignore PlanB-msid + const ssrcs = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:').map(line => SDPUtils.parseSsrcMedia(line)).filter(parts => parts.attribute === 'cname'); + const primarySsrc = ssrcs.length > 0 && ssrcs[0].ssrc; + let secondarySsrc; + const flows = SDPUtils.matchPrefix(mediaSection, 'a=ssrc-group:FID').map(line => { + const parts = line.substring(17).split(' '); + return parts.map(part => parseInt(part, 10)); + }); + if (flows.length > 0 && flows[0].length > 1 && flows[0][0] === primarySsrc) { + secondarySsrc = flows[0][1]; + } + description.codecs.forEach(codec => { + if (codec.name.toUpperCase() === 'RTX' && codec.parameters.apt) { + let encParam = { + ssrc: primarySsrc, + codecPayloadType: parseInt(codec.parameters.apt, 10) + }; + if (primarySsrc && secondarySsrc) { + encParam.rtx = { + ssrc: secondarySsrc + }; + } + encodingParameters.push(encParam); + if (hasRed) { + encParam = JSON.parse(JSON.stringify(encParam)); + encParam.fec = { + ssrc: primarySsrc, + mechanism: hasUlpfec ? 'red+ulpfec' : 'red' + }; + encodingParameters.push(encParam); + } + } + }); + if (encodingParameters.length === 0 && primarySsrc) { + encodingParameters.push({ + ssrc: primarySsrc + }); + } + + // we support both b=AS and b=TIAS but interpret AS as TIAS. + let bandwidth = SDPUtils.matchPrefix(mediaSection, 'b='); + if (bandwidth.length) { + if (bandwidth[0].indexOf('b=TIAS:') === 0) { + bandwidth = parseInt(bandwidth[0].substring(7), 10); + } else if (bandwidth[0].indexOf('b=AS:') === 0) { + // use formula from JSEP to convert b=AS to TIAS value. + bandwidth = parseInt(bandwidth[0].substring(5), 10) * 1000 * 0.95 - 50 * 40 * 8; + } else { + bandwidth = undefined; + } + encodingParameters.forEach(params => { + params.maxBitrate = bandwidth; + }); + } + return encodingParameters; + }; + + // parses http://draft.ortc.org/#rtcrtcpparameters* + SDPUtils.parseRtcpParameters = function (mediaSection) { + const rtcpParameters = {}; + + // Gets the first SSRC. Note that with RTX there might be multiple + // SSRCs. + const remoteSsrc = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:').map(line => SDPUtils.parseSsrcMedia(line)).filter(obj => obj.attribute === 'cname')[0]; + if (remoteSsrc) { + rtcpParameters.cname = remoteSsrc.value; + rtcpParameters.ssrc = remoteSsrc.ssrc; + } + + // Edge uses the compound attribute instead of reducedSize + // compound is !reducedSize + const rsize = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-rsize'); + rtcpParameters.reducedSize = rsize.length > 0; + rtcpParameters.compound = rsize.length === 0; + + // parses the rtcp-mux attrіbute. + // Note that Edge does not support unmuxed RTCP. + const mux = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-mux'); + rtcpParameters.mux = mux.length > 0; + return rtcpParameters; + }; + SDPUtils.writeRtcpParameters = function (rtcpParameters) { + let sdp = ''; + if (rtcpParameters.reducedSize) { + sdp += 'a=rtcp-rsize\r\n'; + } + if (rtcpParameters.mux) { + sdp += 'a=rtcp-mux\r\n'; + } + if (rtcpParameters.ssrc !== undefined && rtcpParameters.cname) { + sdp += 'a=ssrc:' + rtcpParameters.ssrc + ' cname:' + rtcpParameters.cname + '\r\n'; + } + return sdp; + }; + + // parses either a=msid: or a=ssrc:... msid lines and returns + // the id of the MediaStream and MediaStreamTrack. + SDPUtils.parseMsid = function (mediaSection) { + let parts; + const spec = SDPUtils.matchPrefix(mediaSection, 'a=msid:'); + if (spec.length === 1) { + parts = spec[0].substring(7).split(' '); + return { + stream: parts[0], + track: parts[1] + }; + } + const planB = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:').map(line => SDPUtils.parseSsrcMedia(line)).filter(msidParts => msidParts.attribute === 'msid'); + if (planB.length > 0) { + parts = planB[0].value.split(' '); + return { + stream: parts[0], + track: parts[1] + }; + } + }; + + // SCTP + // parses draft-ietf-mmusic-sctp-sdp-26 first and falls back + // to draft-ietf-mmusic-sctp-sdp-05 + SDPUtils.parseSctpDescription = function (mediaSection) { + const mline = SDPUtils.parseMLine(mediaSection); + const maxSizeLine = SDPUtils.matchPrefix(mediaSection, 'a=max-message-size:'); + let maxMessageSize; + if (maxSizeLine.length > 0) { + maxMessageSize = parseInt(maxSizeLine[0].substring(19), 10); + } + if (isNaN(maxMessageSize)) { + maxMessageSize = 65536; + } + const sctpPort = SDPUtils.matchPrefix(mediaSection, 'a=sctp-port:'); + if (sctpPort.length > 0) { + return { + port: parseInt(sctpPort[0].substring(12), 10), + protocol: mline.fmt, + maxMessageSize + }; + } + const sctpMapLines = SDPUtils.matchPrefix(mediaSection, 'a=sctpmap:'); + if (sctpMapLines.length > 0) { + const parts = sctpMapLines[0].substring(10).split(' '); + return { + port: parseInt(parts[0], 10), + protocol: parts[1], + maxMessageSize + }; + } + }; + + // SCTP + // outputs the draft-ietf-mmusic-sctp-sdp-26 version that all browsers + // support by now receiving in this format, unless we originally parsed + // as the draft-ietf-mmusic-sctp-sdp-05 format (indicated by the m-line + // protocol of DTLS/SCTP -- without UDP/ or TCP/) + SDPUtils.writeSctpDescription = function (media, sctp) { + let output = []; + if (media.protocol !== 'DTLS/SCTP') { + output = ['m=' + media.kind + ' 9 ' + media.protocol + ' ' + sctp.protocol + '\r\n', 'c=IN IP4 0.0.0.0\r\n', 'a=sctp-port:' + sctp.port + '\r\n']; + } else { + output = ['m=' + media.kind + ' 9 ' + media.protocol + ' ' + sctp.port + '\r\n', 'c=IN IP4 0.0.0.0\r\n', 'a=sctpmap:' + sctp.port + ' ' + sctp.protocol + ' 65535\r\n']; + } + if (sctp.maxMessageSize !== undefined) { + output.push('a=max-message-size:' + sctp.maxMessageSize + '\r\n'); + } + return output.join(''); + }; + + // Generate a session ID for SDP. + // https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-20#section-5.2.1 + // recommends using a cryptographically random +ve 64-bit value + // but right now this should be acceptable and within the right range + SDPUtils.generateSessionId = function () { + return Math.random().toString().substr(2, 22); + }; + + // Write boiler plate for start of SDP + // sessId argument is optional - if not supplied it will + // be generated randomly + // sessVersion is optional and defaults to 2 + // sessUser is optional and defaults to 'thisisadapterortc' + SDPUtils.writeSessionBoilerplate = function (sessId, sessVer, sessUser) { + let sessionId; + const version = sessVer !== undefined ? sessVer : 2; + if (sessId) { + sessionId = sessId; + } else { + sessionId = SDPUtils.generateSessionId(); + } + const user = sessUser || 'thisisadapterortc'; + // FIXME: sess-id should be an NTP timestamp. + return 'v=0\r\n' + 'o=' + user + ' ' + sessionId + ' ' + version + ' IN IP4 127.0.0.1\r\n' + 's=-\r\n' + 't=0 0\r\n'; + }; + + // Gets the direction from the mediaSection or the sessionpart. + SDPUtils.getDirection = function (mediaSection, sessionpart) { + // Look for sendrecv, sendonly, recvonly, inactive, default to sendrecv. + const lines = SDPUtils.splitLines(mediaSection); + for (let i = 0; i < lines.length; i++) { + switch (lines[i]) { + case 'a=sendrecv': + case 'a=sendonly': + case 'a=recvonly': + case 'a=inactive': + return lines[i].substring(2); + // FIXME: What should happen here? + } + } + + if (sessionpart) { + return SDPUtils.getDirection(sessionpart); + } + return 'sendrecv'; + }; + SDPUtils.getKind = function (mediaSection) { + const lines = SDPUtils.splitLines(mediaSection); + const mline = lines[0].split(' '); + return mline[0].substring(2); + }; + SDPUtils.isRejected = function (mediaSection) { + return mediaSection.split(' ', 2)[1] === '0'; + }; + SDPUtils.parseMLine = function (mediaSection) { + const lines = SDPUtils.splitLines(mediaSection); + const parts = lines[0].substring(2).split(' '); + return { + kind: parts[0], + port: parseInt(parts[1], 10), + protocol: parts[2], + fmt: parts.slice(3).join(' ') + }; + }; + SDPUtils.parseOLine = function (mediaSection) { + const line = SDPUtils.matchPrefix(mediaSection, 'o=')[0]; + const parts = line.substring(2).split(' '); + return { + username: parts[0], + sessionId: parts[1], + sessionVersion: parseInt(parts[2], 10), + netType: parts[3], + addressType: parts[4], + address: parts[5] + }; + }; + + // a very naive interpretation of a valid SDP. + SDPUtils.isValidSDP = function (blob) { + if (typeof blob !== 'string' || blob.length === 0) { + return false; + } + const lines = SDPUtils.splitLines(blob); + for (let i = 0; i < lines.length; i++) { + if (lines[i].length < 2 || lines[i].charAt(1) !== '=') { + return false; + } + // TODO: check the modifier a bit more. + } + + return true; + }; + + // Expose public methods. + { + module.exports = SDPUtils; + } + })(sdp$1); + var sdpExports = sdp$1.exports; + var SDPUtils = /*@__PURE__*/getDefaultExportFromCjs(sdpExports); + + var sdp = /*#__PURE__*/_mergeNamespaces({ + __proto__: null, + default: SDPUtils + }, [sdpExports]); + + /* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ + /* eslint-env node */ + function shimRTCIceCandidate(window) { + // foundation is arbitrarily chosen as an indicator for full support for + // https://w3c.github.io/webrtc-pc/#rtcicecandidate-interface + if (!window.RTCIceCandidate || window.RTCIceCandidate && 'foundation' in window.RTCIceCandidate.prototype) { + return; + } + const NativeRTCIceCandidate = window.RTCIceCandidate; + window.RTCIceCandidate = function RTCIceCandidate(args) { + // Remove the a= which shouldn't be part of the candidate string. + if (typeof args === 'object' && args.candidate && args.candidate.indexOf('a=') === 0) { + args = JSON.parse(JSON.stringify(args)); + args.candidate = args.candidate.substring(2); + } + if (args.candidate && args.candidate.length) { + // Augment the native candidate with the parsed fields. + const nativeCandidate = new NativeRTCIceCandidate(args); + const parsedCandidate = SDPUtils.parseCandidate(args.candidate); + for (const key in parsedCandidate) { + if (!(key in nativeCandidate)) { + Object.defineProperty(nativeCandidate, key, { + value: parsedCandidate[key] + }); + } + } + + // Override serializer to not serialize the extra attributes. + nativeCandidate.toJSON = function toJSON() { + return { + candidate: nativeCandidate.candidate, + sdpMid: nativeCandidate.sdpMid, + sdpMLineIndex: nativeCandidate.sdpMLineIndex, + usernameFragment: nativeCandidate.usernameFragment + }; + }; + return nativeCandidate; + } + return new NativeRTCIceCandidate(args); + }; + window.RTCIceCandidate.prototype = NativeRTCIceCandidate.prototype; + + // Hook up the augmented candidate in onicecandidate and + // addEventListener('icecandidate', ...) + wrapPeerConnectionEvent(window, 'icecandidate', e => { + if (e.candidate) { + Object.defineProperty(e, 'candidate', { + value: new window.RTCIceCandidate(e.candidate), + writable: 'false' + }); + } + return e; + }); + } + function shimRTCIceCandidateRelayProtocol(window) { + if (!window.RTCIceCandidate || window.RTCIceCandidate && 'relayProtocol' in window.RTCIceCandidate.prototype) { + return; + } + + // Hook up the augmented candidate in onicecandidate and + // addEventListener('icecandidate', ...) + wrapPeerConnectionEvent(window, 'icecandidate', e => { + if (e.candidate) { + const parsedCandidate = SDPUtils.parseCandidate(e.candidate.candidate); + if (parsedCandidate.type === 'relay') { + // This is a libwebrtc-specific mapping of local type preference + // to relayProtocol. + e.candidate.relayProtocol = { + 0: 'tls', + 1: 'tcp', + 2: 'udp' + }[parsedCandidate.priority >> 24]; + } + } + return e; + }); + } + function shimMaxMessageSize(window, browserDetails) { + if (!window.RTCPeerConnection) { + return; + } + if (!('sctp' in window.RTCPeerConnection.prototype)) { + Object.defineProperty(window.RTCPeerConnection.prototype, 'sctp', { + get() { + return typeof this._sctp === 'undefined' ? null : this._sctp; + } + }); + } + const sctpInDescription = function (description) { + if (!description || !description.sdp) { + return false; + } + const sections = SDPUtils.splitSections(description.sdp); + sections.shift(); + return sections.some(mediaSection => { + const mLine = SDPUtils.parseMLine(mediaSection); + return mLine && mLine.kind === 'application' && mLine.protocol.indexOf('SCTP') !== -1; + }); + }; + const getRemoteFirefoxVersion = function (description) { + // TODO: Is there a better solution for detecting Firefox? + const match = description.sdp.match(/mozilla...THIS_IS_SDPARTA-(\d+)/); + if (match === null || match.length < 2) { + return -1; + } + const version = parseInt(match[1], 10); + // Test for NaN (yes, this is ugly) + return version !== version ? -1 : version; + }; + const getCanSendMaxMessageSize = function (remoteIsFirefox) { + // Every implementation we know can send at least 64 KiB. + // Note: Although Chrome is technically able to send up to 256 KiB, the + // data does not reach the other peer reliably. + // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=8419 + let canSendMaxMessageSize = 65536; + if (browserDetails.browser === 'firefox') { + if (browserDetails.version < 57) { + if (remoteIsFirefox === -1) { + // FF < 57 will send in 16 KiB chunks using the deprecated PPID + // fragmentation. + canSendMaxMessageSize = 16384; + } else { + // However, other FF (and RAWRTC) can reassemble PPID-fragmented + // messages. Thus, supporting ~2 GiB when sending. + canSendMaxMessageSize = 2147483637; + } + } else if (browserDetails.version < 60) { + // Currently, all FF >= 57 will reset the remote maximum message size + // to the default value when a data channel is created at a later + // stage. :( + // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831 + canSendMaxMessageSize = browserDetails.version === 57 ? 65535 : 65536; + } else { + // FF >= 60 supports sending ~2 GiB + canSendMaxMessageSize = 2147483637; + } + } + return canSendMaxMessageSize; + }; + const getMaxMessageSize = function (description, remoteIsFirefox) { + // Note: 65536 bytes is the default value from the SDP spec. Also, + // every implementation we know supports receiving 65536 bytes. + let maxMessageSize = 65536; + + // FF 57 has a slightly incorrect default remote max message size, so + // we need to adjust it here to avoid a failure when sending. + // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1425697 + if (browserDetails.browser === 'firefox' && browserDetails.version === 57) { + maxMessageSize = 65535; + } + const match = SDPUtils.matchPrefix(description.sdp, 'a=max-message-size:'); + if (match.length > 0) { + maxMessageSize = parseInt(match[0].substring(19), 10); + } else if (browserDetails.browser === 'firefox' && remoteIsFirefox !== -1) { + // If the maximum message size is not present in the remote SDP and + // both local and remote are Firefox, the remote peer can receive + // ~2 GiB. + maxMessageSize = 2147483637; + } + return maxMessageSize; + }; + const origSetRemoteDescription = window.RTCPeerConnection.prototype.setRemoteDescription; + window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription() { + this._sctp = null; + // Chrome decided to not expose .sctp in plan-b mode. + // As usual, adapter.js has to do an 'ugly worakaround' + // to cover up the mess. + if (browserDetails.browser === 'chrome' && browserDetails.version >= 76) { + const { + sdpSemantics + } = this.getConfiguration(); + if (sdpSemantics === 'plan-b') { + Object.defineProperty(this, 'sctp', { + get() { + return typeof this._sctp === 'undefined' ? null : this._sctp; + }, + enumerable: true, + configurable: true + }); + } + } + if (sctpInDescription(arguments[0])) { + // Check if the remote is FF. + const isFirefox = getRemoteFirefoxVersion(arguments[0]); + + // Get the maximum message size the local peer is capable of sending + const canSendMMS = getCanSendMaxMessageSize(isFirefox); + + // Get the maximum message size of the remote peer. + const remoteMMS = getMaxMessageSize(arguments[0], isFirefox); + + // Determine final maximum message size + let maxMessageSize; + if (canSendMMS === 0 && remoteMMS === 0) { + maxMessageSize = Number.POSITIVE_INFINITY; + } else if (canSendMMS === 0 || remoteMMS === 0) { + maxMessageSize = Math.max(canSendMMS, remoteMMS); + } else { + maxMessageSize = Math.min(canSendMMS, remoteMMS); + } + + // Create a dummy RTCSctpTransport object and the 'maxMessageSize' + // attribute. + const sctp = {}; + Object.defineProperty(sctp, 'maxMessageSize', { + get() { + return maxMessageSize; + } + }); + this._sctp = sctp; + } + return origSetRemoteDescription.apply(this, arguments); + }; + } + function shimSendThrowTypeError(window) { + if (!(window.RTCPeerConnection && 'createDataChannel' in window.RTCPeerConnection.prototype)) { + return; + } + + // Note: Although Firefox >= 57 has a native implementation, the maximum + // message size can be reset for all data channels at a later stage. + // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831 + + function wrapDcSend(dc, pc) { + const origDataChannelSend = dc.send; + dc.send = function send() { + const data = arguments[0]; + const length = data.length || data.size || data.byteLength; + if (dc.readyState === 'open' && pc.sctp && length > pc.sctp.maxMessageSize) { + throw new TypeError('Message too large (can send a maximum of ' + pc.sctp.maxMessageSize + ' bytes)'); + } + return origDataChannelSend.apply(dc, arguments); + }; + } + const origCreateDataChannel = window.RTCPeerConnection.prototype.createDataChannel; + window.RTCPeerConnection.prototype.createDataChannel = function createDataChannel() { + const dataChannel = origCreateDataChannel.apply(this, arguments); + wrapDcSend(dataChannel, this); + return dataChannel; + }; + wrapPeerConnectionEvent(window, 'datachannel', e => { + wrapDcSend(e.channel, e.target); + return e; + }); + } + + /* shims RTCConnectionState by pretending it is the same as iceConnectionState. + * See https://bugs.chromium.org/p/webrtc/issues/detail?id=6145#c12 + * for why this is a valid hack in Chrome. In Firefox it is slightly incorrect + * since DTLS failures would be hidden. See + * https://bugzilla.mozilla.org/show_bug.cgi?id=1265827 + * for the Firefox tracking bug. + */ + function shimConnectionState(window) { + if (!window.RTCPeerConnection || 'connectionState' in window.RTCPeerConnection.prototype) { + return; + } + const proto = window.RTCPeerConnection.prototype; + Object.defineProperty(proto, 'connectionState', { + get() { + return { + completed: 'connected', + checking: 'connecting' + }[this.iceConnectionState] || this.iceConnectionState; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(proto, 'onconnectionstatechange', { + get() { + return this._onconnectionstatechange || null; + }, + set(cb) { + if (this._onconnectionstatechange) { + this.removeEventListener('connectionstatechange', this._onconnectionstatechange); + delete this._onconnectionstatechange; + } + if (cb) { + this.addEventListener('connectionstatechange', this._onconnectionstatechange = cb); + } + }, + enumerable: true, + configurable: true + }); + ['setLocalDescription', 'setRemoteDescription'].forEach(method => { + const origMethod = proto[method]; + proto[method] = function () { + if (!this._connectionstatechangepoly) { + this._connectionstatechangepoly = e => { + const pc = e.target; + if (pc._lastConnectionState !== pc.connectionState) { + pc._lastConnectionState = pc.connectionState; + const newEvent = new Event('connectionstatechange', e); + pc.dispatchEvent(newEvent); + } + return e; + }; + this.addEventListener('iceconnectionstatechange', this._connectionstatechangepoly); + } + return origMethod.apply(this, arguments); + }; + }); + } + function removeExtmapAllowMixed(window, browserDetails) { + /* remove a=extmap-allow-mixed for webrtc.org < M71 */ + if (!window.RTCPeerConnection) { + return; + } + if (browserDetails.browser === 'chrome' && browserDetails.version >= 71) { + return; + } + if (browserDetails.browser === 'safari' && browserDetails.version >= 605) { + return; + } + const nativeSRD = window.RTCPeerConnection.prototype.setRemoteDescription; + window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription(desc) { + if (desc && desc.sdp && desc.sdp.indexOf('\na=extmap-allow-mixed') !== -1) { + const sdp = desc.sdp.split('\n').filter(line => { + return line.trim() !== 'a=extmap-allow-mixed'; + }).join('\n'); + // Safari enforces read-only-ness of RTCSessionDescription fields. + if (window.RTCSessionDescription && desc instanceof window.RTCSessionDescription) { + arguments[0] = new window.RTCSessionDescription({ + type: desc.type, + sdp + }); + } else { + desc.sdp = sdp; + } + } + return nativeSRD.apply(this, arguments); + }; + } + function shimAddIceCandidateNullOrEmpty(window, browserDetails) { + // Support for addIceCandidate(null or undefined) + // as well as addIceCandidate({candidate: "", ...}) + // https://bugs.chromium.org/p/chromium/issues/detail?id=978582 + // Note: must be called before other polyfills which change the signature. + if (!(window.RTCPeerConnection && window.RTCPeerConnection.prototype)) { + return; + } + const nativeAddIceCandidate = window.RTCPeerConnection.prototype.addIceCandidate; + if (!nativeAddIceCandidate || nativeAddIceCandidate.length === 0) { + return; + } + window.RTCPeerConnection.prototype.addIceCandidate = function addIceCandidate() { + if (!arguments[0]) { + if (arguments[1]) { + arguments[1].apply(null); + } + return Promise.resolve(); + } + // Firefox 68+ emits and processes {candidate: "", ...}, ignore + // in older versions. + // Native support for ignoring exists for Chrome M77+. + // Safari ignores as well, exact version unknown but works in the same + // version that also ignores addIceCandidate(null). + if ((browserDetails.browser === 'chrome' && browserDetails.version < 78 || browserDetails.browser === 'firefox' && browserDetails.version < 68 || browserDetails.browser === 'safari') && arguments[0] && arguments[0].candidate === '') { + return Promise.resolve(); + } + return nativeAddIceCandidate.apply(this, arguments); + }; + } + + // Note: Make sure to call this ahead of APIs that modify + // setLocalDescription.length + function shimParameterlessSetLocalDescription(window, browserDetails) { + if (!(window.RTCPeerConnection && window.RTCPeerConnection.prototype)) { + return; + } + const nativeSetLocalDescription = window.RTCPeerConnection.prototype.setLocalDescription; + if (!nativeSetLocalDescription || nativeSetLocalDescription.length === 0) { + return; + } + window.RTCPeerConnection.prototype.setLocalDescription = function setLocalDescription() { + let desc = arguments[0] || {}; + if (typeof desc !== 'object' || desc.type && desc.sdp) { + return nativeSetLocalDescription.apply(this, arguments); + } + // The remaining steps should technically happen when SLD comes off the + // RTCPeerConnection's operations chain (not ahead of going on it), but + // this is too difficult to shim. Instead, this shim only covers the + // common case where the operations chain is empty. This is imperfect, but + // should cover many cases. Rationale: Even if we can't reduce the glare + // window to zero on imperfect implementations, there's value in tapping + // into the perfect negotiation pattern that several browsers support. + desc = { + type: desc.type, + sdp: desc.sdp + }; + if (!desc.type) { + switch (this.signalingState) { + case 'stable': + case 'have-local-offer': + case 'have-remote-pranswer': + desc.type = 'offer'; + break; + default: + desc.type = 'answer'; + break; + } + } + if (desc.sdp || desc.type !== 'offer' && desc.type !== 'answer') { + return nativeSetLocalDescription.apply(this, [desc]); + } + const func = desc.type === 'offer' ? this.createOffer : this.createAnswer; + return func.apply(this).then(d => nativeSetLocalDescription.apply(this, [d])); + }; + } + + var commonShim = /*#__PURE__*/Object.freeze({ + __proto__: null, + removeExtmapAllowMixed: removeExtmapAllowMixed, + shimAddIceCandidateNullOrEmpty: shimAddIceCandidateNullOrEmpty, + shimConnectionState: shimConnectionState, + shimMaxMessageSize: shimMaxMessageSize, + shimParameterlessSetLocalDescription: shimParameterlessSetLocalDescription, + shimRTCIceCandidate: shimRTCIceCandidate, + shimRTCIceCandidateRelayProtocol: shimRTCIceCandidateRelayProtocol, + shimSendThrowTypeError: shimSendThrowTypeError + }); + + /* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ + + // Shimming starts here. + function adapterFactory({ + window + } = {}, options = { + shimChrome: true, + shimFirefox: true, + shimSafari: true + }) { + // Utils. + const logging = log; + const browserDetails = detectBrowser(window); + const adapter = { + browserDetails, + commonShim, + extractVersion: extractVersion, + disableLog: disableLog, + disableWarnings: disableWarnings, + // Expose sdp as a convenience. For production apps include directly. + sdp + }; + + // Shim browser if found. + switch (browserDetails.browser) { + case 'chrome': + if (!chromeShim || !shimPeerConnection$1 || !options.shimChrome) { + logging('Chrome shim is not included in this adapter release.'); + return adapter; + } + if (browserDetails.version === null) { + logging('Chrome shim can not determine version, not shimming.'); + return adapter; + } + logging('adapter.js shimming chrome.'); + // Export to the adapter global object visible in the browser. + adapter.browserShim = chromeShim; + + // Must be called before shimPeerConnection. + shimAddIceCandidateNullOrEmpty(window, browserDetails); + shimParameterlessSetLocalDescription(window); + shimGetUserMedia$2(window, browserDetails); + shimMediaStream(window); + shimPeerConnection$1(window, browserDetails); + shimOnTrack$1(window); + shimAddTrackRemoveTrack(window, browserDetails); + shimGetSendersWithDtmf(window); + shimGetStats(window); + shimSenderReceiverGetStats(window); + fixNegotiationNeeded(window, browserDetails); + shimRTCIceCandidate(window); + shimRTCIceCandidateRelayProtocol(window); + shimConnectionState(window); + shimMaxMessageSize(window, browserDetails); + shimSendThrowTypeError(window); + removeExtmapAllowMixed(window, browserDetails); + break; + case 'firefox': + if (!firefoxShim || !shimPeerConnection || !options.shimFirefox) { + logging('Firefox shim is not included in this adapter release.'); + return adapter; + } + logging('adapter.js shimming firefox.'); + // Export to the adapter global object visible in the browser. + adapter.browserShim = firefoxShim; + + // Must be called before shimPeerConnection. + shimAddIceCandidateNullOrEmpty(window, browserDetails); + shimParameterlessSetLocalDescription(window); + shimGetUserMedia$1(window, browserDetails); + shimPeerConnection(window, browserDetails); + shimOnTrack(window); + shimRemoveStream(window); + shimSenderGetStats(window); + shimReceiverGetStats(window); + shimRTCDataChannel(window); + shimAddTransceiver(window); + shimGetParameters(window); + shimCreateOffer(window); + shimCreateAnswer(window); + shimRTCIceCandidate(window); + shimConnectionState(window); + shimMaxMessageSize(window, browserDetails); + shimSendThrowTypeError(window); + break; + case 'safari': + if (!safariShim || !options.shimSafari) { + logging('Safari shim is not included in this adapter release.'); + return adapter; + } + logging('adapter.js shimming safari.'); + // Export to the adapter global object visible in the browser. + adapter.browserShim = safariShim; + + // Must be called before shimCallbackAPI. + shimAddIceCandidateNullOrEmpty(window, browserDetails); + shimParameterlessSetLocalDescription(window); + shimRTCIceServerUrls(window); + shimCreateOfferLegacy(window); + shimCallbacksAPI(window); + shimLocalStreamsAPI(window); + shimRemoteStreamsAPI(window); + shimTrackEventTransceiver(window); + shimGetUserMedia(window); + shimAudioContext(window); + shimRTCIceCandidate(window); + shimRTCIceCandidateRelayProtocol(window); + shimMaxMessageSize(window, browserDetails); + shimSendThrowTypeError(window); + removeExtmapAllowMixed(window, browserDetails); + break; + default: + logging('Unsupported browser!'); + break; + } + return adapter; + } + + /* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ + /* eslint-env node */ + + const adapter = adapterFactory({ + window: typeof window === 'undefined' ? undefined : window + }); + + var Event$1 = /*#__PURE__*/function () { + function Event() { + _classCallCheck(this, Event); + this._stores = Object.create(null); + } + + //订阅事件 ctx事件执行的上下文对象 + _createClass(Event, [{ + key: "on", + value: function on(event, handler, ctx) { + if (typeof handler !== 'function') { + throw new Error('listener must be a function'); + } + (this._stores[event] = this._stores[event] || []).push({ + cb: handler, + ctx: ctx + }); + return this; + } + + //事件类型只订阅一个事件,调用后删除 + }, { + key: "once", + value: function once(event, handler, ctx) { + var that = this; + function on() { + that.off(event, on); + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + handler.apply(this, args); + } + this.on(event, on, ctx); + return that; + } + + //发布事件 + }, { + key: "emit", + value: function emit(event) { + var store = this._stores[event]; + if (store && store.length) { + for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { + args[_key2 - 1] = arguments[_key2]; + } + for (var i = 0, len = store.length; i < len; i++) { + var _store$i$ctx; + store[i].cb.apply((_store$i$ctx = store[i].ctx) !== null && _store$i$ctx !== void 0 ? _store$i$ctx : null, args); + } + } + } + + //取消订阅 + }, { + key: "off", + value: function off(event, handler) { + // all 取消所有的订阅事件 + if (!arguments.length) { + this._stores = {}; + return; + } + + // specific event + var store = this._stores[event]; + if (!store) return; + + // remove all handlers 取消当前事件类型对应的所有事件 + if (arguments.length === 1) { + delete store[event]; + return; + } + + // remove specific handler 取消特定事件 + for (var i = 0, len = store.length; i < len; i++) { + if (store[i].cb === handler) { + store.splice(i, 1); + break; + } + } + return; + } + }, { + key: "destroy", + value: function destroy() { + this._stores = Object.create(null); + } + }]); + return Event; + }(); + + /** + * Common utilities + * @module glMatrix + */ + // Configuration Constants + var EPSILON = 0.000001; + var ARRAY_TYPE = typeof Float32Array !== 'undefined' ? Float32Array : Array; + if (!Math.hypot) Math.hypot = function () { + var y = 0, + i = arguments.length; + while (i--) { + y += arguments[i] * arguments[i]; + } + return Math.sqrt(y); + }; + + /** + * 4x4 Matrix
Format: column-major, when typed out it looks like row-major
The matrices are being post multiplied. + * @module mat4 + */ + + /** + * Creates a new identity mat4 + * + * @returns {mat4} a new 4x4 matrix + */ + + function create$3() { + var out = new ARRAY_TYPE(16); + if (ARRAY_TYPE != Float32Array) { + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + } + out[0] = 1; + out[5] = 1; + out[10] = 1; + out[15] = 1; + return out; + } + /** + * Set a mat4 to the identity matrix + * + * @param {mat4} out the receiving matrix + * @returns {mat4} out + */ + + function identity(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = 1; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 1; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; + } + /** + * Generates a orthogonal projection matrix with the given bounds. + * The near/far clip planes correspond to a normalized device coordinate Z range of [-1, 1], + * which matches WebGL/OpenGL's clip volume. + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {number} left Left bound of the frustum + * @param {number} right Right bound of the frustum + * @param {number} bottom Bottom bound of the frustum + * @param {number} top Top bound of the frustum + * @param {number} near Near bound of the frustum + * @param {number} far Far bound of the frustum + * @returns {mat4} out + */ + + function orthoNO(out, left, right, bottom, top, near, far) { + var lr = 1 / (left - right); + var bt = 1 / (bottom - top); + var nf = 1 / (near - far); + out[0] = -2 * lr; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = -2 * bt; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 2 * nf; + out[11] = 0; + out[12] = (left + right) * lr; + out[13] = (top + bottom) * bt; + out[14] = (far + near) * nf; + out[15] = 1; + return out; + } + /** + * Alias for {@link mat4.orthoNO} + * @function + */ + + var ortho = orthoNO; + /** + * Generates a look-at matrix with the given eye position, focal point, and up axis. + * If you want a matrix that actually makes an object look at another object, you should use targetTo instead. + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {ReadonlyVec3} eye Position of the viewer + * @param {ReadonlyVec3} center Point the viewer is looking at + * @param {ReadonlyVec3} up vec3 pointing up + * @returns {mat4} out + */ + + function lookAt(out, eye, center, up) { + var x0, x1, x2, y0, y1, y2, z0, z1, z2, len; + var eyex = eye[0]; + var eyey = eye[1]; + var eyez = eye[2]; + var upx = up[0]; + var upy = up[1]; + var upz = up[2]; + var centerx = center[0]; + var centery = center[1]; + var centerz = center[2]; + if (Math.abs(eyex - centerx) < EPSILON && Math.abs(eyey - centery) < EPSILON && Math.abs(eyez - centerz) < EPSILON) { + return identity(out); + } + z0 = eyex - centerx; + z1 = eyey - centery; + z2 = eyez - centerz; + len = 1 / Math.hypot(z0, z1, z2); + z0 *= len; + z1 *= len; + z2 *= len; + x0 = upy * z2 - upz * z1; + x1 = upz * z0 - upx * z2; + x2 = upx * z1 - upy * z0; + len = Math.hypot(x0, x1, x2); + if (!len) { + x0 = 0; + x1 = 0; + x2 = 0; + } else { + len = 1 / len; + x0 *= len; + x1 *= len; + x2 *= len; + } + y0 = z1 * x2 - z2 * x1; + y1 = z2 * x0 - z0 * x2; + y2 = z0 * x1 - z1 * x0; + len = Math.hypot(y0, y1, y2); + if (!len) { + y0 = 0; + y1 = 0; + y2 = 0; + } else { + len = 1 / len; + y0 *= len; + y1 *= len; + y2 *= len; + } + out[0] = x0; + out[1] = y0; + out[2] = z0; + out[3] = 0; + out[4] = x1; + out[5] = y1; + out[6] = z1; + out[7] = 0; + out[8] = x2; + out[9] = y2; + out[10] = z2; + out[11] = 0; + out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez); + out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez); + out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez); + out[15] = 1; + return out; + } + + /** + * 3 Dimensional Vector + * @module vec3 + */ + + /** + * Creates a new, empty vec3 + * + * @returns {vec3} a new 3D vector + */ + + function create$2() { + var out = new ARRAY_TYPE(3); + if (ARRAY_TYPE != Float32Array) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + } + return out; + } + /** + * Creates a new vec3 initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @returns {vec3} a new 3D vector + */ + + function fromValues$2(x, y, z) { + var out = new ARRAY_TYPE(3); + out[0] = x; + out[1] = y; + out[2] = z; + return out; + } + /** + * Perform some operation over an array of vec3s. + * + * @param {Array} a the array of vectors to iterate over + * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed + * @param {Number} offset Number of elements to skip at the beginning of the array + * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array + * @param {Function} fn Function to call for each vector in the array + * @param {Object} [arg] additional argument to pass to fn + * @returns {Array} a + * @function + */ + + (function () { + var vec = create$2(); + return function (a, stride, offset, count, fn, arg) { + var i, l; + if (!stride) { + stride = 3; + } + if (!offset) { + offset = 0; + } + if (count) { + l = Math.min(count * stride + offset, a.length); + } else { + l = a.length; + } + for (i = offset; i < l; i += stride) { + vec[0] = a[i]; + vec[1] = a[i + 1]; + vec[2] = a[i + 2]; + fn(vec, vec, arg); + a[i] = vec[0]; + a[i + 1] = vec[1]; + a[i + 2] = vec[2]; + } + return a; + }; + })(); + + /** + * 4 Dimensional Vector + * @module vec4 + */ + + /** + * Creates a new, empty vec4 + * + * @returns {vec4} a new 4D vector + */ + + function create$1() { + var out = new ARRAY_TYPE(4); + if (ARRAY_TYPE != Float32Array) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 0; + } + return out; + } + /** + * Creates a new vec4 initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @param {Number} w W component + * @returns {vec4} a new 4D vector + */ + + function fromValues$1(x, y, z, w) { + var out = new ARRAY_TYPE(4); + out[0] = x; + out[1] = y; + out[2] = z; + out[3] = w; + return out; + } + /** + * Calculates the dot product of two vec4's + * + * @param {ReadonlyVec4} a the first operand + * @param {ReadonlyVec4} b the second operand + * @returns {Number} dot product of a and b + */ + + function dot(a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; + } + /** + * Perform some operation over an array of vec4s. + * + * @param {Array} a the array of vectors to iterate over + * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed + * @param {Number} offset Number of elements to skip at the beginning of the array + * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array + * @param {Function} fn Function to call for each vector in the array + * @param {Object} [arg] additional argument to pass to fn + * @returns {Array} a + * @function + */ + + (function () { + var vec = create$1(); + return function (a, stride, offset, count, fn, arg) { + var i, l; + if (!stride) { + stride = 4; + } + if (!offset) { + offset = 0; + } + if (count) { + l = Math.min(count * stride + offset, a.length); + } else { + l = a.length; + } + for (i = offset; i < l; i += stride) { + vec[0] = a[i]; + vec[1] = a[i + 1]; + vec[2] = a[i + 2]; + vec[3] = a[i + 3]; + fn(vec, vec, arg); + a[i] = vec[0]; + a[i + 1] = vec[1]; + a[i + 2] = vec[2]; + a[i + 3] = vec[3]; + } + return a; + }; + })(); + + /** + * 2 Dimensional Vector + * @module vec2 + */ + + /** + * Creates a new, empty vec2 + * + * @returns {vec2} a new 2D vector + */ + + function create() { + var out = new ARRAY_TYPE(2); + if (ARRAY_TYPE != Float32Array) { + out[0] = 0; + out[1] = 0; + } + return out; + } + /** + * Creates a new vec2 initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @returns {vec2} a new 2D vector + */ + + function fromValues(x, y) { + var out = new ARRAY_TYPE(2); + out[0] = x; + out[1] = y; + return out; + } + /** + * Perform some operation over an array of vec2s. + * + * @param {Array} a the array of vectors to iterate over + * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed + * @param {Number} offset Number of elements to skip at the beginning of the array + * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array + * @param {Function} fn Function to call for each vector in the array + * @param {Object} [arg] additional argument to pass to fn + * @returns {Array} a + * @function + */ + + (function () { + var vec = create(); + return function (a, stride, offset, count, fn, arg) { + var i, l; + if (!stride) { + stride = 2; + } + if (!offset) { + offset = 0; + } + if (count) { + l = Math.min(count * stride + offset, a.length); + } else { + l = a.length; + } + for (i = offset; i < l; i += stride) { + vec[0] = a[i]; + vec[1] = a[i + 1]; + fn(vec, vec, arg); + a[i] = vec[0]; + a[i + 1] = vec[1]; + } + return a; + }; + })(); + + var vsSource$1 = "\nattribute vec4 aVertexPosition;\nattribute vec2 aTexturePosition;\nuniform mat4 uModelMatrix;\nuniform mat4 uViewMatrix;\nuniform mat4 uProjectionMatrix;\nvarying lowp vec2 vTexturePosition;\nvoid main(void) {\n gl_Position = uProjectionMatrix * uViewMatrix * uModelMatrix * aVertexPosition;\n vTexturePosition = aTexturePosition;\n}\n"; + + // Fragment shader program + + var fsSource$1 = "\nprecision mediump float;\nvarying lowp vec2 vTexturePosition;\nuniform sampler2D uTexture; \nvoid main(void) {\n\n vec4 color = texture2D(uTexture, vTexturePosition);\n vec4 alphacolor = texture2D(uTexture, vTexturePosition + vec2(0.5, 0));\n\n color.a = alphacolor.r;\n\n gl_FragColor = color;\n\n}\n"; + var RectMaskRender = /*#__PURE__*/function () { + function RectMaskRender(gl, width, height) { + _classCallCheck(this, RectMaskRender); + _defineProperty(this, "gl", undefined); + _defineProperty(this, "width", 0); + _defineProperty(this, "height", 0); + _defineProperty(this, "programInfo", undefined); + _defineProperty(this, "buffers", undefined); + this.width = width; + this.height = height; + this.gl = gl; + this.gl.pixelStorei(this.gl.UNPACK_ALIGNMENT, 1); + var _this$initShaderProgr = this.initShaderProgram(vsSource$1, fsSource$1), + shaderProgram = _this$initShaderProgr.shaderProgram, + vertexShader = _this$initShaderProgr.vertexShader, + fragmentShader = _this$initShaderProgr.fragmentShader; + this.programInfo = { + program: shaderProgram, + vshader: vertexShader, + fshader: fragmentShader, + attribLocations: { + vertexPosition: this.gl.getAttribLocation(shaderProgram, 'aVertexPosition'), + texturePosition: this.gl.getAttribLocation(shaderProgram, 'aTexturePosition') + }, + uniformLocations: { + projectionMatrix: this.gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'), + modelMatrix: this.gl.getUniformLocation(shaderProgram, 'uModelMatrix'), + viewMatrix: this.gl.getUniformLocation(shaderProgram, 'uViewMatrix'), + texture: this.gl.getUniformLocation(shaderProgram, 'uTexture') + } + }; + this.buffers = this.initBuffers(); + var texture = this.gl.createTexture(); + this.gl.bindTexture(this.gl.TEXTURE_2D, texture); + this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST); + this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST); + this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE); + this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE); + this.texture = texture; + } + _createClass(RectMaskRender, [{ + key: "updateTexture", + value: function updateTexture(rgbabuf) { + var textunit = 3; + this.gl.activeTexture(this.gl.TEXTURE0 + textunit); + this.gl.bindTexture(this.gl.TEXTURE_2D, this.texture); + this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, rgbabuf); + this.drawNow(); + } + }, { + key: "getRGBA", + value: function getRGBA() { + var pixels = new Uint8Array(this.width * this.height * 4); + this.gl.readPixels(0, 0, this.width, this.height, this.gl.RGBA, this.gl.UNSIGNED_BYTE, pixels); + return pixels; + } + }, { + key: "destroy", + value: function destroy() { + if (this.buffers.position) { + this.gl.deleteBuffer(this.buffers.position); + } + if (this.buffers.texposition) { + this.gl.deleteBuffer(this.buffers.texposition); + } + if (this.buffers.indices) { + this.gl.deleteBuffer(this.buffers.indices); + } + if (this.texture) { + this.gl.deleteTexture(this.texture); + } + if (this.programInfo.program) { + this.gl.deleteProgram(this.programInfo.program); + } + if (this.programInfo.vshader) { + this.gl.deleteShader(this.programInfo.vshader); + } + if (this.programInfo.fshader) { + this.gl.deleteShader(this.programInfo.fshader); + } + } + }, { + key: "drawNow", + value: function drawNow() { + this.gl.viewport(0, 0, this.width, this.height); + this.gl.clearColor(0.0, 0.0, 0.0, 0.0); // Clear to black, fully opaque + + this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT); + this.gl.enable(this.gl.BLEND); + this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA); + var zNear = 0.1; + var zFar = 100.0; + var projectionMatrix = create$3(); + ortho(projectionMatrix, -1, 1, -1, 1, zNear, zFar); + var modelMatrix = create$3(); + identity(modelMatrix); + var viewMatrix = create$3(); + lookAt(viewMatrix, fromValues$2(0, 0, 0), fromValues$2(0, 0, -1), fromValues$2(0, 1, 0)); + this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.buffers.position); + this.gl.vertexAttribPointer(this.programInfo.attribLocations.vertexPosition, 3, this.gl.FLOAT, false, 0, 0); + this.gl.enableVertexAttribArray(this.programInfo.attribLocations.vertexPosition); + this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.buffers.texposition); + this.gl.vertexAttribPointer(this.programInfo.attribLocations.texturePosition, 2, this.gl.FLOAT, false, 0, 0); + this.gl.enableVertexAttribArray(this.programInfo.attribLocations.texturePosition); + var textunit = 2; + this.gl.activeTexture(this.gl.TEXTURE0 + textunit); + this.gl.bindTexture(this.gl.TEXTURE_2D, this.texture); + this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.buffers.indices); + this.gl.useProgram(this.programInfo.program); + this.gl.uniformMatrix4fv(this.programInfo.uniformLocations.projectionMatrix, false, projectionMatrix); + this.gl.uniformMatrix4fv(this.programInfo.uniformLocations.modelMatrix, false, modelMatrix); + this.gl.uniformMatrix4fv(this.programInfo.uniformLocations.viewMatrix, false, viewMatrix); + this.gl.uniform1i(this.programInfo.uniformLocations.texture, textunit); + this.gl.drawElements(this.gl.TRIANGLES, 6, this.gl.UNSIGNED_SHORT, 0); + } + }, { + key: "initBuffers", + value: function initBuffers() { + var _texturePos; + var positionBuffer = this.gl.createBuffer(); + this.gl.bindBuffer(this.gl.ARRAY_BUFFER, positionBuffer); + var positions = [ + // Front face + -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0]; + this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(positions), this.gl.STATIC_DRAW); + var facePos = [[0.0, 1.0], [0.5, 1.0], [0.5, 0.0], [0.0, 0.0]]; + + // Convert the array of colors into a table for all the vertices. + + var texturePos = []; + texturePos = (_texturePos = texturePos).concat.apply(_texturePos, facePos); + var texpositionBuffer = this.gl.createBuffer(); + this.gl.bindBuffer(this.gl.ARRAY_BUFFER, texpositionBuffer); + this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(texturePos), this.gl.STATIC_DRAW); + + // Build the element array buffer; this specifies the indices + // into the vertex arrays for each face's vertices. + + var indexBuffer = this.gl.createBuffer(); + this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, indexBuffer); + + // This array defines each face as two triangles, using the + // indices into the vertex array to specify each triangle's + // position. + + var indices = [0, 1, 2, 0, 2, 3]; + + // Now send the element array to GL + + this.gl.bufferData(this.gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), this.gl.STATIC_DRAW); + return { + position: positionBuffer, + texposition: texpositionBuffer, + indices: indexBuffer + }; + } + }, { + key: "initShaderProgram", + value: function initShaderProgram(vsSource, fsSource) { + var vertexShader = this.loadShader(this.gl.VERTEX_SHADER, vsSource); + var fragmentShader = this.loadShader(this.gl.FRAGMENT_SHADER, fsSource); + var shaderProgram = this.gl.createProgram(); + this.gl.attachShader(shaderProgram, vertexShader); + this.gl.attachShader(shaderProgram, fragmentShader); + this.gl.linkProgram(shaderProgram); + if (!this.gl.getProgramParameter(shaderProgram, this.gl.LINK_STATUS)) { + console.error('Unable to initialize the shader program: ' + this.gl.getProgramInfoLog(shaderProgram)); + return; + } + return { + shaderProgram: shaderProgram, + vertexShader: vertexShader, + fragmentShader: fragmentShader + }; + } + }, { + key: "loadShader", + value: function loadShader(type, source) { + var shader = this.gl.createShader(type); + this.gl.shaderSource(shader, source); + this.gl.compileShader(shader); + if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) { + console.error('An error occurred compiling the shaders: ' + this.gl.getShaderInfoLog(shader)); + this.gl.deleteShader(shader); + return; + } + return shader; + } + }]); + return RectMaskRender; + }(); + + var vsSource = "\nattribute vec4 aVertexPosition;\nattribute vec2 aTexturePosition;\nuniform mat4 uModelMatrix;\nuniform mat4 uViewMatrix;\nuniform mat4 uProjectionMatrix;\nvarying highp vec2 vTexturePosition;\nvoid main(void) {\n gl_Position = uProjectionMatrix * uViewMatrix * uModelMatrix * aVertexPosition;\n vTexturePosition = aTexturePosition;\n}\n"; + + // Fragment shader program + + var fsSource = "\nprecision highp float;\nvarying highp vec2 vTexturePosition;\nuniform sampler2D uTexture; \n\n\nuniform float opacity; //\u4E0D\u900F\u660E [0.0 , 1.0] \u9ED8\u8BA4 1.0\nuniform float contrast; //\u5BF9\u6BD4\u5EA6 [-1.0, 1.0] \u9ED8\u8BA4 0\nuniform float brightness; //\u4EAE\u5EA6 [-1.0, 1.0] \u9ED8\u8BA4 0\nuniform float gamma; //gamma [-1.0, 1.0] \u9ED8\u8BA4 0\n\n\nuniform float similarity; //\u76F8\u4F3C\u5EA6 [0.0 , 1.0] \u9ED8\u8BA4 0.4\nuniform float smoothness; //\u5E73\u6ED1\u5EA6 [0.0 , 1.0] \u9ED8\u8BA4 0.08\nuniform float spill; //\u4E3B\u8272\u6CC4\u9732\u51CF\u5C11 [0.0 , 1.0] \u9ED8\u8BA4 0.1\nuniform vec2 chroma_key; //\u62A0\u56FE\u989C\u8272 RGB->YCbCr,\u8FD9\u91CC\u53EA\u8981 Cb\u548CCr \u4E24\u4E2A\u989C\u8272\u5206\u91CF\nuniform vec2 pixel_size; //\u4E00\u4E2A\u50CF\u7D20\u5728\u7EB9\u7406\u7A7A\u95F4\u7684\u5927\u5C0F (1.0/width, 1.0/height)\n\nvec4 cb_v4 = vec4( -0.100644, -0.338572, 0.439216, 0.501961);\nvec4 cr_v4 = vec4( 0.439216, -0.398942, -0.040274, 0.501961);\n\n\nvec4 CalcColor(vec4 rgba)\n{\n\treturn vec4(pow(rgba.rgb, vec3(gamma, gamma, gamma)) * contrast + brightness, rgba.a);\n}\n\nfloat GetChromaDist(vec3 rgb)\n{\n\tfloat cb = dot(rgb.rgb, cb_v4.xyz) + cb_v4.w;\n\tfloat cr = dot(rgb.rgb, cr_v4.xyz) + cr_v4.w;\n\treturn distance(chroma_key, vec2(cb, cr));\n}\n\n\nvec3 SampleTexture(vec2 uv)\n{\n\tvec3 rgb = texture2D(uTexture, uv).rgb;\n return rgb;\n}\n\nfloat GetBoxFilteredChromaDist(vec3 rgb, vec2 texCoord)\n{\n\tvec2 h_pixel_size = pixel_size / 2.0;\n\tvec2 point_0 = vec2(pixel_size.x, h_pixel_size.y);\n\tvec2 point_1 = vec2(h_pixel_size.x, -pixel_size.y);\n\tfloat distVal = GetChromaDist(SampleTexture(texCoord-point_0));\n\tdistVal += GetChromaDist(SampleTexture(texCoord+point_0));\n\tdistVal += GetChromaDist(SampleTexture(texCoord-point_1));\n\tdistVal += GetChromaDist(SampleTexture(texCoord+point_1));\n\tdistVal *= 2.0;\n distVal += GetChromaDist(rgb);\n\treturn distVal / 9.0;\n}\n\nvec4 ProcessChromaKey(vec4 rgba, vec2 uv)\n{\n\tfloat chromaDist = GetBoxFilteredChromaDist(rgba.rgb, uv);\n\tfloat baseMask = chromaDist - similarity;\n\tfloat fullMask = pow(clamp(baseMask / smoothness, 0.0, 1.0), 1.5);\n\tfloat spillVal = pow(clamp(baseMask / spill, 0.0, 1.0), 1.5);\n\n\trgba.a *= opacity;\n\trgba.a *= fullMask;\n\n\tfloat desat = dot(rgba.rgb, vec3(0.2126, 0.7152, 0.0722));\n\trgba.rgb = mix(vec3(desat, desat, desat), rgba.rgb, spillVal);\n\n\treturn CalcColor(rgba);\n}\n\nvec4 PSChromaKeyRGBA(vec2 uv) \n{\n\tvec4 rgba = texture2D(uTexture, uv);\n\trgba.rgb = max(vec3(0.0, 0.0, 0.0), rgba.rgb / rgba.a);\n\trgba = ProcessChromaKey(rgba, uv);\n //rgba.rgb *= rgba.a;\n\treturn rgba;\n}\n\n\nvoid main(void) {\n\n gl_FragColor = PSChromaKeyRGBA(vTexturePosition);\n\n}\n"; + var RectRender = /*#__PURE__*/function () { + function RectRender(gl, width, height) { + _classCallCheck(this, RectRender); + _defineProperty(this, "gl", undefined); + _defineProperty(this, "width", 0); + _defineProperty(this, "height", 0); + _defineProperty(this, "programInfo", undefined); + _defineProperty(this, "buffers", undefined); + _defineProperty(this, "settings", undefined); + this.width = width; + this.height = height; + this.gl = gl; + this.gl.pixelStorei(this.gl.UNPACK_ALIGNMENT, 1); + var _this$initShaderProgr = this.initShaderProgram(vsSource, fsSource), + shaderProgram = _this$initShaderProgr.shaderProgram, + vertexShader = _this$initShaderProgr.vertexShader, + fragmentShader = _this$initShaderProgr.fragmentShader; + this.programInfo = { + program: shaderProgram, + vshader: vertexShader, + fshader: fragmentShader, + attribLocations: { + vertexPosition: this.gl.getAttribLocation(shaderProgram, 'aVertexPosition'), + texturePosition: this.gl.getAttribLocation(shaderProgram, 'aTexturePosition') + }, + uniformLocations: { + projectionMatrix: this.gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'), + modelMatrix: this.gl.getUniformLocation(shaderProgram, 'uModelMatrix'), + viewMatrix: this.gl.getUniformLocation(shaderProgram, 'uViewMatrix'), + texture: this.gl.getUniformLocation(shaderProgram, 'uTexture'), + opacity: this.gl.getUniformLocation(shaderProgram, 'opacity'), + contrast: this.gl.getUniformLocation(shaderProgram, 'contrast'), + brightness: this.gl.getUniformLocation(shaderProgram, 'brightness'), + gamma: this.gl.getUniformLocation(shaderProgram, 'gamma'), + similarity: this.gl.getUniformLocation(shaderProgram, 'similarity'), + smoothness: this.gl.getUniformLocation(shaderProgram, 'smoothness'), + spill: this.gl.getUniformLocation(shaderProgram, 'spill'), + chroma_key: this.gl.getUniformLocation(shaderProgram, 'chroma_key'), + pixel_size: this.gl.getUniformLocation(shaderProgram, 'pixel_size') + } + }; + this.buffers = this.initBuffers(); + var texture = this.gl.createTexture(); + this.gl.bindTexture(this.gl.TEXTURE_2D, texture); + this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST); + this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST); + this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE); + this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE); + this.texture = texture; + this.settings = {}; + this.settings.opacity = 1.0; + this.settings.contrast = 1.0; + this.settings.brightness = 0.; + this.settings.gamma = 1.0; + this.settings.similarity = 0.4; + this.settings.smoothness = 0.08; + this.settings.spill = 0.1; + var chromeColor = fromValues$1(0., 1., 0., 1.0); //这里默认是绿色,可以调整其他颜色 + var cb_v4 = fromValues$1(-0.100644, -0.338572, 0.439216, 0.501961); + var cr_v4 = fromValues$1(0.439216, -0.398942, -0.040274, 0.501961); + this.settings.chroma_key = fromValues(dot(chromeColor, cb_v4), dot(chromeColor, cr_v4)); + this.settings.pixel_size = fromValues(1.0 / width, 1.0 / height); + } + _createClass(RectRender, [{ + key: "updateTexture", + value: function updateTexture(rgbabuf) { + var textunit = 3; + this.gl.activeTexture(this.gl.TEXTURE0 + textunit); + this.gl.bindTexture(this.gl.TEXTURE_2D, this.texture); + this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, rgbabuf); + this.drawNow(); + } + }, { + key: "getRGBA", + value: function getRGBA() { + var pixels = new Uint8Array(this.width * this.height * 4); + this.gl.readPixels(0, 0, this.width, this.height, this.gl.RGBA, this.gl.UNSIGNED_BYTE, pixels); + return pixels; + } + }, { + key: "destroy", + value: function destroy() { + if (this.buffers.position) { + this.gl.deleteBuffer(this.buffers.position); + } + if (this.buffers.texposition) { + this.gl.deleteBuffer(this.buffers.texposition); + } + if (this.buffers.indices) { + this.gl.deleteBuffer(this.buffers.indices); + } + if (this.texture) { + this.gl.deleteTexture(this.texture); + } + if (this.programInfo.program) { + this.gl.deleteProgram(this.programInfo.program); + } + if (this.programInfo.vshader) { + this.gl.deleteShader(this.programInfo.vshader); + } + if (this.programInfo.fshader) { + this.gl.deleteShader(this.programInfo.fshader); + } + } + }, { + key: "initBuffers", + value: function initBuffers() { + var _texturePos; + var positionBuffer = this.gl.createBuffer(); + this.gl.bindBuffer(this.gl.ARRAY_BUFFER, positionBuffer); + var positions = [ + // Front face + -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0]; + this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(positions), this.gl.STATIC_DRAW); + var facePos = [[0.0, 1.0], [1.0, 1.0], [1.0, 0.0], [0.0, 0.0]]; + + // Convert the array of colors into a table for all the vertices. + + var texturePos = []; + texturePos = (_texturePos = texturePos).concat.apply(_texturePos, facePos); + var texpositionBuffer = this.gl.createBuffer(); + this.gl.bindBuffer(this.gl.ARRAY_BUFFER, texpositionBuffer); + this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(texturePos), this.gl.STATIC_DRAW); + + // Build the element array buffer; this specifies the indices + // into the vertex arrays for each face's vertices. + + var indexBuffer = this.gl.createBuffer(); + this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, indexBuffer); + + // This array defines each face as two triangles, using the + // indices into the vertex array to specify each triangle's + // position. + + var indices = [0, 1, 2, 0, 2, 3]; + + // Now send the element array to GL + + this.gl.bufferData(this.gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), this.gl.STATIC_DRAW); + return { + position: positionBuffer, + texposition: texpositionBuffer, + indices: indexBuffer + }; + } + }, { + key: "drawNow", + value: function drawNow() { + this.gl.viewport(0, 0, this.width, this.height); + this.gl.clearColor(0.0, 0.0, 0.0, 0.0); // Clear to black, fully opaque + + this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT); + this.gl.enable(this.gl.BLEND); + this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA); + var zNear = 0.1; + var zFar = 100.0; + var projectionMatrix = create$3(); + ortho(projectionMatrix, -1, 1, -1, 1, zNear, zFar); + var modelMatrix = create$3(); + identity(modelMatrix); + var viewMatrix = create$3(); + lookAt(viewMatrix, fromValues$2(0, 0, 0), fromValues$2(0, 0, -1), fromValues$2(0, 1, 0)); + this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.buffers.position); + this.gl.vertexAttribPointer(this.programInfo.attribLocations.vertexPosition, 3, this.gl.FLOAT, false, 0, 0); + this.gl.enableVertexAttribArray(this.programInfo.attribLocations.vertexPosition); + this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.buffers.texposition); + this.gl.vertexAttribPointer(this.programInfo.attribLocations.texturePosition, 2, this.gl.FLOAT, false, 0, 0); + this.gl.enableVertexAttribArray(this.programInfo.attribLocations.texturePosition); + var textunit = 2; + this.gl.activeTexture(this.gl.TEXTURE0 + textunit); + this.gl.bindTexture(this.gl.TEXTURE_2D, this.texture); + this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.buffers.indices); + this.gl.useProgram(this.programInfo.program); + this.gl.uniformMatrix4fv(this.programInfo.uniformLocations.projectionMatrix, false, projectionMatrix); + this.gl.uniformMatrix4fv(this.programInfo.uniformLocations.modelMatrix, false, modelMatrix); + this.gl.uniformMatrix4fv(this.programInfo.uniformLocations.viewMatrix, false, viewMatrix); + this.gl.uniform1i(this.programInfo.uniformLocations.texture, textunit); + this.gl.uniform1f(this.programInfo.uniformLocations.opacity, this.settings.opacity); + this.gl.uniform1f(this.programInfo.uniformLocations.contrast, this.settings.contrast); + this.gl.uniform1f(this.programInfo.uniformLocations.brightness, this.settings.brightness); + this.gl.uniform1f(this.programInfo.uniformLocations.gamma, this.settings.gamma); + this.gl.uniform1f(this.programInfo.uniformLocations.similarity, this.settings.similarity); + this.gl.uniform1f(this.programInfo.uniformLocations.smoothness, this.settings.smoothness); + this.gl.uniform1f(this.programInfo.uniformLocations.spill, this.settings.spill); + this.gl.uniform2fv(this.programInfo.uniformLocations.chroma_key, this.settings.chroma_key); + this.gl.uniform2fv(this.programInfo.uniformLocations.pixel_size, this.settings.pixel_size); + this.gl.drawElements(this.gl.TRIANGLES, 6, this.gl.UNSIGNED_SHORT, 0); + } + }, { + key: "initShaderProgram", + value: function initShaderProgram(vsSource, fsSource) { + var vertexShader = this.loadShader(this.gl.VERTEX_SHADER, vsSource); + var fragmentShader = this.loadShader(this.gl.FRAGMENT_SHADER, fsSource); + var shaderProgram = this.gl.createProgram(); + this.gl.attachShader(shaderProgram, vertexShader); + this.gl.attachShader(shaderProgram, fragmentShader); + this.gl.linkProgram(shaderProgram); + if (!this.gl.getProgramParameter(shaderProgram, this.gl.LINK_STATUS)) { + console.error('Unable to initialize the shader program: ' + this.gl.getProgramInfoLog(shaderProgram)); + return; + } + return { + shaderProgram: shaderProgram, + vertexShader: vertexShader, + fragmentShader: fragmentShader + }; + } + }, { + key: "loadShader", + value: function loadShader(type, source) { + var shader = this.gl.createShader(type); + this.gl.shaderSource(shader, source); + this.gl.compileShader(shader); + if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) { + console.error('An error occurred compiling the shaders: ' + this.gl.getShaderInfoLog(shader)); + this.gl.deleteShader(shader); + return; + } + return shader; + } + }]); + return RectRender; + }(); + + var alphacanvas = document.createElement('canvas'); // 最终展示的画布 + var alphacanvasGL = createContextGL(alphacanvas); + var render = null; + var video = null; + var fps = 25; + var lastTime = 0; + + /** + * + * @param {Element} v 需要扣背景的video标签 + * @param {number} f fps,默认25 + */ + function wipe(v) { + var f = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 25; + video = v; + fps = f; + video.parentElement.appendChild(alphacanvas); + video.parentElement.style.fontSize = 0; + video.parentElement.style.positon = 'relative'; + rollWipe(); + } + + /** + * + * @param {Element} v 需要扣背景的video标签 + * @param {number} f fps,默认25 + */ + function wipeGreen(v) { + var f = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 25; + video = v; + fps = f; + video.parentElement.appendChild(alphacanvas); + video.parentElement.style.fontSize = 0; + video.parentElement.style.positon = 'relative'; + rollWipeGreen(); + } + + /** + * 停止扣背景,释放资源 + */ + function stopWipe() { + if (render) { + render.destroy(); + render = null; + } + } + function createContextGL(canvas) { + var gl = null; + var validContextNames = ['webgl', 'experimental-webgl', 'moz-webgl', 'webkit-3d']; + var nameIndex = 0; + while (!gl && nameIndex < validContextNames.length) { + var contextName = validContextNames[nameIndex]; + try { + var contextOptions = { + preserveDrawingBuffer: true, + antialias: true + }; + gl = canvas.getContext(contextName, contextOptions); + } catch (e) { + gl = null; + } + if (!gl || typeof gl.getParameter !== 'function') { + gl = null; + } + ++nameIndex; + } + return gl; + } + function rollWipe(timestamp) { + if (!timestamp) { + lastTime = timestamp = performance.now(); + } + var frameTime = 1000 / fps; + if (timestamp - lastTime >= frameTime && 0 !== video.videoWidth) { + if (!render) { + render = new RectMaskRender(alphacanvasGL, video.videoWidth / 2, video.videoHeight); + alphacanvas.width = video.videoWidth / 2; + alphacanvas.height = video.videoHeight; + Object.assign(alphacanvas.style, { + width: '100%', + height: '100%', + position: 'absolute', + top: 0, + left: 0 + }); + } + render.updateTexture(video, video.videoWidth, video.videoHeight); + lastTime = timestamp; + } + requestAnimationFrame(rollWipe); + } + function rollWipeGreen(timestamp) { + if (!timestamp) { + lastTime = timestamp = performance.now(); + } + var frameTime = 1000 / fps; + if (timestamp - lastTime >= frameTime && 0 !== video.videoWidth) { + if (!render) { + render = new RectRender(alphacanvasGL, video.videoWidth, video.videoHeight); + alphacanvas.width = video.videoWidth; + alphacanvas.height = video.videoHeight; + Object.assign(alphacanvas.style, { + width: '100%', + height: '100%', + position: 'absolute', + top: 0, + left: 0 + }); + } + render.updateTexture(video, video.videoWidth, video.videoHeight); + lastTime = timestamp; + } + requestAnimationFrame(rollWipeGreen); + } + + var uuid = function uuid() { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { + var r = Math.random() * 16 | 0, + v = c === 'x' ? r : r & 0x3 | 0x8; + return v.toString(16); + }); + }; + // 客户端唯一标记 + function clientUuid() { + var clientId = localStorage.getItem('__client'); + if (clientId) { + return clientId; + } + clientId = 'C_' + uuid(); + localStorage.setItem('__client', clientId); + return clientId; + } + function pick(obj, keys) { + return keys.reduce(function (acc, key) { + if (obj.hasOwnProperty(key)) { + acc[key] = obj[key]; + } + return acc; + }, {}); + } + function set(obj, path, value) { + if (Object(obj) !== obj) return obj; + if (!Array.isArray(path)) path = path.toString().match(/[^.[\]]+/g) || []; + path.slice(0, -1).reduce(function (a, c, i) { + return Object(a[c]) === a[c] ? a[c] : a[c] = Math.abs(path[i + 1]) >> 0 === +path[i + 1] ? [] : {}; + }, obj)[path[path.length - 1]] = value; + return obj; + } + function isObject(item) { + return item && _typeof(item) === 'object' && !Array.isArray(item); + } + function merge(target, source) { + var output = Object.assign({}, target); + if (isObject(target) && isObject(source)) { + Object.keys(source).forEach(function (key) { + if (isObject(source[key])) { + if (!(key in target)) Object.assign(output, _defineProperty({}, key, source[key]));else output[key] = merge(target[key], source[key]); + } else { + Object.assign(output, _defineProperty({}, key, source[key])); + } + }); + } + return output; + } + function urlAppendParam(uri) { + var params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var url = new URL(uri); + Object.keys(params).forEach(function (key) { + return url.searchParams.append(key, params[key]); + }); + return url.toString(); + } + function getUrlParams(uri) { + var url = new URL(uri); + var params = new URLSearchParams(url.search); + var obj = {}; + var _iterator = _createForOfIteratorHelper(params.entries()), + _step; + try { + for (_iterator.s(); !(_step = _iterator.n()).done;) { + var pair = _step.value; + obj[pair[0]] = pair[1]; + } + } catch (err) { + _iterator.e(err); + } finally { + _iterator.f(); + } + return obj; + } + function getUrlParamsString(uri) { + var url = new URL(uri); + var params = new URLSearchParams(url.search); + return params.toString(); + } + + var http = { + get: function get(url, param) { + return new Promise(function (resolve, reject) { + var xhr = new XMLHttpRequest(); + var query; + if (param) { + query = Object.keys(param).map(function (item) { + return "".concat(item, "=").concat(param[item]); + }).join('&'); + } + xhr.open('get', query ? "".concat(url, "?").concat(query) : url); + xhr.setRequestHeader('sig', sessionStorage.getItem('_duix_sign')); + xhr.responseType = 'json'; + xhr.send(); + xhr.timeout = 15000; + xhr.onload = function () { + resolve(xhr.response); + }; + xhr.ontimeout = function () { + reject({ + code: '504', + text: 'timeout' + }); + }; + }); + }, + post: function post(url, params) { + return new Promise(function (resolve, reject) { + var xhr = new XMLHttpRequest(); + xhr.open('POST', url); + xhr.setRequestHeader('Content-Type', 'application/json'); + xhr.setRequestHeader('Uuid', sessionStorage.getItem('_duix_sessionId')); + xhr.setRequestHeader('Request-Date', new Date().getTime()); + xhr.setRequestHeader('token', sessionStorage.getItem('_duix_token')); + xhr.setRequestHeader('sig', sessionStorage.getItem('_duix_sign')); + xhr.send(JSON.stringify(params)); + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + if (xhr.status === 200) { + if (xhr.responseText) { + resolve(JSON.parse(xhr.responseText)); + } else { + resolve(); + } + } else { + reject('Error: ' + xhr.status); + } + } + }; + }); + }, + stream: function stream(url, data) { + var xhr = new XMLHttpRequest(); + xhr.open('post', url); + xhr.setRequestHeader('Content-Type', 'application/octet-stream'); + xhr.timeout = 15000; + xhr.send(data); + return new Promise(function (resolve) { + xhr.onload = function () { + resolve(xhr.response); + }; + }); + } + }; + + function commonjsRequire(path) { + throw new Error('Could not dynamically require "' + path + '". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.'); + } + + var localforage$1 = {exports: {}}; + + /*! + localForage -- Offline Storage, Improved + Version 1.10.0 + https://localforage.github.io/localForage + (c) 2013-2017 Mozilla, Apache License 2.0 + */ + (function (module, exports) { + (function (f) { + { + module.exports = f(); + } + })(function () { + return function e(t, n, r) { + function s(o, u) { + if (!n[o]) { + if (!t[o]) { + var a = typeof commonjsRequire == "function" && commonjsRequire; + if (!u && a) return a(o, !0); + if (i) return i(o, !0); + var f = new Error("Cannot find module '" + o + "'"); + throw f.code = "MODULE_NOT_FOUND", f; + } + var l = n[o] = { + exports: {} + }; + t[o][0].call(l.exports, function (e) { + var n = t[o][1][e]; + return s(n ? n : e); + }, l, l.exports, e, t, n, r); + } + return n[o].exports; + } + var i = typeof commonjsRequire == "function" && commonjsRequire; + for (var o = 0; o < r.length; o++) s(r[o]); + return s; + }({ + 1: [function (_dereq_, module, exports) { + (function (global) { + + var Mutation = global.MutationObserver || global.WebKitMutationObserver; + var scheduleDrain; + { + if (Mutation) { + var called = 0; + var observer = new Mutation(nextTick); + var element = global.document.createTextNode(''); + observer.observe(element, { + characterData: true + }); + scheduleDrain = function () { + element.data = called = ++called % 2; + }; + } else if (!global.setImmediate && typeof global.MessageChannel !== 'undefined') { + var channel = new global.MessageChannel(); + channel.port1.onmessage = nextTick; + scheduleDrain = function () { + channel.port2.postMessage(0); + }; + } else if ('document' in global && 'onreadystatechange' in global.document.createElement('script')) { + scheduleDrain = function () { + // Create a + + + + + + +
+ + + + + + \ No newline at end of file