@twilio/webrtc
Advanced tools
Comparing version 2.2.1 to 2.3.0
@@ -0,1 +1,15 @@ | ||
2.3.0 (March 18, 2019) | ||
====================== | ||
New Features | ||
------------ | ||
- SafariRTCPeerConnection will now support Unified Plan SDPs. (JSDK-2306) | ||
Bug Fixes | ||
--------- | ||
- Fixed a bug where createOffer(), when called in Safari 12.2 created "offerToReceive" RTCRtpTransceivers | ||
even though the RTCPeerConnection already had "sendrecv" or "recvonly" RTCRtpTransceivers. (JSDK-2286) | ||
2.2.1 (January 29, 2019) | ||
@@ -2,0 +16,0 @@ ======================== |
@@ -1,2 +0,1 @@ | ||
/* global RTCRtpTransceiver */ | ||
'use strict'; | ||
@@ -6,2 +5,3 @@ | ||
var guessBrowser = require('./util').guessBrowser; | ||
var getSdpFormat = require('./util/sdp').getSdpFormat; | ||
@@ -12,2 +12,3 @@ var guess = guessBrowser(); | ||
var isSafari = guess === 'safari'; | ||
var sdpFormat = getSdpFormat(); | ||
@@ -326,4 +327,3 @@ var chromeMajorVersion = isChrome | ||
if (typeof options.testForSafari !== 'undefined' || isSafari) { | ||
if (typeof options.testForSafari !== 'undefined' | ||
|| 'currentDirection' in RTCRtpTransceiver.prototype) { | ||
if (typeof options.testForSafari !== 'undefined' || sdpFormat === 'unified') { | ||
return chromeOrSafariGetTrackStats(peerConnection, track); | ||
@@ -330,0 +330,0 @@ } |
@@ -1,7 +0,5 @@ | ||
/* globals webkitMediaStream, MediaStream */ | ||
/* globals MediaStream */ | ||
'use strict'; | ||
if (typeof webkitMediaStream !== 'undefined') { | ||
module.exports = webkitMediaStream; | ||
} else if (typeof MediaStream !== 'undefined') { | ||
if (typeof MediaStream !== 'undefined') { | ||
module.exports = MediaStream; | ||
@@ -8,0 +6,0 @@ } else { |
@@ -1,2 +0,2 @@ | ||
/* globals RTCDataChannel, RTCSessionDescription, webkitRTCPeerConnection */ | ||
/* globals RTCDataChannel, RTCPeerConnection, RTCSessionDescription */ | ||
'use strict'; | ||
@@ -13,5 +13,3 @@ | ||
var PeerConnection = typeof RTCPeerConnection !== 'undefined' | ||
? RTCPeerConnection | ||
: webkitRTCPeerConnection; | ||
var sdpFormat = sdpUtils.getSdpFormat(); | ||
@@ -36,9 +34,6 @@ // NOTE(mroberts): This class wraps Chrome's RTCPeerConnection implementation. | ||
// NOTE(mhuynh): See | ||
// https://webrtc.org/web-apis/chrome/unified-plan/ | ||
// for transition from 'plan-b' default to 'unified-plan' as default. | ||
var newConfiguration = Object.assign({ sdpSemantics: 'plan-b' }, configuration); | ||
if (newConfiguration.iceTransportPolicy) { | ||
newConfiguration.iceTransports = newConfiguration.iceTransportPolicy; | ||
} | ||
configuration = configuration || {}; | ||
var newConfiguration = Object.assign(configuration.iceTransportPolicy | ||
? { iceTransports: configuration.iceTransportPolicy } | ||
: {}, { sdpSemantics: 'plan-b' }, configuration); | ||
@@ -48,5 +43,3 @@ util.interceptEvent(this, 'datachannel'); | ||
/* eslint new-cap:0 */ | ||
var peerConnection = new PeerConnection(newConfiguration, constraints); | ||
var sdpSemantics = getSdpSemantics(newConfiguration.sdpSemantics); | ||
var peerConnection = new RTCPeerConnection(newConfiguration, constraints); | ||
@@ -68,5 +61,2 @@ Object.defineProperties(this, { | ||
}, | ||
_sdpSemantics: { | ||
value: sdpSemantics | ||
}, | ||
_senders: { | ||
@@ -108,3 +98,3 @@ value: new Map() | ||
if (sdpSemantics === 'plan-b') { | ||
if (sdpFormat === 'planb') { | ||
// NOTE(mmalavalli): Because of a bug related to "ontrack" in Chrome 63 and below, | ||
@@ -133,4 +123,6 @@ // we prevent it from being delegated to ChromeRTCPeerConnection. | ||
peerConnection.addStream(this._localStream); | ||
util.proxyProperties(PeerConnection.prototype, this, peerConnection); | ||
if (!RTCPeerConnection.prototype.addTrack) { | ||
peerConnection.addStream(this._localStream); | ||
} | ||
util.proxyProperties(RTCPeerConnection.prototype, this, peerConnection); | ||
} | ||
@@ -163,4 +155,4 @@ | ||
} | ||
if (this._peerConnection.addTrack) { | ||
if (this._sdpSemantics === 'unified-plan') { | ||
if (RTCPeerConnection.prototype.addTrack) { | ||
if (sdpFormat === 'unified') { | ||
sender = getActiveSenders(this._peerConnection).get(track) | ||
@@ -189,3 +181,3 @@ || this._peerConnection.addTrack.apply(this._peerConnection, args); | ||
// | ||
if (PeerConnection.prototype.addTransceiver) { | ||
if (RTCPeerConnection.prototype.addTransceiver) { | ||
ChromeRTCPeerConnection.prototype.addTransceiver = function addTransceiver() { | ||
@@ -215,5 +207,5 @@ var transceiver = this._peerConnection.addTransceiver.apply(this._peerConnection, arguments); | ||
if (this._peerConnection.removeTrack) { | ||
if (RTCPeerConnection.prototype.removeTrack) { | ||
try { | ||
if (this._sdpSemantics === 'unified-plan') { | ||
if (sdpFormat === 'unified') { | ||
if (sender.track) { | ||
@@ -249,3 +241,3 @@ this._senders.set(sender.track, new RTCRtpSenderShim(null)); | ||
ChromeRTCPeerConnection.prototype.getSenders = function getSenders() { | ||
return this._peerConnection.getSenders && this._sdpSemantics === 'plan-b' | ||
return this._peerConnection.getSenders && sdpFormat === 'planb' | ||
? this._peerConnection.getSenders() | ||
@@ -296,3 +288,3 @@ : Array.from(this._senders.values()); | ||
var promise; | ||
var isPlanB = this._sdpSemantics === 'plan-b'; | ||
var isPlanB = sdpFormat === 'planb'; | ||
var self = this; | ||
@@ -316,5 +308,5 @@ | ||
self._pendingRemoteOffer = null; | ||
return new RTCSessionDescription({ | ||
return new ChromeRTCSessionDescription({ | ||
type: 'answer', | ||
sdp: updateTrackIdsToSSRCs(self._sdpSemantics, self._tracksToSSRCs, answer.sdp) | ||
sdp: updateTrackIdsToSSRCs(sdpFormat, self._tracksToSSRCs, answer.sdp) | ||
}); | ||
@@ -327,5 +319,5 @@ }, function setRemoteDescriptionOrCreateAnswerFailed(error) { | ||
promise = this._peerConnection.createAnswer().then(function(answer) { | ||
return new RTCSessionDescription({ | ||
return new ChromeRTCSessionDescription({ | ||
type: 'answer', | ||
sdp: updateTrackIdsToSSRCs(self._sdpSemantics, self._tracksToSSRCs, answer.sdp) | ||
sdp: updateTrackIdsToSSRCs(sdpFormat, self._tracksToSSRCs, answer.sdp) | ||
}); | ||
@@ -348,3 +340,3 @@ }); | ||
type: offer.type, | ||
sdp: updateTrackIdsToSSRCs(self._sdpSemantics, self._tracksToSSRCs, offer.sdp) | ||
sdp: updateTrackIdsToSSRCs(sdpFormat, self._tracksToSSRCs, offer.sdp) | ||
}); | ||
@@ -384,3 +376,3 @@ }); | ||
util.delegateMethods( | ||
PeerConnection.prototype, | ||
RTCPeerConnection.prototype, | ||
ChromeRTCPeerConnection.prototype, | ||
@@ -435,3 +427,3 @@ '_peerConnection'); | ||
var isPlanB = peerConnection._sdpSemantics === 'plan-b'; | ||
var isPlanB = sdpFormat === 'planb'; | ||
var mediaStreamTracks = isPlanB ? util.flatMap(peerConnection.getRemoteStreams(), function(mediaStream) { | ||
@@ -491,3 +483,3 @@ return mediaStream.getTracks(); | ||
function setRemoteAnswer(peerConnection, answer) { | ||
var isPlanB = peerConnection._sdpSemantics === 'plan-b'; | ||
var isPlanB = sdpFormat === 'planb'; | ||
var mediaStreamTracks = isPlanB ? util.flatMap(peerConnection.getRemoteStreams(), function(mediaStream) { | ||
@@ -588,28 +580,12 @@ return mediaStream.getTracks(); | ||
/** | ||
* Get the actual `sdpSemantics`. | ||
* @param {SdpSemantics} sdpSemantics | ||
* @returns {SdpSemantics} | ||
*/ | ||
function getSdpSemantics(sdpSemantics) { | ||
// NOTE(mmalavalli): Once Chrome stops supporting "plan-b" SDPs, it will | ||
// ignore the "sdpSemantics" flag. So, in order to differentiate between | ||
// versions of Chrome which support only "plan-b" SDPs and versions of Chrome | ||
// which support only "unified-plan" SDPs, which check whether PeerConnection's | ||
// addStream() method is present. | ||
return sdpUtils.checkIfSdpSemanticsIsSupported() | ||
? sdpSemantics | ||
: PeerConnection.prototype.addStream ? 'plan-b' : 'unified-plan'; | ||
} | ||
/** | ||
* Update the mappings from MediaStreamTrack IDs to SSRCs as indicated by both | ||
* the Map from MediaStreamTrack IDs to SSRCs and the SDP itself. This method | ||
* ensures that SSRCs never change once announced. | ||
* @param {SdpSemantics} sdpSemantics | ||
* @param {Map<string, Set<string>>} trackIdsToSSRCs | ||
* @param {'planb'|'unified'} sdpFormat | ||
* @param {Map<string, Set<string>>} tracksToSSRCs | ||
* @param {string} sdp - an SDP whose format is determined by `sdpSemantics` | ||
* @returns {string} updatedSdp - updated SDP | ||
*/ | ||
function updateTrackIdsToSSRCs(sdpSemantics, tracksToSSRCs, sdp) { | ||
return sdpSemantics === 'unified-plan' | ||
function updateTrackIdsToSSRCs(sdpFormat, tracksToSSRCs, sdp) { | ||
return sdpFormat === 'unified' | ||
? sdpUtils.updateUnifiedPlanTrackIdsToSSRCs(tracksToSSRCs, sdp) | ||
@@ -616,0 +592,0 @@ : sdpUtils.updatePlanBTrackIdsToSSRCs(tracksToSSRCs, sdp); |
@@ -1,2 +0,2 @@ | ||
/* globals mozRTCPeerConnection, RTCPeerConnection */ | ||
/* globals RTCPeerConnection */ | ||
'use strict'; | ||
@@ -11,6 +11,2 @@ | ||
var PeerConnection = typeof RTCPeerConnection !== 'undefined' | ||
? RTCPeerConnection | ||
: mozRTCPeerConnection; | ||
// NOTE(mroberts): This is a short-lived workaround. Checking the user agent | ||
@@ -53,3 +49,3 @@ // string might not fix every affected Firefox instance, but it should be good | ||
/* eslint new-cap:0 */ | ||
var peerConnection = new PeerConnection(configuration); | ||
var peerConnection = new RTCPeerConnection(configuration); | ||
@@ -118,3 +114,3 @@ Object.defineProperties(this, { | ||
util.proxyProperties(PeerConnection.prototype, this, peerConnection); | ||
util.proxyProperties(RTCPeerConnection.prototype, this, peerConnection); | ||
} | ||
@@ -159,3 +155,3 @@ | ||
if (PeerConnection.prototype.addTransceiver) { | ||
if (RTCPeerConnection.prototype.addTransceiver) { | ||
FirefoxRTCPeerConnection.prototype.addTransceiver = function addTransceiver() { | ||
@@ -324,3 +320,3 @@ var transceiver = this._peerConnection.addTransceiver.apply(this._peerConnection, arguments); | ||
util.delegateMethods( | ||
PeerConnection.prototype, | ||
RTCPeerConnection.prototype, | ||
FirefoxRTCPeerConnection.prototype, | ||
@@ -327,0 +323,0 @@ '_peerConnection'); |
@@ -1,2 +0,2 @@ | ||
/* globals RTCPeerConnection, RTCRtpTransceiver, RTCSessionDescription */ | ||
/* globals RTCPeerConnection, RTCSessionDescription */ | ||
'use strict'; | ||
@@ -11,3 +11,3 @@ | ||
var isUnifiedPlan = 'currentDirection' in RTCRtpTransceiver.prototype; | ||
var isUnifiedPlan = sdpUtils.getSdpFormat() === 'unified'; | ||
@@ -161,3 +161,3 @@ var updateTrackIdsToSSRCs = isUnifiedPlan | ||
// good enough for our application. | ||
if (options.offerToReceiveAudio && !this._audioTransceiver && !(isUnifiedPlan && hasSendersForTracksOfKind(this, 'audio'))) { | ||
if (options.offerToReceiveAudio && !this._audioTransceiver && !(isUnifiedPlan && hasReceiversForTracksOfKind(this, 'audio'))) { | ||
delete options.offerToReceiveAudio; | ||
@@ -173,3 +173,3 @@ try { | ||
if (options.offerToReceiveVideo && !this._videoTransceiver && !(isUnifiedPlan && hasSendersForTracksOfKind(this, 'video'))) { | ||
if (options.offerToReceiveVideo && !this._videoTransceiver && !(isUnifiedPlan && hasReceiversForTracksOfKind(this, 'video'))) { | ||
delete options.offerToReceiveVideo; | ||
@@ -396,3 +396,3 @@ try { | ||
/** | ||
* Whether a SafariRTCPeerConnection has any RTCRtpSender(s) for the given | ||
* Whether a SafariRTCPeerConnection has any RTCRtpReceivers(s) for the given | ||
* MediaStreamTrack kind. | ||
@@ -403,5 +403,5 @@ * @param {SafariRTCPeerConnection} peerConnection | ||
*/ | ||
function hasSendersForTracksOfKind(peerConnection, kind) { | ||
function hasReceiversForTracksOfKind(peerConnection, kind) { | ||
return !!peerConnection.getTransceivers().find(function(transceiver) { | ||
return transceiver.sender && transceiver.sender.track && transceiver.sender.track.kind === kind; | ||
return transceiver.receiver && transceiver.receiver.track && transceiver.receiver.track.kind === kind; | ||
}); | ||
@@ -408,0 +408,0 @@ } |
@@ -112,11 +112,12 @@ 'use strict'; | ||
function guessBrowser() { | ||
if (typeof webkitRTCPeerConnection !== 'undefined') { | ||
return 'chrome'; | ||
} else if (typeof mozRTCPeerConnection !== 'undefined') { | ||
return 'firefox'; | ||
} else if (typeof RTCPeerConnection !== 'undefined') { | ||
if (typeof navigator !== 'undefined' && navigator.userAgent.match(/AppleWebKit\/(\d+)\./)) { | ||
if (typeof navigator !== 'undefined' && typeof navigator.userAgent === 'string') { | ||
if (/Chrome/.test(navigator.userAgent)) { | ||
return 'chrome'; | ||
} | ||
if (/Firefox/.test(navigator.userAgent)) { | ||
return 'firefox'; | ||
} | ||
if (/Safari/.test(navigator.userAgent)) { | ||
return 'safari'; | ||
} | ||
// NOTE(mroberts): Could be Edge. | ||
} | ||
@@ -123,0 +124,0 @@ return null; |
@@ -0,6 +1,79 @@ | ||
/* globals RTCPeerConnection, RTCRtpTransceiver */ | ||
'use strict'; | ||
var flatMap = require('./').flatMap; | ||
var guessBrowser = require('./').guessBrowser; | ||
// NOTE(mmalavalli): We cache Chrome's sdpSemantics support in order to prevent | ||
// instantiation of more than one RTCPeerConnection. | ||
var isSdpSemanticsSupported; | ||
/** | ||
* Check if Chrome supports specifying sdpSemantics for an RTCPeerConnection. | ||
* @return {boolean} | ||
*/ | ||
function checkIfSdpSemanticsIsSupported() { | ||
if (typeof isSdpSemanticsSupported === 'boolean') { | ||
return isSdpSemanticsSupported; | ||
} | ||
if (typeof RTCPeerConnection === 'undefined') { | ||
isSdpSemanticsSupported = false; | ||
return isSdpSemanticsSupported; | ||
} | ||
try { | ||
new RTCPeerConnection({ sdpSemantics: 'foo' }); | ||
isSdpSemanticsSupported = false; | ||
} catch (e) { | ||
isSdpSemanticsSupported = true; | ||
} | ||
return isSdpSemanticsSupported; | ||
} | ||
// NOTE(mmalavalli): We cache Chrome's SDP format in order to prevent | ||
// instantiation of more than one RTCPeerConnection. | ||
var chromeSdpFormat; | ||
/** | ||
* Get Chrome's default SDP format. | ||
* @returns {'planb'|'unified'} | ||
*/ | ||
function getChromeSdpFormat() { | ||
if (typeof chromeSdpFormat === 'string') { | ||
return chromeSdpFormat; | ||
} | ||
if (checkIfSdpSemanticsIsSupported()) { | ||
chromeSdpFormat = 'planb'; | ||
return chromeSdpFormat; | ||
} | ||
chromeSdpFormat = typeof RTCPeerConnection !== 'undefined' | ||
&& 'addStream' in RTCPeerConnection.prototype | ||
? 'planb' | ||
: 'unified'; | ||
return chromeSdpFormat; | ||
} | ||
/** | ||
* Get Safari's default SDP format. | ||
* @returns {'planb'|'unified'} | ||
*/ | ||
function getSafariSdpFormat() { | ||
return typeof RTCRtpTransceiver !== 'undefined' | ||
&& 'currentDirection' in RTCRtpTransceiver.prototype | ||
? 'unified' | ||
: 'planb'; | ||
} | ||
/** | ||
* Get the browser's default SDP format. | ||
* @returns {'planb'|'unified'} | ||
*/ | ||
function getSdpFormat() { | ||
return { | ||
chrome: getChromeSdpFormat(), | ||
firefox: 'unified', | ||
safari: getSafariSdpFormat() | ||
}[guessBrowser()] || null; | ||
} | ||
/** | ||
* Match a pattern across lines, returning the first capture group for any | ||
@@ -209,29 +282,3 @@ * matches. | ||
// NOTE(mroberts): We need to cache this result so that we don't create too many | ||
// RTCPeerConnections. | ||
var sdpSemanticsIsSupported; | ||
/** | ||
* Check whether or not `sdpSemantics` is supported. | ||
* @returns {boolean} | ||
*/ | ||
function checkIfSdpSemanticsIsSupported() { | ||
if (typeof sdpSemanticsIsSupported === 'boolean') { | ||
return sdpSemanticsIsSupported; | ||
} | ||
if (typeof RTCPeerConnection === 'undefined') { | ||
sdpSemanticsIsSupported = false; | ||
return sdpSemanticsIsSupported; | ||
} | ||
try { | ||
new RTCPeerConnection({ sdpSemantics: 'bogus' }); | ||
sdpSemanticsIsSupported = false; | ||
return sdpSemanticsIsSupported; | ||
} catch (error) { | ||
sdpSemanticsIsSupported = true; | ||
return sdpSemanticsIsSupported; | ||
} | ||
} | ||
exports.checkIfSdpSemanticsIsSupported = checkIfSdpSemanticsIsSupported; | ||
exports.getSdpFormat = getSdpFormat; | ||
exports.getMediaSections = getMediaSections; | ||
@@ -238,0 +285,0 @@ exports.getPlanBTrackIds = getPlanBTrackIds; |
{ | ||
"name": "@twilio/webrtc", | ||
"version": "2.2.1", | ||
"version": "2.3.0", | ||
"description": "WebRTC-related APIs and shims used by twilio-video.js", | ||
@@ -5,0 +5,0 @@ "scripts": { |
122639
2837