twilio-video 2.18.2 → 2.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/LICENSE.md +1 -1
  3. package/README.md +1 -1
  4. package/dist/twilio-video.js +1000 -796
  5. package/dist/twilio-video.min.js +23 -23
  6. package/es5/connect.js +24 -3
  7. package/es5/connect.js.map +1 -1
  8. package/es5/encodingparameters.js +5 -1
  9. package/es5/encodingparameters.js.map +1 -1
  10. package/es5/localparticipant.js +4 -0
  11. package/es5/localparticipant.js.map +1 -1
  12. package/es5/media/track/localmediatrack.js +2 -0
  13. package/es5/media/track/localmediatrack.js.map +1 -1
  14. package/es5/media/track/sender.js +50 -2
  15. package/es5/media/track/sender.js.map +1 -1
  16. package/es5/preflight/getturncredentials.js +14 -9
  17. package/es5/preflight/getturncredentials.js.map +1 -1
  18. package/es5/preflight/preflighttest.js +115 -75
  19. package/es5/preflight/preflighttest.js.map +1 -1
  20. package/es5/signaling/v2/cancelableroomsignalingpromise.js +2 -0
  21. package/es5/signaling/v2/cancelableroomsignalingpromise.js.map +1 -1
  22. package/es5/signaling/v2/iceconnectionmonitor.js +3 -7
  23. package/es5/signaling/v2/iceconnectionmonitor.js.map +1 -1
  24. package/es5/signaling/v2/localparticipant.js +35 -1
  25. package/es5/signaling/v2/localparticipant.js.map +1 -1
  26. package/es5/signaling/v2/networkqualitysignaling.js +20 -1
  27. package/es5/signaling/v2/networkqualitysignaling.js.map +1 -1
  28. package/es5/signaling/v2/peerconnection.js +268 -145
  29. package/es5/signaling/v2/peerconnection.js.map +1 -1
  30. package/es5/signaling/v2/peerconnectionmanager.js +8 -0
  31. package/es5/signaling/v2/peerconnectionmanager.js.map +1 -1
  32. package/es5/signaling/v2/publisherhintsignaling.js +85 -0
  33. package/es5/signaling/v2/publisherhintsignaling.js.map +1 -0
  34. package/es5/signaling/v2/renderhintssignaling.js +28 -17
  35. package/es5/signaling/v2/renderhintssignaling.js.map +1 -1
  36. package/es5/signaling/v2/room.js +33 -1
  37. package/es5/signaling/v2/room.js.map +1 -1
  38. package/es5/signaling/v2/twilioconnectiontransport.js +6 -8
  39. package/es5/signaling/v2/twilioconnectiontransport.js.map +1 -1
  40. package/es5/util/cancelablepromise.js +11 -0
  41. package/es5/util/cancelablepromise.js.map +1 -1
  42. package/es5/util/constants.js +1 -0
  43. package/es5/util/constants.js.map +1 -1
  44. package/es5/util/index.js +22 -6
  45. package/es5/util/index.js.map +1 -1
  46. package/es5/util/sdp/index.js +31 -95
  47. package/es5/util/sdp/index.js.map +1 -1
  48. package/es5/util/sdp/issue8329.js +1 -2
  49. package/es5/util/sdp/issue8329.js.map +1 -1
  50. package/es5/util/sdp/simulcast.js +6 -29
  51. package/es5/util/sdp/simulcast.js.map +1 -1
  52. package/es5/util/sdp/{trackmatcher/mid.js → trackmatcher.js} +11 -11
  53. package/es5/util/sdp/trackmatcher.js.map +1 -0
  54. package/lib/connect.js +29 -3
  55. package/lib/encodingparameters.js +5 -1
  56. package/lib/localparticipant.js +5 -0
  57. package/lib/media/track/localmediatrack.js +2 -0
  58. package/lib/media/track/sender.js +36 -2
  59. package/lib/preflight/getturncredentials.ts +18 -9
  60. package/lib/preflight/preflighttest.ts +110 -74
  61. package/lib/signaling/v2/cancelableroomsignalingpromise.js +2 -0
  62. package/lib/signaling/v2/iceconnectionmonitor.js +3 -8
  63. package/lib/signaling/v2/localparticipant.js +41 -1
  64. package/lib/signaling/v2/networkqualitysignaling.js +24 -1
  65. package/lib/signaling/v2/peerconnection.js +270 -157
  66. package/lib/signaling/v2/peerconnectionmanager.js +9 -0
  67. package/lib/signaling/v2/publisherhintsignaling.js +71 -0
  68. package/lib/signaling/v2/renderhintssignaling.js +28 -17
  69. package/lib/signaling/v2/room.js +37 -1
  70. package/lib/signaling/v2/twilioconnectiontransport.js +7 -10
  71. package/lib/util/cancelablepromise.js +12 -0
  72. package/lib/util/constants.js +1 -0
  73. package/lib/util/index.js +21 -6
  74. package/lib/util/sdp/index.js +30 -102
  75. package/lib/util/sdp/issue8329.js +2 -3
  76. package/lib/util/sdp/simulcast.js +6 -31
  77. package/lib/util/sdp/{trackmatcher/mid.js → trackmatcher.js} +6 -6
  78. package/package.json +3 -3
  79. package/tsconfig.json +1 -1
  80. package/tsdef/PreflightTypes.d.ts +6 -2
  81. package/tsdef/index.d.ts +2 -2
  82. package/tsdef/preflighttest.d.ts +1 -1
  83. package/tsdef/twilio-video-tests.ts +19 -0
  84. package/tsdef/types.d.ts +6 -1
  85. package/es5/util/sdp/trackmatcher/identity.js +0 -25
  86. package/es5/util/sdp/trackmatcher/identity.js.map +0 -1
  87. package/es5/util/sdp/trackmatcher/mid.js.map +0 -1
  88. package/es5/util/sdp/trackmatcher/ordered.js +0 -111
  89. package/es5/util/sdp/trackmatcher/ordered.js.map +0 -1
  90. package/lib/util/sdp/trackmatcher/identity.js +0 -24
  91. package/lib/util/sdp/trackmatcher/ordered.js +0 -120
@@ -36,33 +36,27 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from) {
36
36
  return to;
37
37
  };
38
38
  var DefaultBackoff = require('backoff');
39
- var _a = require('@twilio/webrtc'), DefaultMediaStream = _a.MediaStream, DefaultRTCIceCandidate = _a.RTCIceCandidate, DefaultRTCPeerConnection = _a.RTCPeerConnection, DefaultRTCSessionDescription = _a.RTCSessionDescription, getStatistics = _a.getStats;
40
- var guessBrowser = require('@twilio/webrtc/lib/util').guessBrowser;
41
- var getSdpFormat = require('@twilio/webrtc/lib/util/sdp').getSdpFormat;
39
+ var _a = require('@twilio/webrtc'), DefaultRTCIceCandidate = _a.RTCIceCandidate, DefaultRTCPeerConnection = _a.RTCPeerConnection, DefaultRTCSessionDescription = _a.RTCSessionDescription, getStatistics = _a.getStats;
40
+ var util = require('@twilio/webrtc/lib/util');
42
41
  var _b = require('../../util/constants'), DEFAULT_ICE_GATHERING_TIMEOUT_MS = _b.DEFAULT_ICE_GATHERING_TIMEOUT_MS, DEFAULT_LOG_LEVEL = _b.DEFAULT_LOG_LEVEL, DEFAULT_SESSION_TIMEOUT_SEC = _b.DEFAULT_SESSION_TIMEOUT_SEC, iceRestartBackoffConfig = _b.iceRestartBackoffConfig;
43
- var _c = require('../../util/sdp'), createCodecMapForMediaSection = _c.createCodecMapForMediaSection, disableRtx = _c.disableRtx, enableDtxForOpus = _c.enableDtxForOpus, getMediaSections = _c.getMediaSections, removeSSRCAttributes = _c.removeSSRCAttributes, revertSimulcastForNonVP8MediaSections = _c.revertSimulcastForNonVP8MediaSections, setBitrateParameters = _c.setBitrateParameters, setCodecPreferences = _c.setCodecPreferences, setSimulcast = _c.setSimulcast, unifiedPlanAddOrRewriteNewTrackIds = _c.unifiedPlanAddOrRewriteNewTrackIds, unifiedPlanAddOrRewriteTrackIds = _c.unifiedPlanAddOrRewriteTrackIds, unifiedPlanFilterLocalCodecs = _c.unifiedPlanFilterLocalCodecs;
42
+ var _c = require('../../util/sdp'), addOrRewriteNewTrackIds = _c.addOrRewriteNewTrackIds, addOrRewriteTrackIds = _c.addOrRewriteTrackIds, createCodecMapForMediaSection = _c.createCodecMapForMediaSection, disableRtx = _c.disableRtx, enableDtxForOpus = _c.enableDtxForOpus, filterLocalCodecs = _c.filterLocalCodecs, getMediaSections = _c.getMediaSections, removeSSRCAttributes = _c.removeSSRCAttributes, revertSimulcast = _c.revertSimulcast, setCodecPreferences = _c.setCodecPreferences, setSimulcast = _c.setSimulcast;
44
43
  var DefaultTimeout = require('../../util/timeout');
45
44
  var _d = require('../../util/twilio-video-errors'), MediaClientLocalDescFailedError = _d.MediaClientLocalDescFailedError, MediaClientRemoteDescFailedError = _d.MediaClientRemoteDescFailedError;
46
- var _e = require('../../util'), buildLogLevels = _e.buildLogLevels, getPlatform = _e.getPlatform, isChromeScreenShareTrack = _e.isChromeScreenShareTrack, oncePerTick = _e.oncePerTick;
45
+ var _e = require('../../util'), buildLogLevels = _e.buildLogLevels, getPlatform = _e.getPlatform, isChromeScreenShareTrack = _e.isChromeScreenShareTrack, oncePerTick = _e.oncePerTick, defer = _e.defer;
47
46
  var IceBox = require('./icebox');
48
47
  var DefaultIceConnectionMonitor = require('./iceconnectionmonitor.js');
49
48
  var DataTrackReceiver = require('../../data/receiver');
50
49
  var MediaTrackReceiver = require('../../media/track/receiver');
51
50
  var StateMachine = require('../../statemachine');
52
51
  var Log = require('../../util/log');
53
- var IdentityTrackMatcher = require('../../util/sdp/trackmatcher/identity');
54
- var OrderedTrackMatcher = require('../../util/sdp/trackmatcher/ordered');
55
- var MIDTrackMatcher = require('../../util/sdp/trackmatcher/mid');
52
+ var TrackMatcher = require('../../util/sdp/trackmatcher');
56
53
  var workaroundIssue8329 = require('../../util/sdp/issue8329');
57
- var guess = guessBrowser();
54
+ var guess = util.guessBrowser();
58
55
  var platform = getPlatform();
59
56
  var isAndroid = /android/.test(platform);
60
57
  var isChrome = guess === 'chrome';
61
58
  var isFirefox = guess === 'firefox';
62
59
  var isSafari = guess === 'safari';
63
- var isRTCRtpSenderParamsSupported = typeof RTCRtpSender !== 'undefined'
64
- && typeof RTCRtpSender.prototype.getParameters === 'function'
65
- && typeof RTCRtpSender.prototype.setParameters === 'function';
66
60
  var nInstances = 0;
67
61
  /*
68
62
  PeerConnectionV2 States
@@ -119,26 +113,20 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
119
113
  dummyAudioMediaStreamTrack: null,
120
114
  isChromeScreenShareTrack: isChromeScreenShareTrack,
121
115
  iceServers: [],
122
- isRTCRtpSenderParamsSupported: isRTCRtpSenderParamsSupported,
123
116
  logLevel: DEFAULT_LOG_LEVEL,
124
117
  offerOptions: {},
125
- revertSimulcastForNonVP8MediaSections: revertSimulcastForNonVP8MediaSections,
118
+ revertSimulcast: revertSimulcast,
126
119
  sessionTimeout: DEFAULT_SESSION_TIMEOUT_SEC * 1000,
127
- setBitrateParameters: setBitrateParameters,
128
120
  setCodecPreferences: setCodecPreferences,
129
121
  setSimulcast: setSimulcast,
130
122
  Backoff: DefaultBackoff,
131
123
  IceConnectionMonitor: DefaultIceConnectionMonitor,
132
- MediaStream: DefaultMediaStream,
133
124
  RTCIceCandidate: DefaultRTCIceCandidate,
134
125
  RTCPeerConnection: DefaultRTCPeerConnection,
135
126
  RTCSessionDescription: DefaultRTCSessionDescription,
136
127
  Timeout: DefaultTimeout
137
128
  }, options);
138
129
  var configuration = getConfiguration(options);
139
- var sdpFormat = getSdpFormat(configuration.sdpSemantics);
140
- var isUnifiedPlan = sdpFormat === 'unified';
141
- var localMediaStream = isUnifiedPlan ? null : new options.MediaStream();
142
130
  var logLevels = buildLogLevels(options.logLevel);
143
131
  var RTCPeerConnection = options.RTCPeerConnection;
144
132
  if (options.enableDscp === true) {
@@ -149,7 +137,7 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
149
137
  var log = options.log ? options.log.createLog('webrtc', _this) : new Log('webrtc', _this, logLevels, options.loggerName);
150
138
  var peerConnection = new RTCPeerConnection(configuration, options.chromeSpecificConstraints);
151
139
  if (options.dummyAudioMediaStreamTrack) {
152
- peerConnection.addTrack(options.dummyAudioMediaStreamTrack, localMediaStream || new options.MediaStream());
140
+ peerConnection.addTrack(options.dummyAudioMediaStreamTrack);
153
141
  }
154
142
  Object.defineProperties(_this, {
155
143
  _appliedTrackIdsToAttributes: {
@@ -208,12 +196,6 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
208
196
  writable: true,
209
197
  value: false
210
198
  },
211
- _isUnifiedPlan: {
212
- value: isUnifiedPlan
213
- },
214
- _isRTCRtpSenderParamsSupported: {
215
- value: options.isRTCRtpSenderParamsSupported
216
- },
217
199
  _lastIceConnectionState: {
218
200
  writable: true,
219
201
  value: null
@@ -241,9 +223,6 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
241
223
  writable: true,
242
224
  value: null
243
225
  },
244
- _localMediaStream: {
245
- value: localMediaStream
246
- },
247
226
  _localUfrag: {
248
227
  writable: true,
249
228
  value: null
@@ -260,6 +239,9 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
260
239
  _rtpSenders: {
261
240
  value: new Map()
262
241
  },
242
+ _rtpNewSenders: {
243
+ value: new Set()
244
+ },
263
245
  _iceConnectionMonitor: {
264
246
  value: new options.IceConnectionMonitor(peerConnection)
265
247
  },
@@ -280,13 +262,9 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
280
262
  },
281
263
  _onEncodingParametersChanged: {
282
264
  value: oncePerTick(function () {
283
- if (_this._isRTCRtpSenderParamsSupported) {
284
- if (!_this._needsAnswer) {
285
- updateEncodingParameters(_this);
286
- }
287
- return;
265
+ if (!_this._needsAnswer) {
266
+ updateEncodingParameters(_this);
288
267
  }
289
- _this.offer();
290
268
  })
291
269
  },
292
270
  _peerConnection: {
@@ -308,9 +286,6 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
308
286
  return codec === 'opus' && dtx;
309
287
  })
310
288
  },
311
- _shouldApplySimulcast: {
312
- value: (isChrome || isSafari) && preferredCodecs.video.some(function (codecSettings) { return codecSettings.codec.toLowerCase() === 'vp8' && codecSettings.simulcast; })
313
- },
314
289
  _queuedDescription: {
315
290
  writable: true,
316
291
  value: null
@@ -334,12 +309,6 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
334
309
  writable: true,
335
310
  value: new IceBox()
336
311
  },
337
- _sdpFormat: {
338
- value: sdpFormat
339
- },
340
- _setBitrateParameters: {
341
- value: options.setBitrateParameters
342
- },
343
312
  _setCodecPreferences: {
344
313
  // NOTE(mmalavalli): Re-ordering payload types in order to make sure a non-H264
345
314
  // preferred codec is selected does not work on Android Firefox due to this behavior:
@@ -352,8 +321,8 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
352
321
  _setSimulcast: {
353
322
  value: options.setSimulcast
354
323
  },
355
- _revertSimulcastForNonVP8MediaSections: {
356
- value: options.revertSimulcastForNonVP8MediaSections
324
+ _revertSimulcast: {
325
+ value: options.revertSimulcast
357
326
  },
358
327
  _RTCIceCandidate: {
359
328
  value: options.RTCIceCandidate
@@ -380,6 +349,9 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
380
349
  writable: true,
381
350
  value: null
382
351
  },
352
+ _mediaTrackSenderToPublisherHints: {
353
+ value: new Map()
354
+ },
383
355
  id: {
384
356
  enumerable: true,
385
357
  value: id
@@ -409,6 +381,29 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
409
381
  PeerConnectionV2.prototype.toString = function () {
410
382
  return "[PeerConnectionV2 #" + this._instanceId + ": " + this.id + "]";
411
383
  };
384
+ PeerConnectionV2.prototype.setEffectiveAdaptiveSimulcast = function (effectiveAdaptiveSimulcast) {
385
+ this._log.debug('Setting setEffectiveAdaptiveSimulcast: ', effectiveAdaptiveSimulcast);
386
+ // clear adaptive simulcast from codec preferences if it was set.
387
+ this._preferredVideoCodecs.forEach(function (cs) {
388
+ if ('adaptiveSimulcast' in cs) {
389
+ cs.adaptiveSimulcast = effectiveAdaptiveSimulcast;
390
+ }
391
+ });
392
+ };
393
+ Object.defineProperty(PeerConnectionV2.prototype, "_shouldApplySimulcast", {
394
+ get: function () {
395
+ if (!isChrome && !isSafari) {
396
+ return false;
397
+ }
398
+ // adaptiveSimulcast is set to false after connected message is received if other party does not support it.
399
+ var simulcast = this._preferredVideoCodecs.some(function (cs) {
400
+ return cs.codec.toLowerCase() === 'vp8' && cs.simulcast && cs.adaptiveSimulcast !== false;
401
+ });
402
+ return simulcast;
403
+ },
404
+ enumerable: false,
405
+ configurable: true
406
+ });
412
407
  Object.defineProperty(PeerConnectionV2.prototype, "connectionState", {
413
408
  /**
414
409
  * The {@link PeerConnectionV2}'s underlying RTCPeerConnection's RTCPeerConnectionState
@@ -453,35 +448,97 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
453
448
  enumerable: false,
454
449
  configurable: true
455
450
  });
451
+ Object.defineProperty(PeerConnectionV2.prototype, "_isAdaptiveSimulcastEnabled", {
452
+ /**
453
+ * Whether adaptive simulcast is enabled.
454
+ * @returns {boolean}
455
+ */
456
+ get: function () {
457
+ var adaptiveSimulcastEntry = this._preferredVideoCodecs.find(function (cs) { return 'adaptiveSimulcast' in cs; });
458
+ return adaptiveSimulcastEntry && adaptiveSimulcastEntry.adaptiveSimulcast === true;
459
+ },
460
+ enumerable: false,
461
+ configurable: true
462
+ });
456
463
  /**
457
- * Updates scaleResolutionDownBy for encoding layers.
458
- * @param {number} width
459
- * @param {number} height
464
+ * @param {MediaStreamTrack} track
460
465
  * @param {Array<RTCRtpEncodingParameters>} encodings
466
+ * @param {boolean} trackReplaced
467
+ * @returns {boolean} true if encodings were updated.
461
468
  */
462
- PeerConnectionV2.prototype._updateEncodings = function (width, height, encodings) {
463
- var _this = this;
464
- // NOTE(mpatwardhan): All the simulcast encodings in Safari have
465
- // the same resolution. So, here we make sure that the lower layers have
466
- // lower resolution, as seen in Chrome.
467
- var pixelsToMaxActiveLayers = [
468
- { pixels: 960 * 540, maxActiveLayers: 3 },
469
- { pixels: 480 * 270, maxActiveLayers: 2 },
470
- { pixels: 0, maxActiveLayers: 1 }
471
- ];
472
- var trackPixels = width * height;
473
- var activeLayersInfo = pixelsToMaxActiveLayers.find(function (layer) { return trackPixels >= layer.pixels; });
474
- var activeLayers = Math.min(encodings.length, activeLayersInfo.maxActiveLayers);
475
- encodings.forEach(function (encoding, i) {
476
- encoding.active = i < activeLayers;
477
- if (encoding.active) {
478
- encoding.scaleResolutionDownBy = 1 << (activeLayers - i - 1);
479
- }
480
- else {
481
- delete encoding.scaleResolutionDownBy;
482
- }
483
- _this._log.debug("setting up simulcast layer " + i + " with active = " + encoding.active + ", scaleResolutionDownBy = " + encoding.scaleResolutionDownBy);
484
- });
469
+ PeerConnectionV2.prototype._maybeUpdateEncodings = function (track, encodings, trackReplaced) {
470
+ if (trackReplaced === void 0) { trackReplaced = false; }
471
+ if (track.kind !== 'video') {
472
+ return false;
473
+ }
474
+ var browser = util.guessBrowser();
475
+ // Note(mpatwardhan): always configure encodings for safari.
476
+ // for chrome only when adaptive simulcast enabled.
477
+ if (browser === 'safari' || (browser === 'chrome' && this._isAdaptiveSimulcastEnabled)) {
478
+ this._updateEncodings(track, encodings, trackReplaced);
479
+ return true;
480
+ }
481
+ return false;
482
+ };
483
+ /**
484
+ * Configures with default encodings depending on track type and resolution.
485
+ * Default configuration sets some encodings to disabled, and for others set scaleResolutionDownBy
486
+ * values. When trackReplaced is set to true, it will clear 'active' for any encodings that
487
+ * needs to be enabled.
488
+ * @param {MediaStreamTrack} track
489
+ * @param {Array<RTCRtpEncodingParameters>} encodings
490
+ * @param {boolean} trackReplaced
491
+ */
492
+ PeerConnectionV2.prototype._updateEncodings = function (track, encodings, trackReplaced) {
493
+ if (this._isChromeScreenShareTrack(track)) {
494
+ var screenShareActiveLayerConfig_1 = [
495
+ { scaleResolutionDownBy: 1 },
496
+ { scaleResolutionDownBy: 1 }
497
+ ];
498
+ encodings.forEach(function (encoding, i) {
499
+ var activeLayerConfig = screenShareActiveLayerConfig_1[i];
500
+ if (activeLayerConfig) {
501
+ encoding.scaleResolutionDownBy = activeLayerConfig.scaleResolutionDownBy;
502
+ if (trackReplaced) {
503
+ delete encoding.active;
504
+ }
505
+ }
506
+ else {
507
+ encoding.active = false;
508
+ delete encoding.scaleResolutionDownBy;
509
+ }
510
+ });
511
+ }
512
+ else {
513
+ var _a = track.getSettings(), width = _a.width, height = _a.height;
514
+ // NOTE(mpatwardhan): for non-screen share tracks
515
+ // enable layers depending on track resolutions
516
+ var pixelsToMaxActiveLayers = [
517
+ { pixels: 960 * 540, maxActiveLayers: 3 },
518
+ { pixels: 480 * 270, maxActiveLayers: 2 },
519
+ { pixels: 0, maxActiveLayers: 1 }
520
+ ];
521
+ var trackPixels_1 = width * height;
522
+ var activeLayersInfo = pixelsToMaxActiveLayers.find(function (layer) { return trackPixels_1 >= layer.pixels; });
523
+ var activeLayers_1 = Math.min(encodings.length, activeLayersInfo.maxActiveLayers);
524
+ encodings.forEach(function (encoding, i) {
525
+ var enabled = i < activeLayers_1;
526
+ if (enabled) {
527
+ encoding.scaleResolutionDownBy = 1 << (activeLayers_1 - i - 1);
528
+ if (trackReplaced) {
529
+ delete encoding.active;
530
+ }
531
+ }
532
+ else {
533
+ encoding.active = false;
534
+ delete encoding.scaleResolutionDownBy;
535
+ }
536
+ });
537
+ }
538
+ this._log.debug('_updateEncodings:', encodings.map(function (_a, i) {
539
+ var active = _a.active, scaleResolutionDownBy = _a.scaleResolutionDownBy;
540
+ return "[" + i + ": " + active + ", " + (scaleResolutionDownBy || 0) + "]";
541
+ }).join(', '));
485
542
  };
486
543
  /**
487
544
  * Add an ICE candidate to the {@link PeerConnectionV2}.
@@ -597,11 +654,11 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
597
654
  var updatedSdp = removeSSRCAttributes(answer.sdp, ['mslabel', 'label']);
598
655
  if (_this._shouldApplySimulcast) {
599
656
  var sdpWithoutSimulcast = updatedSdp;
600
- updatedSdp = _this._setSimulcast(sdpWithoutSimulcast, _this._sdpFormat, _this._trackIdsToAttributes);
657
+ updatedSdp = _this._setSimulcast(sdpWithoutSimulcast, _this._trackIdsToAttributes);
601
658
  // NOTE(syerrapragada): VMS does not support H264 simulcast. So,
602
659
  // unset simulcast for sections in local offer where corresponding
603
660
  // sections in answer doesn't have vp8 as preferred codec and reapply offer.
604
- updatedSdp = _this._revertSimulcastForNonVP8MediaSections(updatedSdp, sdpWithoutSimulcast, offer.sdp);
661
+ updatedSdp = _this._revertSimulcast(updatedSdp, sdpWithoutSimulcast, offer.sdp);
605
662
  }
606
663
  // NOTE(mmalavalli): Work around Chromium bug 1074421.
607
664
  // https://bugs.chromium.org/p/chromium/issues/detail?id=1074421
@@ -819,7 +876,7 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
819
876
  /**
820
877
  * Handle a track event.
821
878
  * @private
822
- * @param {Event} event
879
+ * @param {RTCTrackEvent} event
823
880
  * @returns {void}
824
881
  */
825
882
  PeerConnectionV2.prototype._handleTrackEvent = function (event) {
@@ -827,24 +884,16 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
827
884
  var sdp = this._peerConnection.remoteDescription
828
885
  ? this._peerConnection.remoteDescription.sdp
829
886
  : null;
830
- if (!this._trackMatcher) {
831
- this._trackMatcher = event.transceiver && event.transceiver.mid
832
- ? new MIDTrackMatcher()
833
- // NOTE(mroberts): Until Chrome ships RTCRtpTransceivers with MID
834
- // support, we have to use the same hacky solution as Safari. Revisit
835
- // this when RTCRtpTransceivers and MIDs land. We should be able to use
836
- // the same technique as Firefox.
837
- : isSafari || this._isUnifiedPlan ? new OrderedTrackMatcher() : new IdentityTrackMatcher();
838
- }
887
+ this._trackMatcher = this._trackMatcher || new TrackMatcher();
839
888
  this._trackMatcher.update(sdp);
840
889
  var mediaStreamTrack = event.track;
841
890
  var signaledTrackId = this._trackMatcher.match(event) || mediaStreamTrack.id;
842
891
  var mediaTrackReceiver = new MediaTrackReceiver(signaledTrackId, mediaStreamTrack);
843
- // NOTE(mmalavalli): In unified plan mode, "ended" is not fired on the remote
844
- // MediaStreamTrack when the remote peer removes a track. So, when this
845
- // MediaStreamTrack is re-used for a different track due to the remote peer
846
- // calling RTCRtpSender.replaceTrack(), we delete the previous MediaTrackReceiver
847
- // that owned this MediaStreamTrack before adding the new MediaTrackReceiver.
892
+ // NOTE(mmalavalli): "ended" is not fired on the remote MediaStreamTrack when
893
+ // the remote peer removes a track. So, when this MediaStreamTrack is re-used
894
+ // for a different track due to the remote peer calling RTCRtpSender.replaceTrack(),
895
+ // we delete the previous MediaTrackReceiver that owned this MediaStreamTrack
896
+ // before adding the new MediaTrackReceiver.
848
897
  this._mediaTrackReceivers.forEach(function (trackReceiver) {
849
898
  if (trackReceiver.track.id === mediaTrackReceiver.track.id) {
850
899
  _this._mediaTrackReceivers.delete(trackReceiver);
@@ -899,18 +948,16 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
899
948
  PeerConnectionV2.prototype._maybeReoffer = function (localDescription) {
900
949
  var shouldReoffer = this._shouldOffer;
901
950
  if (localDescription && localDescription.sdp) {
902
- // NOTE(mmalavalli): For "unified-plan" sdps, if the local RTCSessionDescription
903
- // has fewer audio and/or video send* m= lines than the corresponding RTCRtpSenders
904
- // with non-null MediaStreamTracks, it means that the newly added RTCRtpSenders
905
- // require renegotiation.
906
- if (this._isUnifiedPlan) {
907
- var senders_1 = this._peerConnection.getSenders().filter(function (sender) { return sender.track; });
908
- shouldReoffer = ['audio', 'video'].reduce(function (shouldOffer, kind) {
909
- var mediaSections = getMediaSections(localDescription.sdp, kind, '(sendrecv|sendonly)');
910
- var sendersOfKind = senders_1.filter(isSenderOfKind.bind(null, kind));
911
- return shouldOffer || (mediaSections.length < sendersOfKind.length);
912
- }, shouldReoffer);
913
- }
951
+ // NOTE(mmalavalli): If the local RTCSessionDescription has fewer audio and/or
952
+ // video send* m= lines than the corresponding RTCRtpSenders with non-null
953
+ // MediaStreamTracks, it means that the newly added RTCRtpSenders require
954
+ // renegotiation.
955
+ var senders_1 = this._peerConnection.getSenders().filter(function (sender) { return sender.track; });
956
+ shouldReoffer = ['audio', 'video'].reduce(function (shouldOffer, kind) {
957
+ var mediaSections = getMediaSections(localDescription.sdp, kind, '(sendrecv|sendonly)');
958
+ var sendersOfKind = senders_1.filter(isSenderOfKind.bind(null, kind));
959
+ return shouldOffer || (mediaSections.length < sendersOfKind.length);
960
+ }, shouldReoffer);
914
961
  // NOTE(mroberts): We also need to re-offer if we have a DataTrack to share
915
962
  // but no m= application section.
916
963
  var hasDataTrack = this._dataChannels.size > 0;
@@ -964,8 +1011,8 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
964
1011
  // Looks like we are not referencing those attributes, but this changes goes ahead and removes them to see if it works.
965
1012
  // this also helps reduce bytes on wires
966
1013
  var sdp = removeSSRCAttributes(offer.sdp, ['mslabel', 'label']);
967
- sdp = _this._isUnifiedPlan && _this._peerConnection.remoteDescription
968
- ? unifiedPlanFilterLocalCodecs(sdp, _this._peerConnection.remoteDescription.sdp)
1014
+ sdp = _this._peerConnection.remoteDescription
1015
+ ? filterLocalCodecs(sdp, _this._peerConnection.remoteDescription.sdp)
969
1016
  : sdp;
970
1017
  var updatedSdp = _this._setCodecPreferences(sdp, _this._preferredAudioCodecs, _this._preferredVideoCodecs);
971
1018
  _this._shouldOffer = false;
@@ -977,7 +1024,7 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
977
1024
  type: 'offer',
978
1025
  sdp: updatedSdp
979
1026
  };
980
- updatedSdp = _this._setSimulcast(updatedSdp, _this._sdpFormat, _this._trackIdsToAttributes);
1027
+ updatedSdp = _this._setSimulcast(updatedSdp, _this._trackIdsToAttributes);
981
1028
  }
982
1029
  return _this._setLocalDescription({
983
1030
  type: 'offer',
@@ -1001,7 +1048,7 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
1001
1048
  return mediaTrackSender ? mediaTrackSender.id : trackId;
1002
1049
  };
1003
1050
  /**
1004
- * Add or rewrite local MediaStreamTrack IDs in the given Unified Plan RTCSessionDescription.
1051
+ * Add or rewrite local MediaStreamTrack IDs in the given RTCSessionDescription.
1005
1052
  * @private
1006
1053
  * @param {RTCSessionDescription} description
1007
1054
  * @return {RTCSessionDescription}
@@ -1025,7 +1072,7 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
1025
1072
  var mid = _a.mid, sender = _a.sender;
1026
1073
  return [mid, _this._getMediaTrackSenderId(sender.track.id)];
1027
1074
  }));
1028
- var sdp1 = unifiedPlanAddOrRewriteTrackIds(description.sdp, midsToTrackIds);
1075
+ var sdp1 = addOrRewriteTrackIds(description.sdp, midsToTrackIds);
1029
1076
  // NOTE(mmalavalli): Chrome and Safari do not apply the offer until they get an answer.
1030
1077
  // So, we add or re-write the actual MediaStreamTrack IDs to the unassigned m= sections here.
1031
1078
  var unassignedTransceivers = activeTransceivers.filter(function (_a) {
@@ -1042,7 +1089,7 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
1042
1089
  return _this._getMediaTrackSenderId(sender.track.id);
1043
1090
  })
1044
1091
  ]; }));
1045
- var sdp2 = unifiedPlanAddOrRewriteNewTrackIds(sdp1, midsToTrackIds, newTrackIdsByKind);
1092
+ var sdp2 = addOrRewriteNewTrackIds(sdp1, midsToTrackIds, newTrackIdsByKind);
1046
1093
  return new this._RTCSessionDescription({
1047
1094
  sdp: sdp2,
1048
1095
  type: description.type
@@ -1073,7 +1120,7 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
1073
1120
  });
1074
1121
  }
1075
1122
  return this._peerConnection.setLocalDescription(description).catch(function (error) {
1076
- _this._log.warn("Calling setLocalDescription with an RTCSessionDescription of type \"" + description.type + "\" failed with the error \"" + error.message + "\".");
1123
+ _this._log.warn("Calling setLocalDescription with an RTCSessionDescription of type \"" + description.type + "\" failed with the error \"" + error.message + "\".", error);
1077
1124
  var errorToThrow = new MediaClientLocalDescFailedError();
1078
1125
  var publishWarning = {
1079
1126
  message: "Calling setLocalDescription with an RTCSessionDescription of type \"" + description.type + "\" failed",
@@ -1088,7 +1135,7 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
1088
1135
  throw errorToThrow;
1089
1136
  }).then(function () {
1090
1137
  if (description.type !== 'rollback') {
1091
- _this._localDescription = _this._isUnifiedPlan ? _this._addOrRewriteLocalTrackIds(description) : description;
1138
+ _this._localDescription = _this._addOrRewriteLocalTrackIds(description);
1092
1139
  // NOTE(mmalavalli): In order for this feature to be backward compatible with older
1093
1140
  // SDK versions which to not support opus DTX, we append "usedtx=1" to the local SDP
1094
1141
  // only while applying it. We will not send it over the wire to prevent inadvertent
@@ -1122,9 +1169,6 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
1122
1169
  PeerConnectionV2.prototype._setRemoteDescription = function (description) {
1123
1170
  var _this = this;
1124
1171
  if (description.sdp) {
1125
- if (!this._isRTCRtpSenderParamsSupported) {
1126
- description.sdp = this._setBitrateParameters(description.sdp, isFirefox ? 'TIAS' : 'AS', this._encodingParameters.maxAudioBitrate, this._encodingParameters.maxVideoBitrate);
1127
- }
1128
1172
  description.sdp = this._setCodecPreferences(description.sdp, this._preferredAudioCodecs, this._preferredVideoCodecs);
1129
1173
  if (this._shouldApplyDtx) {
1130
1174
  description.sdp = enableDtxForOpus(description.sdp);
@@ -1151,8 +1195,13 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
1151
1195
  // NOTE(syerrapragada): VMS does not support H264 simulcast. So,
1152
1196
  // unset simulcast for sections in local offer where corresponding
1153
1197
  // sections in answer doesn't have vp8 as preferred codec and reapply offer.
1154
- if (description.type === 'answer' && _this._shouldApplySimulcast) {
1155
- var sdpWithoutSimulcastForNonVP8MediaSections = _this._revertSimulcastForNonVP8MediaSections(_this._localDescription.sdp, _this._localDescriptionWithoutSimulcast.sdp, description.sdp);
1198
+ if (description.type === 'answer' && _this._localDescriptionWithoutSimulcast) {
1199
+ // NOTE(mpatwardhan):if we were using adaptive simulcast, and if its not supported by server
1200
+ // revert simulcast even for vp8.
1201
+ var adaptiveSimulcastEntry = _this._preferredVideoCodecs.find(function (cs) { return 'adaptiveSimulcast' in cs; });
1202
+ var revertForAll = !!adaptiveSimulcastEntry && adaptiveSimulcastEntry.adaptiveSimulcast === false;
1203
+ var sdpWithoutSimulcastForNonVP8MediaSections = _this._revertSimulcast(_this._localDescription.sdp, _this._localDescriptionWithoutSimulcast.sdp, description.sdp, revertForAll);
1204
+ _this._localDescriptionWithoutSimulcast = null;
1156
1205
  if (sdpWithoutSimulcastForNonVP8MediaSections !== _this._localDescription.sdp) {
1157
1206
  return _this._rollbackAndApplyOffer({
1158
1207
  type: _this._localDescription.type,
@@ -1169,7 +1218,7 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
1169
1218
  negotiationCompleted(_this);
1170
1219
  }
1171
1220
  }, function (error) {
1172
- _this._log.warn("Calling setRemoteDescription with an RTCSessionDescription of type \"" + description.type + "\" failed with the error \"" + error.message + "\".");
1221
+ _this._log.warn("Calling setRemoteDescription with an RTCSessionDescription of type \"" + description.type + "\" failed with the error \"" + error.message + "\".", error);
1173
1222
  if (description.sdp) {
1174
1223
  _this._log.warn("The SDP was " + description.sdp);
1175
1224
  }
@@ -1293,25 +1342,89 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
1293
1342
  this._log.warn("Error creating an RTCDataChannel for DataTrack \"" + dataTrackSender.id + "\": " + error.message);
1294
1343
  }
1295
1344
  };
1345
+ PeerConnectionV2.prototype._handleQueuedPublisherHints = function () {
1346
+ var _this = this;
1347
+ if (this._peerConnection.signalingState === 'stable') {
1348
+ this._mediaTrackSenderToPublisherHints.forEach(function (_a, mediaTrackSender) {
1349
+ var deferred = _a.deferred, encodings = _a.encodings;
1350
+ _this._mediaTrackSenderToPublisherHints.delete(mediaTrackSender);
1351
+ _this._setPublisherHint(mediaTrackSender, encodings)
1352
+ .then(function (result) { return deferred.resolve(result); })
1353
+ .catch(function (error) { return deferred.reject(error); });
1354
+ });
1355
+ }
1356
+ };
1357
+ /**
1358
+ * updates encodings for simulcast layers of given sender.
1359
+ * @param {RTCRtpSender} sender
1360
+ * @param {Array<{enabled: boolean, layer_index: number}>|null} encodings
1361
+ * @returns {Promise<string>} string indicating result of the operation. can be one of
1362
+ * "OK", "INVALID_HINT", "COULD_NOT_APPLY_HINT", "UNKNOWN_TRACK"
1363
+ */
1364
+ PeerConnectionV2.prototype._setPublisherHint = function (mediaTrackSender, encodings) {
1365
+ var _this = this;
1366
+ if (isFirefox) {
1367
+ return Promise.resolve('COULD_NOT_APPLY_HINT');
1368
+ }
1369
+ if (this._mediaTrackSenderToPublisherHints.has(mediaTrackSender)) {
1370
+ // skip any stale hint associated with the mediaTrackSender.
1371
+ var queuedHint = this._mediaTrackSenderToPublisherHints.get(mediaTrackSender);
1372
+ queuedHint.deferred.resolve('REQUEST_SKIPPED');
1373
+ this._mediaTrackSenderToPublisherHints.delete(mediaTrackSender);
1374
+ }
1375
+ var sender = this._rtpSenders.get(mediaTrackSender);
1376
+ if (!sender) {
1377
+ this._log.warn('Could not apply publisher hint because RTCRtpSender was not found');
1378
+ return Promise.resolve('UNKNOWN_TRACK');
1379
+ }
1380
+ if (this._peerConnection.signalingState === 'closed') {
1381
+ this._log.warn('Could not apply publisher hint because signalingState was "closed"');
1382
+ return Promise.resolve('COULD_NOT_APPLY_HINT');
1383
+ }
1384
+ if (this._peerConnection.signalingState !== 'stable') {
1385
+ // enqueue this hint to be applied when pc becomes stable.
1386
+ this._log.debug('Queuing up publisher hint because signalingState:', this._peerConnection.signalingState);
1387
+ var deferred = defer();
1388
+ this._mediaTrackSenderToPublisherHints.set(mediaTrackSender, { deferred: deferred, encodings: encodings });
1389
+ return deferred.promise;
1390
+ }
1391
+ var parameters = sender.getParameters();
1392
+ if (encodings !== null) {
1393
+ encodings.forEach(function (_a) {
1394
+ var enabled = _a.enabled, layerIndex = _a.layer_index;
1395
+ if (parameters.encodings.length > layerIndex) {
1396
+ _this._log.debug("layer:" + layerIndex + ", active:" + parameters.encodings[layerIndex].active + " => " + enabled);
1397
+ parameters.encodings[layerIndex].active = enabled;
1398
+ }
1399
+ else {
1400
+ _this._log.warn("invalid layer:" + layerIndex + ", active:" + enabled);
1401
+ }
1402
+ });
1403
+ }
1404
+ // Note(mpatwardhan): after publisher hints are applied, overwrite with default encodings
1405
+ // to disable any encoding that shouldn't have been enabled by publisher_hints.
1406
+ // When encodings===null (that is we are asked to reset encodings for replaceTrack)
1407
+ // along with disabling encodings, clear active flag for encodings that should not be disabled
1408
+ this._maybeUpdateEncodings(sender.track, parameters.encodings, encodings === null /* trackReplaced */);
1409
+ return sender.setParameters(parameters).then(function () { return 'OK'; }).catch(function (error) {
1410
+ _this._log.error('Failed to apply publisher hints:', error);
1411
+ return 'COULD_NOT_APPLY_HINT';
1412
+ });
1413
+ };
1296
1414
  /**
1297
1415
  * Add the {@link MediaTrackSender} to the {@link PeerConnectionV2}.
1298
1416
  * @param {MediaTrackSender} mediaTrackSender
1299
1417
  * @returns {void}
1300
1418
  */
1301
1419
  PeerConnectionV2.prototype.addMediaTrackSender = function (mediaTrackSender) {
1420
+ var _this = this;
1302
1421
  if (this._peerConnection.signalingState === 'closed' || this._rtpSenders.has(mediaTrackSender)) {
1303
1422
  return;
1304
1423
  }
1305
- var sender;
1306
- if (this._localMediaStream) {
1307
- this._localMediaStream.addTrack(mediaTrackSender.track);
1308
- sender = this._peerConnection.addTrack(mediaTrackSender.track, this._localMediaStream);
1309
- }
1310
- else {
1311
- var transceiver = this._addOrUpdateTransceiver(mediaTrackSender.track);
1312
- sender = transceiver.sender;
1313
- }
1314
- mediaTrackSender.addSender(sender);
1424
+ var transceiver = this._addOrUpdateTransceiver(mediaTrackSender.track);
1425
+ var sender = transceiver.sender;
1426
+ mediaTrackSender.addSender(sender, function (encodings) { return _this._setPublisherHint(mediaTrackSender, encodings); });
1427
+ this._rtpNewSenders.add(sender);
1315
1428
  this._rtpSenders.set(mediaTrackSender, sender);
1316
1429
  };
1317
1430
  /**
@@ -1326,7 +1439,7 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
1326
1439
  }
1327
1440
  };
1328
1441
  /**
1329
- * Get the {@link DataTrackReceiver}s and the {@link MediaTrackReceivers} on the
1442
+ * Get the {@link DataTrackReceiver}s and the {@link MediaTrackReceiver}s on the
1330
1443
  * {@link PeerConnectionV2}.
1331
1444
  * @returns {Array<DataTrackReceiver|MediaTrackReceiver>} trackReceivers
1332
1445
  */
@@ -1405,10 +1518,14 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
1405
1518
  if (this._peerConnection.signalingState !== 'closed') {
1406
1519
  this._peerConnection.removeTrack(sender);
1407
1520
  }
1408
- if (this._localMediaStream) {
1409
- this._localMediaStream.removeTrack(mediaTrackSender.track);
1410
- }
1411
1521
  mediaTrackSender.removeSender(sender);
1522
+ // clean up any pending publisher hints associated with this mediaTrackSender.
1523
+ if (this._mediaTrackSenderToPublisherHints.has(mediaTrackSender)) {
1524
+ var queuedHint = this._mediaTrackSenderToPublisherHints.get(mediaTrackSender);
1525
+ queuedHint.deferred.resolve('UNKNOWN_TRACK');
1526
+ this._mediaTrackSenderToPublisherHints.delete(mediaTrackSender);
1527
+ }
1528
+ this._rtpNewSenders.delete(sender);
1412
1529
  this._rtpSenders.delete(mediaTrackSender);
1413
1530
  };
1414
1531
  /**
@@ -1587,7 +1704,7 @@ function takeRecycledTransceiver(pcv2, kind) {
1587
1704
  */
1588
1705
  function updateLocalCodecs(pcv2) {
1589
1706
  var description = pcv2._peerConnection.localDescription;
1590
- if (!description) {
1707
+ if (!description || !description.sdp) {
1591
1708
  return;
1592
1709
  }
1593
1710
  getMediaSections(description.sdp).forEach(function (section) {
@@ -1602,11 +1719,15 @@ function updateLocalCodecs(pcv2) {
1602
1719
  */
1603
1720
  function updateRemoteCodecMaps(pcv2) {
1604
1721
  var description = pcv2._peerConnection.remoteDescription;
1605
- if (!description) {
1722
+ if (!description || !description.sdp) {
1606
1723
  return;
1607
1724
  }
1608
1725
  getMediaSections(description.sdp).forEach(function (section) {
1609
- var mid = section.match(/^a=mid:(.+)$/m)[1];
1726
+ var matched = section.match(/^a=mid:(.+)$/m);
1727
+ if (!matched || !matched[1]) {
1728
+ return;
1729
+ }
1730
+ var mid = matched[1];
1610
1731
  var codecMap = createCodecMapForMediaSection(section);
1611
1732
  pcv2._remoteCodecMaps.set(mid, codecMap);
1612
1733
  });
@@ -1631,14 +1752,13 @@ function updateRecycledTransceivers(pcv2) {
1631
1752
  * @returns {void}
1632
1753
  */
1633
1754
  function negotiationCompleted(pcv2) {
1634
- if (pcv2._isUnifiedPlan) {
1635
- updateRecycledTransceivers(pcv2);
1636
- updateLocalCodecs(pcv2);
1637
- updateRemoteCodecMaps(pcv2);
1638
- }
1639
- if (pcv2._isRTCRtpSenderParamsSupported) {
1640
- updateEncodingParameters(pcv2);
1641
- }
1755
+ updateRecycledTransceivers(pcv2);
1756
+ updateLocalCodecs(pcv2);
1757
+ updateRemoteCodecMaps(pcv2);
1758
+ updateEncodingParameters(pcv2).then(function () {
1759
+ // if there any any publisher hints queued, apply them now.
1760
+ pcv2._handleQueuedPublisherHints();
1761
+ });
1642
1762
  }
1643
1763
  /**
1644
1764
  * Update the RTCRtpEncodingParameters of all active RTCRtpSenders.
@@ -1651,6 +1771,7 @@ function updateEncodingParameters(pcv2) {
1651
1771
  ['audio', maxAudioBitrate],
1652
1772
  ['video', maxVideoBitrate]
1653
1773
  ]);
1774
+ var promises = [];
1654
1775
  pcv2._peerConnection.getSenders().filter(function (sender) { return sender.track; }).forEach(function (sender) {
1655
1776
  var maxBitrate = maxBitrates.get(sender.track.kind);
1656
1777
  var params = sender.getParameters();
@@ -1673,14 +1794,16 @@ function updateEncodingParameters(pcv2) {
1673
1794
  // by RTCRtpSender.setParameters() being rejected.
1674
1795
  params.encodings[0].networkPriority = 'high';
1675
1796
  }
1676
- if (isSafari && sender.track.kind === 'video') {
1677
- var _a = sender.track.getSettings(), width = _a.width, height = _a.height;
1678
- pcv2._updateEncodings(width, height, params.encodings);
1679
- }
1680
- sender.setParameters(params).catch(function (error) {
1797
+ // when a sender is reused, delete any active encodings set by server.
1798
+ var trackReplaced = pcv2._rtpNewSenders.has(sender);
1799
+ pcv2._maybeUpdateEncodings(sender.track, params.encodings, trackReplaced);
1800
+ pcv2._rtpNewSenders.delete(sender);
1801
+ var promise = sender.setParameters(params).catch(function (error) {
1681
1802
  pcv2._log.warn("Error while setting encodings parameters for " + sender.track.kind + " Track " + sender.track.id + ": " + (error.message || error.name));
1682
1803
  });
1804
+ promises.push(promise);
1683
1805
  });
1806
+ return Promise.all(promises);
1684
1807
  }
1685
1808
  /**
1686
1809
  * Remove maxBitrate from the RTCRtpSendParameters' encodings.