FRE-600: Fix code review blockers

- Consolidated duplicate UndoManagers to single instance
- Fixed connection promise to only resolve on 'connected' status
- Fixed WebSocketProvider import (WebsocketProvider)
- Added proper doc.destroy() cleanup
- Renamed isPresenceInitialized property to avoid conflict

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
2026-04-25 00:08:01 -04:00
parent 65b552bb08
commit 7c684a42cc
48450 changed files with 5679671 additions and 383 deletions

70
node_modules/webrtc-adapter/.eslintrc generated vendored Normal file
View File

@@ -0,0 +1,70 @@
{
"rules": {
"array-bracket-spacing": 2,
"block-spacing": [2, "never"],
"brace-style": [2, "1tbs", {"allowSingleLine": false}],
"camelcase": [2, {"properties": "always"}],
"curly": 2,
"default-case": 2,
"dot-notation": 2,
"eqeqeq": 2,
"id-match": ["error", "^[\x00-\x7F]+$", {
"properties": true,
"onlyDeclarations": false,
"ignoreDestructuring": false
}],
"indent": [
2,
2,
{"SwitchCase": 1}
],
"key-spacing": [2, {"beforeColon": false, "afterColon": true}],
"keyword-spacing": 2,
"max-len": [2, 80, 2, {"ignoreUrls": true}],
"new-cap": [2, {"newIsCapExceptions": [
"webkitRTCPeerConnection",
"mozRTCPeerConnection"
]}],
"no-console": 0,
"no-else-return": 2,
"no-eval": 2,
"no-multi-spaces": 2,
"no-multiple-empty-lines": [2, {"max": 2}],
"no-shadow": 2,
"no-trailing-spaces": 2,
"no-unused-expressions": 2,
"no-unused-vars": [2, {"args": "none"}],
"object-curly-spacing": [2, "never"],
"padded-blocks": [2, "never"],
"quotes": [
2,
"single"
],
"semi": [
2,
"always"
],
"space-before-blocks": 2,
"space-before-function-paren": [2, "never"],
"space-unary-ops": 2,
"space-infix-ops": 2,
"spaced-comment": 2,
"valid-typeof": 2
},
"env": {
"browser": true,
"es6": true,
"node": true
},
"extends": ["eslint:recommended"],
"parserOptions": {
"sourceType": "module"
},
"globals": {
"module": true,
"require": true,
"process": true,
"Promise": true,
"Map": true
}
}

15
node_modules/webrtc-adapter/CONTRIBUTING.md generated vendored Normal file
View File

@@ -0,0 +1,15 @@
WebRTC welcomes patches/pulls for features and bug fixes.
For contributors external to Google, follow the instructions given in the [Google Individual Contributor License Agreement](https://cla.developers.google.com/about/google-individual).
In all cases, contributors must sign a contributor license agreement before a contribution can be accepted. Please complete the agreement for an [individual](https://developers.google.com/open-source/cla/individual) or a [corporation](https://developers.google.com/open-source/cla/corporate) as appropriate.
If you plan to add a significant component or large chunk of code, we recommend you bring this up on the [webrtc-discuss group](https://groups.google.com/forum/#!forum/discuss-webrtc) for a design discussion before writing code.
If appropriate, write a unit test which demonstrates that your code functions as expected. Tests are the best way to ensure that future contributors do not break your code accidentally.
To request a change or addition, you must [submit a pull request](https://help.github.com/categories/collaborating/).
WebRTC developers monitor outstanding pull requests. They may request changes to the pull request before accepting. They will also verify that a CLA has been signed.
The [Developer's Guide](https://bit.ly/webrtcdevguide) for this repo has more detailed information about code style, structure and validation.

65
node_modules/webrtc-adapter/Gruntfile.js generated vendored Normal file
View File

@@ -0,0 +1,65 @@
'use strict';
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
babel: {
options: {
presets: ['@babel/preset-env']
},
dist: {
files: [{
expand: 'true',
cwd: 'src/js',
src: ['*.js', '**/*.js'],
dest: 'dist/'
}]
}
},
browserify: {
adapterGlobalObject: {
src: ['./dist/adapter_core5.js'],
dest: './out/adapter.js',
options: {
browserifyOptions: {
// Exposes shim methods in a global object to the browser.
// The tests require this.
standalone: 'adapter'
}
}
},
// Use this if you do not want adapter to expose anything to the global
// scope.
adapterAndNoGlobalObject: {
src: ['./dist/adapter_core5.js'],
dest: './out/adapter_no_global.js'
}
},
eslint: {
options: {
overrideConfigFile: '.eslintrc'
},
target: ['src/**/*.js', 'test/*.js', 'test/unit/*.js', 'test/e2e/*.js']
},
copy: {
build: {
dest: 'release/',
cwd: 'out',
src: '**',
nonull: true,
expand: true
}
},
});
grunt.loadNpmTasks('grunt-eslint');
grunt.loadNpmTasks('grunt-browserify');
grunt.loadNpmTasks('grunt-babel');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.registerTask('default', ['eslint', 'build']);
grunt.registerTask('lint', ['eslint']);
grunt.registerTask('build', ['babel', 'browserify']);
grunt.registerTask('copyForPublish', ['copy']);
grunt.registerTask('downloadBrowser', ['shell:downloadBrowser'])
};

30
node_modules/webrtc-adapter/LICENSE.md generated vendored Normal file
View File

@@ -0,0 +1,30 @@
Copyright (c) 2014, The WebRTC project authors. All rights reserved.
Copyright (c) 2018, The adapter.js project authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Google nor the names of its contributors may
be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

80
node_modules/webrtc-adapter/README.md generated vendored Normal file
View File

@@ -0,0 +1,80 @@
# WebRTC adapter #
adapter.js is a shim to insulate apps from spec changes and prefix differences in WebRTC. The prefix differences are mostly gone these days but differences in behaviour between browsers remain.
This repository used to be part of the WebRTC organisation on github but moved. We aim to keep the old repository updated with new releases.
## Install ##
#### NPM
```bash
npm install webrtc-adapter
```
#### Bower
```bash
bower install webrtc-adapter
```
## Usage ##
##### Javascript
Just import adapter:
```
import adapter from 'webrtc-adapter';
```
No further action is required. You might want to use adapters browser detection
which detects which webrtc quirks are required. You can look at
```
adapter.browserDetails.browser
```
for webrtc engine detection (which will for example detect Opera or the Chromium based Edge as 'chrome') and
```
adapter.browserDetails.version
```
for the version according to the user-agent string.
##### NPM
Copy to desired location in your src tree or use a minify/vulcanize tool (node_modules is usually not published with the code).
See [webrtc/samples repo](https://github.com/webrtc/samples) as an example on how you can do this.
#### Prebuilt releases
##### Web
In the [gh-pages branch](https://github.com/webrtcHacks/adapter/tree/gh-pages) prebuilt ready to use files can be downloaded/linked directly.
Latest version can be found at https://webrtc.github.io/adapter/adapter-latest.js.
Specific versions can be found at https://webrtc.github.io/adapter/adapter-N.N.N.js, e.g. https://webrtc.github.io/adapter/adapter-1.0.2.js.
##### Bower
You will find `adapter.js` in `bower_components/webrtc-adapter/`.
##### NPM
In node_modules/webrtc-adapter/out/ folder you will find 4 files:
* `adapter.js` - includes all the shims and is visible in the browser under the global `adapter` object (window.adapter).
* `adapter_no_global.js` - same as `adapter.js` but is not exposed/visible in the browser (you cannot call/interact with the shims in the browser).
Include the file that suits your need in your project.
## Development ##
Head over to [test/README.md](https://github.com/webrtcHacks/adapter/blob/master/test/README.md) and get started developing.
## Publish a new version ##
* Go to the adapter repository root directory
* Make sure your repository is clean, i.e. no untracked files etc. Also check that you are on the master branch and have pulled the latest changes.
* Depending on the impact of the release, either use `patch`, `minor` or `major` in place of `<version>`. Run `npm version <version> -m 'bump to %s'` and type in your password lots of times (setting up credential caching is probably a good idea).
* Create and merge the PR if green in the GitHub web ui
* Go to the releases tab in the GitHub web ui and edit the tag.
* Add a summary of the recent commits in the tag summary and a link to the diff between the previous and current version in the description, [example](https://github.com/webrtcHacks/adapter/releases/tag/v3.4.1).
* Go back to your checkout and run `git pull`
* Run `npm publish` (you need access to the [webrtc-adapter npmjs package](https://www.npmjs.com/package/webrtc-adapter)). For big changes, consider using a [tag version](https://docs.npmjs.com/adding-dist-tags-to-packages) such as `next` and then [change the dist-tag after testing](https://docs.npmjs.com/cli/dist-tag).
* Done! There should now be a new release published to NPM and the gh-pages branch.
Note: Currently only tested on Linux, not sure about Mac but will definitely not work on Windows.
### Publish a hotfix patch versions
In some cases it may be necessary to do a patch version while there are significant changes changes on the master branch.
To make a patch release,
* checkout the latest git tag using `git checkout tags/vMajor.minor.patch`.
* checkout a new branch, using a name such as patchrelease-major-minor-patch.
* cherry-pick the fixes using `git cherry-pick some-commit-hash`.
* run `npm version patch`. This will create a new patch version and publish it on github.
* check out `origin/bumpVersion` branch and publish the new version using `npm publish`.
* the branch can now safely be deleted. It is not necessary to merge it into the main branch since it only contains cherry-picked commits.
* after publishing a hotfiix use `npm dist-tag` to ensure latest still points to the highest version.

25
node_modules/webrtc-adapter/bower.json generated vendored Normal file
View File

@@ -0,0 +1,25 @@
{
"name": "webrtc-adapter",
"description": "A shim to insulate apps from WebRTC spec changes and browser prefix differences",
"license": "BSD-3-Clause",
"main": "./release/adapter.js",
"repository": {
"type": "git",
"url": "https://github.com/webrtchacks/adapter.git"
},
"authors": [
"The WebRTC project authors (https://www.webrtc.org/)",
"The adapter.js project authors (https://github.com/webrtchacks/adapter/)"
],
"moduleType": [
"node"
],
"ignore": [
"test/*"
],
"keywords": [
"WebRTC",
"RTCPeerConnection",
"getUserMedia"
]
}

20
node_modules/webrtc-adapter/dist/adapter_core.js generated vendored Normal file
View File

@@ -0,0 +1,20 @@
/*
* 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 */
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
var _adapter_factory = require("./adapter_factory.js");
var adapter = (0, _adapter_factory.adapterFactory)({
window: typeof window === 'undefined' ? undefined : window
});
var _default = exports["default"] = adapter;

16
node_modules/webrtc-adapter/dist/adapter_core5.js generated vendored Normal file
View File

@@ -0,0 +1,16 @@
/*
* 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 */
'use strict';
var _adapter_factory = require("./adapter_factory.js");
var adapter = (0, _adapter_factory.adapterFactory)({
window: typeof window === 'undefined' ? undefined : window
});
module.exports = adapter; // this is the difference from adapter_core.

140
node_modules/webrtc-adapter/dist/adapter_factory.js generated vendored Normal file
View File

@@ -0,0 +1,140 @@
"use strict";
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.adapterFactory = adapterFactory;
var utils = _interopRequireWildcard(require("./utils"));
var chromeShim = _interopRequireWildcard(require("./chrome/chrome_shim"));
var firefoxShim = _interopRequireWildcard(require("./firefox/firefox_shim"));
var safariShim = _interopRequireWildcard(require("./safari/safari_shim"));
var commonShim = _interopRequireWildcard(require("./common_shim"));
var sdp = _interopRequireWildcard(require("sdp"));
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, "default": e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
/*
* 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.
*/
// Browser shims.
// Shimming starts here.
function adapterFactory() {
var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
window = _ref.window;
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {
shimChrome: true,
shimFirefox: true,
shimSafari: true
};
// Utils.
var logging = utils.log;
var browserDetails = utils.detectBrowser(window);
var adapter = {
browserDetails: browserDetails,
commonShim: commonShim,
extractVersion: utils.extractVersion,
disableLog: utils.disableLog,
disableWarnings: utils.disableWarnings,
// Expose sdp as a convenience. For production apps include directly.
sdp: sdp
};
// Shim browser if found.
switch (browserDetails.browser) {
case 'chrome':
if (!chromeShim || !chromeShim.shimPeerConnection || !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.
commonShim.shimAddIceCandidateNullOrEmpty(window, browserDetails);
commonShim.shimParameterlessSetLocalDescription(window, browserDetails);
chromeShim.shimGetUserMedia(window, browserDetails);
chromeShim.shimMediaStream(window, browserDetails);
chromeShim.shimPeerConnection(window, browserDetails);
chromeShim.shimOnTrack(window, browserDetails);
chromeShim.shimAddTrackRemoveTrack(window, browserDetails);
chromeShim.shimGetSendersWithDtmf(window, browserDetails);
chromeShim.shimSenderReceiverGetStats(window, browserDetails);
chromeShim.fixNegotiationNeeded(window, browserDetails);
commonShim.shimRTCIceCandidate(window, browserDetails);
commonShim.shimRTCIceCandidateRelayProtocol(window, browserDetails);
commonShim.shimConnectionState(window, browserDetails);
commonShim.shimMaxMessageSize(window, browserDetails);
commonShim.shimSendThrowTypeError(window, browserDetails);
commonShim.removeExtmapAllowMixed(window, browserDetails);
break;
case 'firefox':
if (!firefoxShim || !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.
commonShim.shimAddIceCandidateNullOrEmpty(window, browserDetails);
commonShim.shimParameterlessSetLocalDescription(window, browserDetails);
firefoxShim.shimGetUserMedia(window, browserDetails);
firefoxShim.shimPeerConnection(window, browserDetails);
firefoxShim.shimGetStats(window, browserDetails);
firefoxShim.shimOnTrack(window, browserDetails);
firefoxShim.shimRemoveStream(window, browserDetails);
firefoxShim.shimSenderGetStats(window, browserDetails);
firefoxShim.shimReceiverGetStats(window, browserDetails);
firefoxShim.shimRTCDataChannel(window, browserDetails);
firefoxShim.shimAddTransceiver(window, browserDetails);
firefoxShim.shimGetParameters(window, browserDetails);
firefoxShim.shimCreateOffer(window, browserDetails);
firefoxShim.shimCreateAnswer(window, browserDetails);
commonShim.shimRTCIceCandidate(window, browserDetails);
commonShim.shimConnectionState(window, browserDetails);
commonShim.shimMaxMessageSize(window, browserDetails);
commonShim.shimSendThrowTypeError(window, browserDetails);
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.
commonShim.shimAddIceCandidateNullOrEmpty(window, browserDetails);
commonShim.shimParameterlessSetLocalDescription(window, browserDetails);
safariShim.shimRTCIceServerUrls(window, browserDetails);
safariShim.shimCreateOfferLegacy(window, browserDetails);
safariShim.shimCallbacksAPI(window, browserDetails);
safariShim.shimLocalStreamsAPI(window, browserDetails);
safariShim.shimRemoteStreamsAPI(window, browserDetails);
safariShim.shimTrackEventTransceiver(window, browserDetails);
safariShim.shimGetUserMedia(window, browserDetails);
safariShim.shimAudioContext(window, browserDetails);
commonShim.shimRTCIceCandidate(window, browserDetails);
commonShim.shimRTCIceCandidateRelayProtocol(window, browserDetails);
commonShim.shimMaxMessageSize(window, browserDetails);
commonShim.shimSendThrowTypeError(window, browserDetails);
commonShim.removeExtmapAllowMixed(window, browserDetails);
break;
default:
logging('Unsupported browser!');
break;
}
return adapter;
}

635
node_modules/webrtc-adapter/dist/chrome/chrome_shim.js generated vendored Normal file
View File

@@ -0,0 +1,635 @@
/*
* 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 */
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.fixNegotiationNeeded = fixNegotiationNeeded;
exports.shimAddTrackRemoveTrack = shimAddTrackRemoveTrack;
exports.shimAddTrackRemoveTrackWithNative = shimAddTrackRemoveTrackWithNative;
exports.shimGetSendersWithDtmf = shimGetSendersWithDtmf;
Object.defineProperty(exports, "shimGetUserMedia", {
enumerable: true,
get: function get() {
return _getusermedia.shimGetUserMedia;
}
});
exports.shimMediaStream = shimMediaStream;
exports.shimOnTrack = shimOnTrack;
exports.shimPeerConnection = shimPeerConnection;
exports.shimSenderReceiverGetStats = shimSenderReceiverGetStats;
var utils = _interopRequireWildcard(require("../utils.js"));
var _getusermedia = require("./getusermedia");
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, "default": e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function shimMediaStream(window) {
window.MediaStream = window.MediaStream || window.webkitMediaStream;
}
function shimOnTrack(window, browserDetails) {
if (browserDetails.version > 102) {
// Unified plan is supported so no need to do anything.
return;
}
if (_typeof(window) === 'object' && window.RTCPeerConnection && !('ontrack' in window.RTCPeerConnection.prototype)) {
Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', {
get: function get() {
return this._ontrack;
},
set: function set(f) {
if (this._ontrack) {
this.removeEventListener('track', this._ontrack);
}
this.addEventListener('track', this._ontrack = f);
},
enumerable: true,
configurable: true
});
var origSetRemoteDescription = window.RTCPeerConnection.prototype.setRemoteDescription;
window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription() {
var _this = this;
if (!this._ontrackpoly) {
this._ontrackpoly = function (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', function (te) {
var receiver;
if (window.RTCPeerConnection.prototype.getReceivers) {
receiver = _this.getReceivers().find(function (r) {
return r.track && r.track.id === te.track.id;
});
} else {
receiver = {
track: te.track
};
}
var event = new Event('track');
event.track = te.track;
event.receiver = receiver;
event.transceiver = {
receiver: receiver
};
event.streams = [e.stream];
_this.dispatchEvent(event);
});
e.stream.getTracks().forEach(function (track) {
var receiver;
if (window.RTCPeerConnection.prototype.getReceivers) {
receiver = _this.getReceivers().find(function (r) {
return r.track && r.track.id === track.id;
});
} else {
receiver = {
track: track
};
}
var event = new Event('track');
event.track = track;
event.receiver = receiver;
event.transceiver = {
receiver: 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.
utils.wrapPeerConnectionEvent(window, 'track', function (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) {
var shimSenderWithDtmf = function shimSenderWithDtmf(pc, track) {
return {
track: 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.
};
var origAddTrack = window.RTCPeerConnection.prototype.addTrack;
window.RTCPeerConnection.prototype.addTrack = function addTrack(track, stream) {
var sender = origAddTrack.apply(this, arguments);
if (!sender) {
sender = shimSenderWithDtmf(this, track);
this._senders.push(sender);
}
return sender;
};
var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack;
window.RTCPeerConnection.prototype.removeTrack = function removeTrack(sender) {
origRemoveTrack.apply(this, arguments);
var idx = this._senders.indexOf(sender);
if (idx !== -1) {
this._senders.splice(idx, 1);
}
};
}
var origAddStream = window.RTCPeerConnection.prototype.addStream;
window.RTCPeerConnection.prototype.addStream = function addStream(stream) {
var _this2 = this;
this._senders = this._senders || [];
origAddStream.apply(this, [stream]);
stream.getTracks().forEach(function (track) {
_this2._senders.push(shimSenderWithDtmf(_this2, track));
});
};
var origRemoveStream = window.RTCPeerConnection.prototype.removeStream;
window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) {
var _this3 = this;
this._senders = this._senders || [];
origRemoveStream.apply(this, [stream]);
stream.getTracks().forEach(function (track) {
var sender = _this3._senders.find(function (s) {
return s.track === track;
});
if (sender) {
// remove sender
_this3._senders.splice(_this3._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)) {
var origGetSenders = window.RTCPeerConnection.prototype.getSenders;
window.RTCPeerConnection.prototype.getSenders = function getSenders() {
var _this4 = this;
var senders = origGetSenders.apply(this, []);
senders.forEach(function (sender) {
return sender._pc = _this4;
});
return senders;
};
Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', {
get: function 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 shimSenderReceiverGetStats(window, browserDetails) {
if (browserDetails.version >= 67) {
return;
}
if (!(_typeof(window) === 'object' && window.RTCPeerConnection && window.RTCRtpSender && window.RTCRtpReceiver)) {
return;
}
// shim sender stats.
if (!('getStats' in window.RTCRtpSender.prototype)) {
var origGetSenders = window.RTCPeerConnection.prototype.getSenders;
if (origGetSenders) {
window.RTCPeerConnection.prototype.getSenders = function getSenders() {
var _this5 = this;
var senders = origGetSenders.apply(this, []);
senders.forEach(function (sender) {
return sender._pc = _this5;
});
return senders;
};
}
var origAddTrack = window.RTCPeerConnection.prototype.addTrack;
if (origAddTrack) {
window.RTCPeerConnection.prototype.addTrack = function addTrack() {
var sender = origAddTrack.apply(this, arguments);
sender._pc = this;
return sender;
};
}
window.RTCRtpSender.prototype.getStats = function getStats() {
var sender = this;
return this._pc.getStats().then(function (result) {
return (
/* 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.
*/
utils.filterStats(result, sender.track, true)
);
});
};
}
// shim receiver stats.
if (!('getStats' in window.RTCRtpReceiver.prototype)) {
var origGetReceivers = window.RTCPeerConnection.prototype.getReceivers;
if (origGetReceivers) {
window.RTCPeerConnection.prototype.getReceivers = function getReceivers() {
var _this6 = this;
var receivers = origGetReceivers.apply(this, []);
receivers.forEach(function (receiver) {
return receiver._pc = _this6;
});
return receivers;
};
}
utils.wrapPeerConnectionEvent(window, 'track', function (e) {
e.receiver._pc = e.srcElement;
return e;
});
window.RTCRtpReceiver.prototype.getStats = function getStats() {
var receiver = this;
return this._pc.getStats().then(function (result) {
return utils.filterStats(result, receiver.track, false);
});
};
}
if (!('getStats' in window.RTCRtpSender.prototype && 'getStats' in window.RTCRtpReceiver.prototype)) {
return;
}
// shim RTCPeerConnection.getStats(track).
var origGetStats = window.RTCPeerConnection.prototype.getStats;
window.RTCPeerConnection.prototype.getStats = function getStats() {
if (arguments.length > 0 && arguments[0] instanceof window.MediaStreamTrack) {
var track = arguments[0];
var sender;
var receiver;
var err;
this.getSenders().forEach(function (s) {
if (s.track === track) {
if (sender) {
err = true;
} else {
sender = s;
}
}
});
this.getReceivers().forEach(function (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() {
var _this7 = this;
this._shimmedLocalStreams = this._shimmedLocalStreams || {};
return Object.keys(this._shimmedLocalStreams).map(function (streamId) {
return _this7._shimmedLocalStreams[streamId][0];
});
};
var origAddTrack = window.RTCPeerConnection.prototype.addTrack;
window.RTCPeerConnection.prototype.addTrack = function addTrack(track, stream) {
if (!stream) {
return origAddTrack.apply(this, arguments);
}
this._shimmedLocalStreams = this._shimmedLocalStreams || {};
var 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;
};
var origAddStream = window.RTCPeerConnection.prototype.addStream;
window.RTCPeerConnection.prototype.addStream = function addStream(stream) {
var _this8 = this;
this._shimmedLocalStreams = this._shimmedLocalStreams || {};
stream.getTracks().forEach(function (track) {
var alreadyExists = _this8.getSenders().find(function (s) {
return s.track === track;
});
if (alreadyExists) {
throw new DOMException('Track already exists.', 'InvalidAccessError');
}
});
var existingSenders = this.getSenders();
origAddStream.apply(this, arguments);
var newSenders = this.getSenders().filter(function (newSender) {
return existingSenders.indexOf(newSender) === -1;
});
this._shimmedLocalStreams[stream.id] = [stream].concat(newSenders);
};
var 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);
};
var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack;
window.RTCPeerConnection.prototype.removeTrack = function removeTrack(sender) {
var _this9 = this;
this._shimmedLocalStreams = this._shimmedLocalStreams || {};
if (sender) {
Object.keys(this._shimmedLocalStreams).forEach(function (streamId) {
var idx = _this9._shimmedLocalStreams[streamId].indexOf(sender);
if (idx !== -1) {
_this9._shimmedLocalStreams[streamId].splice(idx, 1);
}
if (_this9._shimmedLocalStreams[streamId].length === 1) {
delete _this9._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.
var origGetLocalStreams = window.RTCPeerConnection.prototype.getLocalStreams;
window.RTCPeerConnection.prototype.getLocalStreams = function getLocalStreams() {
var _this0 = this;
var nativeStreams = origGetLocalStreams.apply(this);
this._reverseStreams = this._reverseStreams || {};
return nativeStreams.map(function (stream) {
return _this0._reverseStreams[stream.id];
});
};
var origAddStream = window.RTCPeerConnection.prototype.addStream;
window.RTCPeerConnection.prototype.addStream = function addStream(stream) {
var _this1 = this;
this._streams = this._streams || {};
this._reverseStreams = this._reverseStreams || {};
stream.getTracks().forEach(function (track) {
var alreadyExists = _this1.getSenders().find(function (s) {
return 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]) {
var newStream = new window.MediaStream(stream.getTracks());
this._streams[stream.id] = newStream;
this._reverseStreams[newStream.id] = stream;
stream = newStream;
}
origAddStream.apply(this, [stream]);
};
var 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) {
var _this10 = this;
if (this.signalingState === 'closed') {
throw new DOMException('The RTCPeerConnection\'s signalingState is \'closed\'.', 'InvalidStateError');
}
var streams = [].slice.call(arguments, 1);
if (streams.length !== 1 || !streams[0].getTracks().find(function (t) {
return 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');
}
var alreadyExists = this.getSenders().find(function (s) {
return s.track === track;
});
if (alreadyExists) {
throw new DOMException('Track already exists.', 'InvalidAccessError');
}
this._streams = this._streams || {};
this._reverseStreams = this._reverseStreams || {};
var 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(function () {
_this10.dispatchEvent(new Event('negotiationneeded'));
});
} else {
var newStream = new window.MediaStream([track]);
this._streams[stream.id] = newStream;
this._reverseStreams[newStream.id] = stream;
this.addStream(newStream);
}
return this.getSenders().find(function (s) {
return s.track === track;
});
};
// replace the internal stream id with the external one and
// vice versa.
function replaceInternalStreamId(pc, description) {
var sdp = description.sdp;
Object.keys(pc._reverseStreams || []).forEach(function (internalId) {
var externalStream = pc._reverseStreams[internalId];
var internalStream = pc._streams[externalStream.id];
sdp = sdp.replace(new RegExp(internalStream.id, 'g'), externalStream.id);
});
return new RTCSessionDescription({
type: description.type,
sdp: sdp
});
}
function replaceExternalStreamId(pc, description) {
var sdp = description.sdp;
Object.keys(pc._reverseStreams || []).forEach(function (internalId) {
var externalStream = pc._reverseStreams[internalId];
var internalStream = pc._streams[externalStream.id];
sdp = sdp.replace(new RegExp(externalStream.id, 'g'), internalStream.id);
});
return new RTCSessionDescription({
type: description.type,
sdp: sdp
});
}
['createOffer', 'createAnswer'].forEach(function (method) {
var nativeMethod = window.RTCPeerConnection.prototype[method];
var methodObj = _defineProperty({}, method, function () {
var _this11 = this;
var args = arguments;
var isLegacyCall = arguments.length && typeof arguments[0] === 'function';
if (isLegacyCall) {
return nativeMethod.apply(this, [function (description) {
var desc = replaceInternalStreamId(_this11, description);
args[0].apply(null, [desc]);
}, function (err) {
if (args[1]) {
args[1].apply(null, err);
}
}, arguments[2]]);
}
return nativeMethod.apply(this, arguments).then(function (description) {
return replaceInternalStreamId(_this11, description);
});
});
window.RTCPeerConnection.prototype[method] = methodObj[method];
});
var 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
var origLocalDescription = Object.getOwnPropertyDescriptor(window.RTCPeerConnection.prototype, 'localDescription');
Object.defineProperty(window.RTCPeerConnection.prototype, 'localDescription', {
get: function get() {
var description = origLocalDescription.get.apply(this);
if (description.type === '') {
return description;
}
return replaceInternalStreamId(this, description);
}
});
window.RTCPeerConnection.prototype.removeTrack = function removeTrack(sender) {
var _this12 = this;
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');
}
var 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 || {};
var stream;
Object.keys(this._streams).forEach(function (streamid) {
var hasTrack = _this12._streams[streamid].getTracks().find(function (track) {
return sender.track === track;
});
if (hasTrack) {
stream = _this12._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(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) {
var nativeMethod = window.RTCPeerConnection.prototype[method];
var methodObj = _defineProperty({}, method, function () {
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) {
if (browserDetails.version > 102) {
// Plan-B is no longer supported.
return;
}
utils.wrapPeerConnectionEvent(window, 'negotiationneeded', function (e) {
var pc = e.target;
if (browserDetails.version < 72 || pc.getConfiguration && pc.getConfiguration().sdpSemantics === 'plan-b') {
if (pc.signalingState !== 'stable') {
return;
}
}
return e;
});
}

197
node_modules/webrtc-adapter/dist/chrome/getusermedia.js generated vendored Normal file
View File

@@ -0,0 +1,197 @@
/*
* 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 */
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.shimGetUserMedia = shimGetUserMedia;
var utils = _interopRequireWildcard(require("../utils.js"));
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, "default": e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
var logging = utils.log;
function shimGetUserMedia(window, browserDetails) {
var navigator = window && window.navigator;
if (!navigator.mediaDevices) {
return;
}
var constraintsToChrome_ = function constraintsToChrome_(c) {
if (_typeof(c) !== 'object' || c.mandatory || c.optional) {
return c;
}
var cc = {};
Object.keys(c).forEach(function (key) {
if (key === 'require' || key === 'advanced' || key === 'mediaSource') {
return;
}
var r = _typeof(c[key]) === 'object' ? c[key] : {
ideal: c[key]
};
if (r.exact !== undefined && typeof r.exact === 'number') {
r.min = r.max = r.exact;
}
var oldname_ = function oldname_(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 || [];
var 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(function (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;
};
var shimConstraints_ = function shimConstraints_(constraints, func) {
if (browserDetails.version >= 61) {
return func(constraints);
}
constraints = JSON.parse(JSON.stringify(constraints));
if (constraints && _typeof(constraints.audio) === 'object') {
var remap = function remap(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.
var face = constraints.video.facingMode;
face = face && (_typeof(face) === 'object' ? face : {
ideal: face
});
var 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;
var 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(function (devices) {
devices = devices.filter(function (d) {
return d.kind === 'videoinput';
});
var dev = devices.find(function (d) {
return matches.some(function (match) {
return 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);
};
var shimError_ = function shimError_(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: function toString() {
return this.name + (this.message && ': ') + this.message;
}
};
};
var getUserMedia_ = function getUserMedia_(constraints, onSuccess, onError) {
shimConstraints_(constraints, function (c) {
navigator.webkitGetUserMedia(c, onSuccess, function (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) {
var origGetUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);
navigator.mediaDevices.getUserMedia = function (cs) {
return shimConstraints_(cs, function (c) {
return origGetUserMedia(c).then(function (stream) {
if (c.audio && !stream.getAudioTracks().length || c.video && !stream.getVideoTracks().length) {
stream.getTracks().forEach(function (track) {
track.stop();
});
throw new DOMException('', 'NotFoundError');
}
return stream;
}, function (e) {
return Promise.reject(shimError_(e));
});
});
};
}
}

441
node_modules/webrtc-adapter/dist/common_shim.js generated vendored Normal file
View File

@@ -0,0 +1,441 @@
/*
* 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 */
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.removeExtmapAllowMixed = removeExtmapAllowMixed;
exports.shimAddIceCandidateNullOrEmpty = shimAddIceCandidateNullOrEmpty;
exports.shimConnectionState = shimConnectionState;
exports.shimMaxMessageSize = shimMaxMessageSize;
exports.shimParameterlessSetLocalDescription = shimParameterlessSetLocalDescription;
exports.shimRTCIceCandidate = shimRTCIceCandidate;
exports.shimRTCIceCandidateRelayProtocol = shimRTCIceCandidateRelayProtocol;
exports.shimSendThrowTypeError = shimSendThrowTypeError;
var _sdp = _interopRequireDefault(require("sdp"));
var utils = _interopRequireWildcard(require("./utils"));
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, "default": e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
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;
}
var 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.
var nativeCandidate = new NativeRTCIceCandidate(args);
var parsedCandidate = _sdp["default"].parseCandidate(args.candidate);
for (var 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', ...)
utils.wrapPeerConnectionEvent(window, 'icecandidate', function (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', ...)
utils.wrapPeerConnectionEvent(window, 'icecandidate', function (e) {
if (e.candidate) {
var parsedCandidate = _sdp["default"].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: function get() {
return typeof this._sctp === 'undefined' ? null : this._sctp;
}
});
}
var sctpInDescription = function sctpInDescription(description) {
if (!description || !description.sdp) {
return false;
}
var sections = _sdp["default"].splitSections(description.sdp);
sections.shift();
return sections.some(function (mediaSection) {
var mLine = _sdp["default"].parseMLine(mediaSection);
return mLine && mLine.kind === 'application' && mLine.protocol.indexOf('SCTP') !== -1;
});
};
var getRemoteFirefoxVersion = function getRemoteFirefoxVersion(description) {
// TODO: Is there a better solution for detecting Firefox?
var match = description.sdp.match(/mozilla...THIS_IS_SDPARTA-(\d+)/);
if (match === null || match.length < 2) {
return -1;
}
var version = parseInt(match[1], 10);
// Test for NaN (yes, this is ugly)
return version !== version ? -1 : version;
};
var getCanSendMaxMessageSize = function getCanSendMaxMessageSize(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
var 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;
};
var getMaxMessageSize = function getMaxMessageSize(description, remoteIsFirefox) {
// Note: 65536 bytes is the default value from the SDP spec. Also,
// every implementation we know supports receiving 65536 bytes.
var 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;
}
var match = _sdp["default"].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;
};
var 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) {
var _this$getConfiguratio = this.getConfiguration(),
sdpSemantics = _this$getConfiguratio.sdpSemantics;
if (sdpSemantics === 'plan-b') {
Object.defineProperty(this, 'sctp', {
get: function get() {
return typeof this._sctp === 'undefined' ? null : this._sctp;
},
enumerable: true,
configurable: true
});
}
}
if (sctpInDescription(arguments[0])) {
// Check if the remote is FF.
var isFirefox = getRemoteFirefoxVersion(arguments[0]);
// Get the maximum message size the local peer is capable of sending
var canSendMMS = getCanSendMaxMessageSize(isFirefox);
// Get the maximum message size of the remote peer.
var remoteMMS = getMaxMessageSize(arguments[0], isFirefox);
// Determine final maximum message size
var 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.
var sctp = {};
Object.defineProperty(sctp, 'maxMessageSize', {
get: function get() {
return maxMessageSize;
}
});
this._sctp = sctp;
}
return origSetRemoteDescription.apply(this, arguments);
};
}
function shimSendThrowTypeError(window, browserDetails) {
if (!(window.RTCPeerConnection && 'createDataChannel' in window.RTCPeerConnection.prototype)) {
return;
}
if (browserDetails.browser === 'chrome' && browserDetails.version > 149) {
// Fixed by https://issues.chromium.org/issues/490588131
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
if (browserDetails.browser === 'firefox' && browserDetails.version > 60) {
return;
}
function wrapDcSend(dc, pc) {
var origDataChannelSend = dc.send;
dc.send = function send() {
var data = arguments[0];
var 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);
};
}
var origCreateDataChannel = window.RTCPeerConnection.prototype.createDataChannel;
window.RTCPeerConnection.prototype.createDataChannel = function createDataChannel() {
var dataChannel = origCreateDataChannel.apply(this, arguments);
wrapDcSend(dataChannel, this);
return dataChannel;
};
utils.wrapPeerConnectionEvent(window, 'datachannel', function (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;
}
var proto = window.RTCPeerConnection.prototype;
Object.defineProperty(proto, 'connectionState', {
get: function get() {
return {
completed: 'connected',
checking: 'connecting'
}[this.iceConnectionState] || this.iceConnectionState;
},
enumerable: true,
configurable: true
});
Object.defineProperty(proto, 'onconnectionstatechange', {
get: function get() {
return this._onconnectionstatechange || null;
},
set: function 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(function (method) {
var origMethod = proto[method];
proto[method] = function () {
if (!this._connectionstatechangepoly) {
this._connectionstatechangepoly = function (e) {
var pc = e.target;
if (pc._lastConnectionState !== pc.connectionState) {
pc._lastConnectionState = pc.connectionState;
var 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._safariVersion >= 13.1) {
return;
}
var nativeSRD = window.RTCPeerConnection.prototype.setRemoteDescription;
window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription(desc) {
if (desc && desc.sdp && desc.sdp.indexOf('\na=extmap-allow-mixed') !== -1) {
var sdp = desc.sdp.split('\n').filter(function (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: 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;
}
var 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;
}
var nativeSetLocalDescription = window.RTCPeerConnection.prototype.setLocalDescription;
if (!nativeSetLocalDescription || nativeSetLocalDescription.length === 0) {
return;
}
window.RTCPeerConnection.prototype.setLocalDescription = function setLocalDescription() {
var _this = this;
var 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]);
}
var func = desc.type === 'offer' ? this.createOffer : this.createAnswer;
return func.apply(this).then(function (d) {
return nativeSetLocalDescription.apply(_this, [d]);
});
};
}

View File

@@ -0,0 +1,330 @@
/*
* 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 */
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.shimAddTransceiver = shimAddTransceiver;
exports.shimCreateAnswer = shimCreateAnswer;
exports.shimCreateOffer = shimCreateOffer;
Object.defineProperty(exports, "shimGetDisplayMedia", {
enumerable: true,
get: function get() {
return _getdisplaymedia.shimGetDisplayMedia;
}
});
exports.shimGetParameters = shimGetParameters;
exports.shimGetStats = shimGetStats;
Object.defineProperty(exports, "shimGetUserMedia", {
enumerable: true,
get: function get() {
return _getusermedia.shimGetUserMedia;
}
});
exports.shimOnTrack = shimOnTrack;
exports.shimPeerConnection = shimPeerConnection;
exports.shimRTCDataChannel = shimRTCDataChannel;
exports.shimReceiverGetStats = shimReceiverGetStats;
exports.shimRemoveStream = shimRemoveStream;
exports.shimSenderGetStats = shimSenderGetStats;
var utils = _interopRequireWildcard(require("../utils"));
var _getusermedia = require("./getusermedia");
var _getdisplaymedia = require("./getdisplaymedia");
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, "default": e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
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: function 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) {
var nativeMethod = window.RTCPeerConnection.prototype[method];
var methodObj = _defineProperty({}, method, function () {
arguments[0] = new (method === 'addIceCandidate' ? window.RTCIceCandidate : window.RTCSessionDescription)(arguments[0]);
return nativeMethod.apply(this, arguments);
});
window.RTCPeerConnection.prototype[method] = methodObj[method];
});
}
}
function shimGetStats(window, browserDetails) {
if (_typeof(window) !== 'object' || !(window.RTCPeerConnection || window.mozRTCPeerConnection)) {
return; // probably media.peerconnection.enabled=false in about:config
}
if (browserDetails.version >= 151) {
// https://bugzilla.mozilla.org/show_bug.cgi?id=1056433
return;
}
var modernStatsTypes = {
inboundrtp: 'inbound-rtp',
outboundrtp: 'outbound-rtp',
candidatepair: 'candidate-pair',
localcandidate: 'local-candidate',
remotecandidate: 'remote-candidate'
};
var nativeGetStats = window.RTCPeerConnection.prototype.getStats;
window.RTCPeerConnection.prototype.getStats = function getStats() {
var _arguments = Array.prototype.slice.call(arguments),
selector = _arguments[0],
onSucc = _arguments[1],
onErr = _arguments[2];
if (this.signalingState === 'closed') {
// No longer required in FF151+
return Promise.resolve(new Map());
}
return nativeGetStats.apply(this, [selector || null]).then(function (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(function (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(function (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;
}
var origGetSenders = window.RTCPeerConnection.prototype.getSenders;
if (origGetSenders) {
window.RTCPeerConnection.prototype.getSenders = function getSenders() {
var _this = this;
var senders = origGetSenders.apply(this, []);
senders.forEach(function (sender) {
return sender._pc = _this;
});
return senders;
};
}
var origAddTrack = window.RTCPeerConnection.prototype.addTrack;
if (origAddTrack) {
window.RTCPeerConnection.prototype.addTrack = function addTrack() {
var 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;
}
var origGetReceivers = window.RTCPeerConnection.prototype.getReceivers;
if (origGetReceivers) {
window.RTCPeerConnection.prototype.getReceivers = function getReceivers() {
var _this2 = this;
var receivers = origGetReceivers.apply(this, []);
receivers.forEach(function (receiver) {
return receiver._pc = _this2;
});
return receivers;
};
}
utils.wrapPeerConnectionEvent(window, 'track', function (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) {
var _this3 = this;
utils.deprecated('removeStream', 'removeTrack');
this.getSenders().forEach(function (sender) {
if (sender.track && stream.getTracks().includes(sender.track)) {
_this3.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;
}
var origAddTransceiver = window.RTCPeerConnection.prototype.addTransceiver;
if (origAddTransceiver) {
window.RTCPeerConnection.prototype.addTransceiver = function addTransceiver() {
this.setParametersPromises = [];
// WebIDL input coercion and validation
var sendEncodings = arguments[1] && arguments[1].sendEncodings;
if (sendEncodings === undefined) {
sendEncodings = [];
}
sendEncodings = _toConsumableArray(sendEncodings);
var shouldPerformCheck = sendEncodings.length > 0;
if (shouldPerformCheck) {
// If sendEncodings params are provided, validate grammar
sendEncodings.forEach(function (encodingParam) {
if ('rid' in encodingParam) {
var 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');
}
}
});
}
var 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.
var sender = transceiver.sender;
var 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(function () {
delete sender.sendEncodings;
})["catch"](function () {
delete sender.sendEncodings;
}));
}
}
return transceiver;
};
}
}
function shimGetParameters(window) {
if (!(_typeof(window) === 'object' && window.RTCRtpSender)) {
return;
}
var origGetParameters = window.RTCRtpSender.prototype.getParameters;
if (origGetParameters) {
window.RTCRtpSender.prototype.getParameters = function getParameters() {
var 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;
}
var origCreateOffer = window.RTCPeerConnection.prototype.createOffer;
window.RTCPeerConnection.prototype.createOffer = function createOffer() {
var _arguments2 = arguments,
_this4 = this;
if (this.setParametersPromises && this.setParametersPromises.length) {
return Promise.all(this.setParametersPromises).then(function () {
return origCreateOffer.apply(_this4, _arguments2);
})["finally"](function () {
_this4.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;
}
var origCreateAnswer = window.RTCPeerConnection.prototype.createAnswer;
window.RTCPeerConnection.prototype.createAnswer = function createAnswer() {
var _arguments3 = arguments,
_this5 = this;
if (this.setParametersPromises && this.setParametersPromises.length) {
return Promise.all(this.setParametersPromises).then(function () {
return origCreateAnswer.apply(_this5, _arguments3);
})["finally"](function () {
_this5.setParametersPromises = [];
});
}
return origCreateAnswer.apply(this, arguments);
};
}

View File

@@ -0,0 +1,39 @@
/*
* 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 */
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.shimGetDisplayMedia = shimGetDisplayMedia;
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)) {
var 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);
};
}

View File

@@ -0,0 +1,63 @@
/*
* 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 */
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.shimGetUserMedia = shimGetUserMedia;
var utils = _interopRequireWildcard(require("../utils"));
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, "default": e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function shimGetUserMedia(window, browserDetails) {
var navigator = window && window.navigator;
var MediaStreamTrack = window && window.MediaStreamTrack;
navigator.getUserMedia = function (constraints, onSuccess, onError) {
// Replace Firefox 44+'s deprecation warning with unprefixed version.
utils.deprecated('navigator.getUserMedia', 'navigator.mediaDevices.getUserMedia');
navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError);
};
if (!(browserDetails.version > 55 && 'autoGainControl' in navigator.mediaDevices.getSupportedConstraints())) {
var remap = function remap(obj, a, b) {
if (a in obj && !(b in obj)) {
obj[b] = obj[a];
delete obj[a];
}
};
var 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) {
var nativeGetSettings = MediaStreamTrack.prototype.getSettings;
MediaStreamTrack.prototype.getSettings = function () {
var obj = nativeGetSettings.apply(this, arguments);
remap(obj, 'mozAutoGainControl', 'autoGainControl');
remap(obj, 'mozNoiseSuppression', 'noiseSuppression');
return obj;
};
}
if (MediaStreamTrack && MediaStreamTrack.prototype.applyConstraints) {
var 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]);
};
}
}
}

345
node_modules/webrtc-adapter/dist/safari/safari_shim.js generated vendored Normal file
View File

@@ -0,0 +1,345 @@
/*
* 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.
*/
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.shimAudioContext = shimAudioContext;
exports.shimCallbacksAPI = shimCallbacksAPI;
exports.shimConstraints = shimConstraints;
exports.shimCreateOfferLegacy = shimCreateOfferLegacy;
exports.shimGetUserMedia = shimGetUserMedia;
exports.shimLocalStreamsAPI = shimLocalStreamsAPI;
exports.shimRTCIceServerUrls = shimRTCIceServerUrls;
exports.shimRemoteStreamsAPI = shimRemoteStreamsAPI;
exports.shimTrackEventTransceiver = shimTrackEventTransceiver;
var utils = _interopRequireWildcard(require("../utils"));
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, "default": e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
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)) {
var _addTrack = window.RTCPeerConnection.prototype.addTrack;
window.RTCPeerConnection.prototype.addStream = function addStream(stream) {
var _this = this;
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(function (track) {
return _addTrack.call(_this, track, stream);
});
stream.getVideoTracks().forEach(function (track) {
return _addTrack.call(_this, track, stream);
});
};
window.RTCPeerConnection.prototype.addTrack = function addTrack(track) {
var _this2 = this;
for (var _len = arguments.length, streams = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
streams[_key - 1] = arguments[_key];
}
if (streams) {
streams.forEach(function (stream) {
if (!_this2._localStreams) {
_this2._localStreams = [stream];
} else if (!_this2._localStreams.includes(stream)) {
_this2._localStreams.push(stream);
}
});
}
return _addTrack.apply(this, arguments);
};
}
if (!('removeStream' in window.RTCPeerConnection.prototype)) {
window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) {
var _this3 = this;
if (!this._localStreams) {
this._localStreams = [];
}
var index = this._localStreams.indexOf(stream);
if (index === -1) {
return;
}
this._localStreams.splice(index, 1);
var tracks = stream.getTracks();
this.getSenders().forEach(function (sender) {
if (tracks.includes(sender.track)) {
_this3.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: function get() {
return this._onaddstream;
},
set: function set(f) {
var _this4 = this;
if (this._onaddstream) {
this.removeEventListener('addstream', this._onaddstream);
this.removeEventListener('track', this._onaddstreampoly);
}
this.addEventListener('addstream', this._onaddstream = f);
this.addEventListener('track', this._onaddstreampoly = function (e) {
e.streams.forEach(function (stream) {
if (!_this4._remoteStreams) {
_this4._remoteStreams = [];
}
if (_this4._remoteStreams.includes(stream)) {
return;
}
_this4._remoteStreams.push(stream);
var event = new Event('addstream');
event.stream = stream;
_this4.dispatchEvent(event);
});
});
}
});
var origSetRemoteDescription = window.RTCPeerConnection.prototype.setRemoteDescription;
window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription() {
var pc = this;
if (!this._onaddstreampoly) {
this.addEventListener('track', this._onaddstreampoly = function (e) {
e.streams.forEach(function (stream) {
if (!pc._remoteStreams) {
pc._remoteStreams = [];
}
if (pc._remoteStreams.indexOf(stream) >= 0) {
return;
}
pc._remoteStreams.push(stream);
var 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;
}
var prototype = window.RTCPeerConnection.prototype;
var origCreateOffer = prototype.createOffer;
var origCreateAnswer = prototype.createAnswer;
var setLocalDescription = prototype.setLocalDescription;
var setRemoteDescription = prototype.setRemoteDescription;
var addIceCandidate = prototype.addIceCandidate;
prototype.createOffer = function createOffer(successCallback, failureCallback) {
var options = arguments.length >= 2 ? arguments[2] : arguments[0];
var promise = origCreateOffer.apply(this, [options]);
if (!failureCallback) {
return promise;
}
promise.then(successCallback, failureCallback);
return Promise.resolve();
};
prototype.createAnswer = function createAnswer(successCallback, failureCallback) {
var options = arguments.length >= 2 ? arguments[2] : arguments[0];
var promise = origCreateAnswer.apply(this, [options]);
if (!failureCallback) {
return promise;
}
promise.then(successCallback, failureCallback);
return Promise.resolve();
};
var withCallback = function withCallback(description, successCallback, failureCallback) {
var promise = setLocalDescription.apply(this, [description]);
if (!failureCallback) {
return promise;
}
promise.then(successCallback, failureCallback);
return Promise.resolve();
};
prototype.setLocalDescription = withCallback;
withCallback = function withCallback(description, successCallback, failureCallback) {
var promise = setRemoteDescription.apply(this, [description]);
if (!failureCallback) {
return promise;
}
promise.then(successCallback, failureCallback);
return Promise.resolve();
};
prototype.setRemoteDescription = withCallback;
withCallback = function withCallback(candidate, successCallback, failureCallback) {
var promise = addIceCandidate.apply(this, [candidate]);
if (!failureCallback) {
return promise;
}
promise.then(successCallback, failureCallback);
return Promise.resolve();
};
prototype.addIceCandidate = withCallback;
}
function shimGetUserMedia(window) {
var navigator = window && window.navigator;
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
// shim not needed in Safari 12.1
var mediaDevices = navigator.mediaDevices;
var _getUserMedia = mediaDevices.getUserMedia.bind(mediaDevices);
navigator.mediaDevices.getUserMedia = function (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: utils.compactObject(constraints.video)
});
}
return constraints;
}
function shimRTCIceServerUrls(window) {
if (!window.RTCPeerConnection) {
return;
}
// migrate from non-spec RTCIceServer.url to RTCIceServer.urls
var OrigPeerConnection = window.RTCPeerConnection;
window.RTCPeerConnection = function RTCPeerConnection(pcConfig, pcConstraints) {
if (pcConfig && pcConfig.iceServers) {
var newIceServers = [];
for (var i = 0; i < pcConfig.iceServers.length; i++) {
var server = pcConfig.iceServers[i];
if (server.urls === undefined && server.url) {
utils.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: function 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: function get() {
return {
receiver: this.receiver
};
}
});
}
}
function shimCreateOfferLegacy(window) {
var 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;
}
var audioTransceiver = this.getTransceivers().find(function (transceiver) {
return 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;
}
var videoTransceiver = this.getTransceivers().find(function (transceiver) {
return 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;
}

280
node_modules/webrtc-adapter/dist/utils.js generated vendored Normal file
View File

@@ -0,0 +1,280 @@
/*
* 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 */
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.compactObject = compactObject;
exports.deprecated = deprecated;
exports.detectBrowser = detectBrowser;
exports.disableLog = disableLog;
exports.disableWarnings = disableWarnings;
exports.extractVersion = extractVersion;
exports.filterStats = filterStats;
exports.log = log;
exports.walkStats = walkStats;
exports.wrapPeerConnectionEvent = wrapPeerConnectionEvent;
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
var logDisabled_ = true;
var 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) {
var match = uastring.match(expr);
return match && match.length >= pos && parseFloat(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;
}
var addEventListener = Object.getOwnPropertyDescriptor(EventTarget.prototype, 'addEventListener');
if (!addEventListener.writable) {
log('Unable to polyfill events');
return;
}
var proto = window.RTCPeerConnection.prototype;
var nativeAddEventListener = proto.addEventListener;
proto.addEventListener = function (nativeEventName, cb) {
if (nativeEventName !== eventNameToWrap) {
return nativeAddEventListener.apply(this, arguments);
}
var wrappedCallback = function wrappedCallback(e) {
var 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]);
};
var 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);
}
var 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: function get() {
return this['_on' + eventNameToWrap];
},
set: function 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 === "undefined" ? "undefined" : _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.
var 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;
}
var navigator = window.navigator;
// Prefer navigator.userAgentData.
if (navigator.userAgentData && navigator.userAgentData.brands) {
var chromium = navigator.userAgentData.brands.find(function (brand) {
return brand.brand === 'Chromium';
});
if (chromium) {
return {
browser: 'chrome',
version: parseInt(chromium.version, 10)
};
}
}
if (navigator.mozGetUserMedia) {
// Firefox.
result.browser = 'firefox';
result.version = parseInt(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 = parseInt(extractVersion(navigator.userAgent, /Chrom(e|ium)\/(\d+)\./, 2)) || null;
} else if (window.RTCPeerConnection && navigator.userAgent.match(/AppleWebKit\/(\d+)\./)) {
// Safari.
result.browser = 'safari';
result.version = parseInt(extractVersion(navigator.userAgent, /AppleWebKit\/(\d+)\./, 1));
result.supportsUnifiedPlan = window.RTCRtpTransceiver && 'currentDirection' in window.RTCRtpTransceiver.prototype;
// Only for internal usage.
result._safariVersion = extractVersion(navigator.userAgent, /Version\/(\d+(\.?\d+))/, 1);
} 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(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(data)) {
return data;
}
return Object.keys(data).reduce(function (accumulator, key) {
var isObj = isObject(data[key]);
var value = isObj ? compactObject(data[key]) : data[key];
var isEmptyObject = isObj && !Object.keys(value).length;
if (value === undefined || isEmptyObject) {
return accumulator;
}
return Object.assign(accumulator, _defineProperty({}, 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(function (name) {
if (name.endsWith('Id')) {
walkStats(stats, stats.get(base[name]), resultSet);
} else if (name.endsWith('Ids')) {
base[name].forEach(function (id) {
walkStats(stats, stats.get(id), resultSet);
});
}
});
}
/* filter getStats for a sender/receiver track. */
function filterStats(result, track, outbound) {
var streamStatsType = outbound ? 'outbound-rtp' : 'inbound-rtp';
var filteredResult = new Map();
if (track === null) {
return filteredResult;
}
var trackStats = [];
result.forEach(function (value) {
if (value.type === 'track' && value.trackIdentifier === track.id) {
trackStats.push(value);
}
});
trackStats.forEach(function (trackStat) {
result.forEach(function (stats) {
if (stats.type === streamStatsType && stats.trackId === trackStat.id) {
walkStats(result, stats, filteredResult);
}
});
});
return filteredResult;
}

58
node_modules/webrtc-adapter/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,58 @@
declare module "webrtc-adapter" {
interface IBrowserDetails {
browser: string;
version?: number;
supportsUnifiedPlan?: boolean;
}
interface ICommonShim {
shimRTCIceCandidate(window: Window): void;
shimMaxMessageSize(window: Window): void;
shimSendThrowTypeError(window: Window): void;
shimConnectionState(window: Window): void;
removeAllowExtmapMixed(window: Window): void;
}
interface IChromeShim {
shimMediaStream(window: Window): void;
shimOnTrack(window: Window): void;
shimGetSendersWithDtmf(window: Window): void;
shimSenderReceiverGetStats(window: Window): void;
shimAddTrackRemoveTrackWithNative(window: Window): void;
shimAddTrackRemoveTrack(window: Window): void;
shimPeerConnection(window: Window): void;
fixNegotiationNeeded(window: Window): void;
}
interface IFirefoxShim {
shimOnTrack(window: Window): void;
shimPeerConnection(window: Window): void;
shimSenderGetStats(window: Window): void;
shimReceiverGetStats(window: Window): void;
shimRemoveStream(window: Window): void;
shimRTCDataChannel(window: Window): void;
}
interface ISafariShim {
shimLocalStreamsAPI(window: Window): void;
shimRemoteStreamsAPI(window: Window): void;
shimCallbacksAPI(window: Window): void;
shimGetUserMedia(window: Window): void;
shimConstraints(constraints: MediaStreamConstraints): void;
shimRTCIceServerUrls(window: Window): void;
shimTrackEventTransceiver(window: Window): void;
shimCreateOfferLegacy(window: Window): void;
}
export interface IAdapter {
browserDetails: IBrowserDetails;
commonShim: ICommonShim;
browserShim: IChromeShim | IFirefoxShim | ISafariShim | undefined;
extractVersion(uastring: string, expr: string, pos: number): number;
disableLog(disable: boolean): void;
disableWarnings(disable: boolean): void;
}
const adapter: IAdapter;
export default adapter;
}

3260
node_modules/webrtc-adapter/out/adapter.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

3259
node_modules/webrtc-adapter/out/adapter_no_global.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

60
node_modules/webrtc-adapter/package.json generated vendored Normal file
View File

@@ -0,0 +1,60 @@
{
"name": "webrtc-adapter",
"version": "9.0.5",
"description": "A shim to insulate apps from WebRTC spec changes and browser prefix differences",
"license": "BSD-3-Clause",
"main": "./dist/adapter_core.js",
"types": "./index.d.ts",
"module": "./src/js/adapter_core.js",
"repository": {
"type": "git",
"url": "https://github.com/webrtchacks/adapter.git"
},
"authors": [
"The WebRTC project authors (https://www.webrtc.org/)",
"The adapter.js project authors (https://github.com/webrtchacks/adapter/)"
],
"scripts": {
"preversion": "git stash && npm install && npm update && BROWSER=chrome BVER=stable CI=true npm test && git checkout -B bumpVersion && grunt build && grunt copyForPublish && git add package.json release/* && git commit -m 'Add adapter artifacts' --allow-empty",
"version": "",
"postversion": "export GITTAG=\"echo $(git describe --abbrev=0 --tags | sed 's/^v//')\" && git push --force --set-upstream origin bumpVersion --follow-tags && git checkout gh-pages && git pull && cp out/adapter.js adapter.js && cp adapter.js adapter-`$GITTAG`.js && rm adapter-latest.js && ln -s adapter-`$GITTAG`.js adapter-latest.js && mkdir -p adapter-`$GITTAG`-variants && cp out/adapter.js adapter-`$GITTAG`-variants/ && cp out/adapter_*.js adapter-`$GITTAG`-variants/ && git add adapter.js adapter-latest.js adapter-`$GITTAG`.js adapter-`$GITTAG`-variants && git commit -m `$GITTAG` && git push --set-upstream origin gh-pages && git checkout main",
"prepare": "grunt build",
"prepublishonly": "npm test",
"test": "grunt && jest test/unit && karma start test/karma.conf.js",
"lint-and-unit-tests": "grunt && jest test/unit",
"e2e-tests": "grunt && karma start test/karma.conf.js"
},
"dependencies": {
"sdp": "^3.2.0"
},
"engines": {
"npm": ">=3.10.0",
"node": ">=6.0.0"
},
"devDependencies": {
"@babel/core": "^7.21.0",
"@babel/preset-env": "^7.20.2",
"@puppeteer/browsers": "^2.2.0",
"babel-preset-env": "^0.0.0",
"brfs": "^1.5.0",
"chai": "^3.5.0",
"eslint-plugin-jest": "^27.4.0",
"grunt": "^1.1.0",
"grunt-babel": "^8.0.0",
"grunt-browserify": "^6.0.0",
"grunt-cli": "^1.3.1",
"grunt-contrib-clean": "^1.1.0",
"grunt-contrib-copy": "^1.0.0",
"grunt-eslint": "^24.0.0",
"jest": "^29.7.0",
"karma": "^6.4.1",
"karma-browserify": "^8.1.0",
"karma-chai": "^0.1.0",
"karma-chrome-launcher": "^2.2.0",
"karma-firefox-launcher": "^1.3.0",
"karma-mocha": "^2.0.1",
"karma-mocha-reporter": "^2.2.3",
"karma-safari-launcher": "^1.0.0",
"mocha": "^10.2.0"
}
}

16
node_modules/webrtc-adapter/src/js/adapter_core.js generated vendored Normal file
View File

@@ -0,0 +1,16 @@
/*
* 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 */
'use strict';
import {adapterFactory} from './adapter_factory.js';
const adapter =
adapterFactory({window: typeof window === 'undefined' ? undefined : window});
export default adapter;

16
node_modules/webrtc-adapter/src/js/adapter_core5.js generated vendored Normal file
View File

@@ -0,0 +1,16 @@
/*
* 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 */
'use strict';
import {adapterFactory} from './adapter_factory.js';
const adapter =
adapterFactory({window: typeof window === 'undefined' ? undefined : window});
module.exports = adapter; // this is the difference from adapter_core.

139
node_modules/webrtc-adapter/src/js/adapter_factory.js generated vendored Normal file
View File

@@ -0,0 +1,139 @@
/*
* 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.
*/
import * as utils from './utils';
// Browser shims.
import * as chromeShim from './chrome/chrome_shim';
import * as firefoxShim from './firefox/firefox_shim';
import * as safariShim from './safari/safari_shim';
import * as commonShim from './common_shim';
import * as sdp from 'sdp';
// Shimming starts here.
export function adapterFactory({window} = {}, options = {
shimChrome: true,
shimFirefox: true,
shimSafari: true,
}) {
// Utils.
const logging = utils.log;
const browserDetails = utils.detectBrowser(window);
const adapter = {
browserDetails,
commonShim,
extractVersion: utils.extractVersion,
disableLog: utils.disableLog,
disableWarnings: utils.disableWarnings,
// Expose sdp as a convenience. For production apps include directly.
sdp,
};
// Shim browser if found.
switch (browserDetails.browser) {
case 'chrome':
if (!chromeShim || !chromeShim.shimPeerConnection ||
!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.
commonShim.shimAddIceCandidateNullOrEmpty(window, browserDetails);
commonShim.shimParameterlessSetLocalDescription(window, browserDetails);
chromeShim.shimGetUserMedia(window, browserDetails);
chromeShim.shimMediaStream(window, browserDetails);
chromeShim.shimPeerConnection(window, browserDetails);
chromeShim.shimOnTrack(window, browserDetails);
chromeShim.shimAddTrackRemoveTrack(window, browserDetails);
chromeShim.shimGetSendersWithDtmf(window, browserDetails);
chromeShim.shimSenderReceiverGetStats(window, browserDetails);
chromeShim.fixNegotiationNeeded(window, browserDetails);
commonShim.shimRTCIceCandidate(window, browserDetails);
commonShim.shimRTCIceCandidateRelayProtocol(window, browserDetails);
commonShim.shimConnectionState(window, browserDetails);
commonShim.shimMaxMessageSize(window, browserDetails);
commonShim.shimSendThrowTypeError(window, browserDetails);
commonShim.removeExtmapAllowMixed(window, browserDetails);
break;
case 'firefox':
if (!firefoxShim || !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.
commonShim.shimAddIceCandidateNullOrEmpty(window, browserDetails);
commonShim.shimParameterlessSetLocalDescription(window, browserDetails);
firefoxShim.shimGetUserMedia(window, browserDetails);
firefoxShim.shimPeerConnection(window, browserDetails);
firefoxShim.shimGetStats(window, browserDetails);
firefoxShim.shimOnTrack(window, browserDetails);
firefoxShim.shimRemoveStream(window, browserDetails);
firefoxShim.shimSenderGetStats(window, browserDetails);
firefoxShim.shimReceiverGetStats(window, browserDetails);
firefoxShim.shimRTCDataChannel(window, browserDetails);
firefoxShim.shimAddTransceiver(window, browserDetails);
firefoxShim.shimGetParameters(window, browserDetails);
firefoxShim.shimCreateOffer(window, browserDetails);
firefoxShim.shimCreateAnswer(window, browserDetails);
commonShim.shimRTCIceCandidate(window, browserDetails);
commonShim.shimConnectionState(window, browserDetails);
commonShim.shimMaxMessageSize(window, browserDetails);
commonShim.shimSendThrowTypeError(window, browserDetails);
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.
commonShim.shimAddIceCandidateNullOrEmpty(window, browserDetails);
commonShim.shimParameterlessSetLocalDescription(window, browserDetails);
safariShim.shimRTCIceServerUrls(window, browserDetails);
safariShim.shimCreateOfferLegacy(window, browserDetails);
safariShim.shimCallbacksAPI(window, browserDetails);
safariShim.shimLocalStreamsAPI(window, browserDetails);
safariShim.shimRemoteStreamsAPI(window, browserDetails);
safariShim.shimTrackEventTransceiver(window, browserDetails);
safariShim.shimGetUserMedia(window, browserDetails);
safariShim.shimAudioContext(window, browserDetails);
commonShim.shimRTCIceCandidate(window, browserDetails);
commonShim.shimRTCIceCandidateRelayProtocol(window, browserDetails);
commonShim.shimMaxMessageSize(window, browserDetails);
commonShim.shimSendThrowTypeError(window, browserDetails);
commonShim.removeExtmapAllowMixed(window, browserDetails);
break;
default:
logging('Unsupported browser!');
break;
}
return adapter;
}

View File

@@ -0,0 +1,645 @@
/*
* 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 */
'use strict';
import * as utils from '../utils.js';
export {shimGetUserMedia} from './getusermedia';
export function shimMediaStream(window) {
window.MediaStream = window.MediaStream || window.webkitMediaStream;
}
export function shimOnTrack(window, browserDetails) {
if (browserDetails.version > 102) {
// Unified plan is supported so no need to do anything.
return;
}
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.
utils.wrapPeerConnectionEvent(window, 'track', e => {
if (!e.transceiver) {
Object.defineProperty(e, 'transceiver',
{value: {receiver: e.receiver}});
}
return e;
});
}
}
export 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;
}
});
}
}
export function shimSenderReceiverGetStats(window, browserDetails) {
if (browserDetails.version >= 67) {
return;
}
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.
*/
utils.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;
};
}
utils.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 =>
utils.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);
};
}
export 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);
};
}
export 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'));
}
};
}
export function shimPeerConnection(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.
export function fixNegotiationNeeded(window, browserDetails) {
if (browserDetails.version > 102) {
// Plan-B is no longer supported.
return;
}
utils.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;
});
}

View File

@@ -0,0 +1,189 @@
/*
* 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 */
'use strict';
import * as utils from '../utils.js';
const logging = utils.log;
export function shimGetUserMedia(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))));
};
}
}

470
node_modules/webrtc-adapter/src/js/common_shim.js generated vendored Normal file
View File

@@ -0,0 +1,470 @@
/*
* 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 */
'use strict';
import SDPUtils from 'sdp';
import * as utils from './utils';
export 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', ...)
utils.wrapPeerConnectionEvent(window, 'icecandidate', e => {
if (e.candidate) {
Object.defineProperty(e, 'candidate', {
value: new window.RTCIceCandidate(e.candidate),
writable: 'false'
});
}
return e;
});
}
export function shimRTCIceCandidateRelayProtocol(window) {
if (!window.RTCIceCandidate || (window.RTCIceCandidate && 'relayProtocol' in
window.RTCIceCandidate.prototype)) {
return;
}
// Hook up the augmented candidate in onicecandidate and
// addEventListener('icecandidate', ...)
utils.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;
});
}
export 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);
};
}
export function shimSendThrowTypeError(window, browserDetails) {
if (!(window.RTCPeerConnection &&
'createDataChannel' in window.RTCPeerConnection.prototype)) {
return;
}
if (browserDetails.browser === 'chrome' && browserDetails.version > 149) {
// Fixed by https://issues.chromium.org/issues/490588131
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
if (browserDetails.browser === 'firefox' && browserDetails.version > 60) {
return;
}
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;
};
utils.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.
*/
export 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);
};
});
}
export 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._safariVersion >= 13.1) {
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);
};
}
export 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
export 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]));
};
}

View File

@@ -0,0 +1,315 @@
/*
* 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 */
'use strict';
import * as utils from '../utils';
export {shimGetUserMedia} from './getusermedia';
export {shimGetDisplayMedia} from './getdisplaymedia';
export 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};
}
});
}
}
export 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];
});
}
}
export function shimGetStats(window, browserDetails) {
if (typeof window !== 'object' ||
!(window.RTCPeerConnection || window.mozRTCPeerConnection)) {
return; // probably media.peerconnection.enabled=false in about:config
}
if (browserDetails.version >= 151) {
// https://bugzilla.mozilla.org/show_bug.cgi?id=1056433
return;
}
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;
if (this.signalingState === 'closed') {
// No longer required in FF151+
return Promise.resolve(new Map());
}
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);
};
}
export 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());
};
}
export 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;
};
}
utils.wrapPeerConnectionEvent(window, 'track', e => {
e.receiver._pc = e.srcElement;
return e;
});
window.RTCRtpReceiver.prototype.getStats = function getStats() {
return this._pc.getStats(this.track);
};
}
export function shimRemoveStream(window) {
if (!window.RTCPeerConnection ||
'removeStream' in window.RTCPeerConnection.prototype) {
return;
}
window.RTCPeerConnection.prototype.removeStream =
function removeStream(stream) {
utils.deprecated('removeStream', 'removeTrack');
this.getSenders().forEach(sender => {
if (sender.track && stream.getTracks().includes(sender.track)) {
this.removeTrack(sender);
}
});
};
}
export 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;
}
}
export 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;
};
}
}
export 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;
};
}
}
export 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);
};
}
export 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);
};
}

View File

@@ -0,0 +1,36 @@
/*
* 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 */
'use strict';
export 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);
};
}

View File

@@ -0,0 +1,67 @@
/*
* 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 */
'use strict';
import * as utils from '../utils';
export function shimGetUserMedia(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.
utils.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]);
};
}
}
}

View File

@@ -0,0 +1,352 @@
/*
* 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.
*/
'use strict';
import * as utils from '../utils';
export 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);
}
});
};
}
}
export 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);
};
}
}
export 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;
}
export 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);
}
}
export function shimConstraints(constraints) {
if (constraints && constraints.video !== undefined) {
return Object.assign({},
constraints,
{video: utils.compactObject(constraints.video)}
);
}
return constraints;
}
export 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) {
utils.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;
}
});
}
}
export 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};
}
});
}
}
export 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);
};
}
export function shimAudioContext(window) {
if (typeof window !== 'object' || window.AudioContext) {
return;
}
window.AudioContext = window.webkitAudioContext;
}

283
node_modules/webrtc-adapter/src/js/utils.js generated vendored Normal file
View File

@@ -0,0 +1,283 @@
/*
* 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 */
'use strict';
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.
*/
export function extractVersion(uastring, expr, pos) {
const match = uastring.match(expr);
return match && match.length >= pos && parseFloat(match[pos], 10);
}
// Wraps the peerconnection event eventNameToWrap in a function
// which returns the modified event object (or false to prevent
// the event).
export function wrapPeerConnectionEvent(window, eventNameToWrap, wrapper) {
if (!window.RTCPeerConnection) {
return;
}
const addEventListener = Object.getOwnPropertyDescriptor(
EventTarget.prototype, 'addEventListener');
if (!addEventListener.writable) {
log('Unable to polyfill events');
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
});
}
export 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.
*/
export 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');
}
export 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.
*/
export 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.
*/
export 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;
// Prefer navigator.userAgentData.
if (navigator.userAgentData && navigator.userAgentData.brands) {
const chromium = navigator.userAgentData.brands.find((brand) => {
return brand.brand === 'Chromium';
});
if (chromium) {
return {browser: 'chrome', version: parseInt(chromium.version, 10)};
}
}
if (navigator.mozGetUserMedia) { // Firefox.
result.browser = 'firefox';
result.version = parseInt(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 = parseInt(extractVersion(navigator.userAgent,
/Chrom(e|ium)\/(\d+)\./, 2)) || null;
} else if (window.RTCPeerConnection &&
navigator.userAgent.match(/AppleWebKit\/(\d+)\./)) { // Safari.
result.browser = 'safari';
result.version = parseInt(extractVersion(navigator.userAgent,
/AppleWebKit\/(\d+)\./, 1));
result.supportsUnifiedPlan = window.RTCRtpTransceiver &&
'currentDirection' in window.RTCRtpTransceiver.prototype;
// Only for internal usage.
result._safariVersion = extractVersion(navigator.userAgent,
/Version\/(\d+(\.?\d+))/, 1);
} 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(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`.
*/
export function compactObject(data) {
if (!isObject(data)) {
return data;
}
return Object.keys(data).reduce(function(accumulator, key) {
const isObj = isObject(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. */
export 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. */
export 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;
}