update
This commit is contained in:
463
APP/nexus-remote/node_modules/webrtc-adapter/src/js/common_shim.js
generated
vendored
Normal file
463
APP/nexus-remote/node_modules/webrtc-adapter/src/js/common_shim.js
generated
vendored
Normal file
@@ -0,0 +1,463 @@
|
||||
/*
|
||||
* 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) {
|
||||
if (!(window.RTCPeerConnection &&
|
||||
'createDataChannel' in window.RTCPeerConnection.prototype)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Note: Although Firefox >= 57 has a native implementation, the maximum
|
||||
// message size can be reset for all data channels at a later stage.
|
||||
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831
|
||||
|
||||
function wrapDcSend(dc, pc) {
|
||||
const origDataChannelSend = dc.send;
|
||||
dc.send = function send() {
|
||||
const data = arguments[0];
|
||||
const length = data.length || data.size || data.byteLength;
|
||||
if (dc.readyState === 'open' &&
|
||||
pc.sctp && length > pc.sctp.maxMessageSize) {
|
||||
throw new TypeError('Message too large (can send a maximum of ' +
|
||||
pc.sctp.maxMessageSize + ' bytes)');
|
||||
}
|
||||
return origDataChannelSend.apply(dc, arguments);
|
||||
};
|
||||
}
|
||||
const origCreateDataChannel =
|
||||
window.RTCPeerConnection.prototype.createDataChannel;
|
||||
window.RTCPeerConnection.prototype.createDataChannel =
|
||||
function createDataChannel() {
|
||||
const dataChannel = origCreateDataChannel.apply(this, arguments);
|
||||
wrapDcSend(dataChannel, this);
|
||||
return dataChannel;
|
||||
};
|
||||
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]));
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user