@webex/web-client-media-engine 2.1.1 → 2.1.3

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.
package/dist/cjs/index.js CHANGED
@@ -8859,6 +8859,30 @@ function eventTargetAgnosticAddListener(emitter, name, listener, flags) {
8859
8859
  class EventEmitter extends events.exports.EventEmitter {
8860
8860
  }
8861
8861
 
8862
+ class MidPredictor {
8863
+ constructor() {
8864
+ this.currentMid = 0;
8865
+ this.midMap = new Map();
8866
+ }
8867
+ getNextMid(mediaType) {
8868
+ const mid = this.currentMid++;
8869
+ const mids = this.midMap.get(mediaType) || [];
8870
+ mids.push(`${mid}`);
8871
+ this.midMap.set(mediaType, mids);
8872
+ return `${mid}`;
8873
+ }
8874
+ allocateMidForDatachannel() {
8875
+ this.currentMid += 1;
8876
+ }
8877
+ reset() {
8878
+ this.midMap = new Map();
8879
+ this.currentMid = 0;
8880
+ }
8881
+ getMidMap() {
8882
+ return this.midMap;
8883
+ }
8884
+ }
8885
+
8862
8886
  var OveruseState;
8863
8887
  (function (OveruseState) {
8864
8888
  OveruseState[OveruseState["NOT_OVERUSED"] = 0] = "NOT_OVERUSED";
@@ -8966,8 +8990,9 @@ class ReceiveSlot extends EventEmitter {
8966
8990
  ReceiveSlot.Events = exports.ReceiveSlotEvents;
8967
8991
 
8968
8992
  class Transceiver {
8969
- constructor(rtcRtpTransceiver) {
8993
+ constructor(rtcRtpTransceiver, mid) {
8970
8994
  this._rtcRtpTransceiver = rtcRtpTransceiver;
8995
+ this.mid = mid;
8971
8996
  }
8972
8997
  replaceTransceiver(newRtcRtpTransceiver) {
8973
8998
  this._rtcRtpTransceiver = newRtcRtpTransceiver;
@@ -8978,22 +9003,20 @@ class Transceiver {
8978
9003
  get sender() {
8979
9004
  return this._rtcRtpTransceiver.sender;
8980
9005
  }
8981
- get mid() {
8982
- return this._rtcRtpTransceiver.mid;
8983
- }
8984
9006
  close() {
8985
9007
  this._rtcRtpTransceiver.stop();
8986
9008
  }
8987
9009
  }
8988
9010
 
8989
9011
  class ReceiveOnlyTransceiver extends Transceiver {
8990
- constructor(rtcRtpTransceiver, idGetter) {
8991
- super(rtcRtpTransceiver);
9012
+ constructor(rtcRtpTransceiver, mid, signaler) {
9013
+ super(rtcRtpTransceiver, mid);
9014
+ this.streamSignaler = signaler;
8992
9015
  this._receiveSlot = new ReceiveSlot(() => {
8993
9016
  if (!this._rtcRtpTransceiver.mid) {
8994
9017
  return null;
8995
9018
  }
8996
- return idGetter(this._rtcRtpTransceiver.mid);
9019
+ return this.streamSignaler.getReceiverId();
8997
9020
  }, this._rtcRtpTransceiver.receiver.track);
8998
9021
  }
8999
9022
  replaceTransceiver(newRtcRtpTransceiver) {
@@ -9010,62 +9033,21 @@ class ReceiveOnlyTransceiver extends Transceiver {
9010
9033
  getStats() {
9011
9034
  return this.receiver.getStats();
9012
9035
  }
9036
+ signalLocalStreams(mLine) {
9037
+ this.streamSignaler.signalLocalStreams(mLine);
9038
+ }
9039
+ signalRemoteStreams(mLine) {
9040
+ this.streamSignaler.signalRemoteStreams(mLine);
9041
+ }
9042
+ get receiverId() {
9043
+ return this.streamSignaler.getReceiverId();
9044
+ }
9045
+ resetStreamSignaler() {
9046
+ this.streamSignaler.reset();
9047
+ }
9013
9048
  }
9014
9049
  ReceiveOnlyTransceiver.rid = '1';
9015
9050
 
9016
- function deepCopy(source) {
9017
- return Array.isArray(source)
9018
- ? source.map((item) => deepCopy(item))
9019
- : source instanceof Map
9020
- ? new Map(source)
9021
- : source instanceof Date
9022
- ? new Date(source.getTime())
9023
- : source && typeof source === 'object'
9024
- ? Object.getOwnPropertyNames(source).reduce((o, prop) => {
9025
- Object.defineProperty(o, prop, Object.getOwnPropertyDescriptor(source, prop));
9026
- o[prop] = deepCopy(source[prop]);
9027
- return o;
9028
- }, Object.create(Object.getPrototypeOf(source)))
9029
- : source;
9030
- }
9031
-
9032
- function matchMlinesInAnswer(parsedOffer, parsedAnswer, streamSignalerManager) {
9033
- parsedAnswer.session.groups = parsedOffer.session.groups;
9034
- parsedAnswer.media = parsedOffer.media.map((offerMline) => {
9035
- if (!offerMline.mid) {
9036
- throw new Error(`Offer mline is missing MID`);
9037
- }
9038
- const answerMline = parsedAnswer.media.find((m) => m.mid === offerMline.mid);
9039
- if (answerMline) {
9040
- if (answerMline instanceof AvMediaDescription) {
9041
- [...answerMline.codecs.values()].forEach((ci) => {
9042
- ci.fmtParams.set('x-google-start-bitrate', '60000');
9043
- });
9044
- }
9045
- return answerMline;
9046
- }
9047
- if (!(offerMline instanceof AvMediaDescription)) {
9048
- throw new Error(`Answer is missing a non-media mline: ${offerMline.mid}`);
9049
- }
9050
- const startingMline = parsedAnswer.avMedia.find((m) => m.type === offerMline.type);
9051
- if (!startingMline) {
9052
- throw new Error(`Answer has no mline of type ${offerMline.type}, can't generate synthetic answer mline for mid ${offerMline.mid}`);
9053
- }
9054
- const fakeCorrespondingMline = deepCopy(startingMline);
9055
- fakeCorrespondingMline.mid = offerMline.mid;
9056
- fakeCorrespondingMline.simulcast = undefined;
9057
- if (offerMline.direction === 'sendrecv' || offerMline.direction === 'sendonly') {
9058
- fakeCorrespondingMline.direction = 'recvonly';
9059
- }
9060
- if (offerMline.direction === 'recvonly') {
9061
- fakeCorrespondingMline.direction = 'sendonly';
9062
- const ingressSignaler = streamSignalerManager.getIngressStreamSignalerOrThrow(offerMline.mid);
9063
- ingressSignaler.signalRemoteStreams(fakeCorrespondingMline);
9064
- }
9065
- return fakeCorrespondingMline;
9066
- });
9067
- }
9068
-
9069
9051
  class JmpLine extends Line {
9070
9052
  constructor(versions) {
9071
9053
  super();
@@ -9239,9 +9221,6 @@ function injectDummyCandidates(parsedSdp) {
9239
9221
  }
9240
9222
  });
9241
9223
  }
9242
- function hasSimulcast(av) {
9243
- return !!av.simulcast || av.ssrcGroups.map((sg) => sg.semantics).some((sem) => sem === 'SIM');
9244
- }
9245
9224
  function addVlaExtension(mLine) {
9246
9225
  const vlaUri = 'http://www.webrtc.org/experiments/rtp-hdrext/video-layers-allocation00';
9247
9226
  if (mLine.extMaps.findIndex((extMapLine) => extMapLine.uri === vlaUri) === -1) {
@@ -9251,13 +9230,147 @@ function addVlaExtension(mLine) {
9251
9230
  }
9252
9231
  }
9253
9232
 
9233
+ const simulcastMaxFrameSizes = {
9234
+ 0: '240',
9235
+ 1: '2304',
9236
+ 2: '8160',
9237
+ };
9238
+
9239
+ class RidIngressStreamSignaler {
9240
+ constructor(mid) {
9241
+ this.mid = mid;
9242
+ }
9243
+ getReceiverId() {
9244
+ return {
9245
+ mid: this.mid,
9246
+ rid: '1',
9247
+ };
9248
+ }
9249
+ signalLocalStreams(mLine) {
9250
+ }
9251
+ signalRemoteStreams(mLine) {
9252
+ }
9253
+ reset() {
9254
+ }
9255
+ }
9256
+ class RidEgressStreamSignaler {
9257
+ constructor(mid) {
9258
+ this.streamIds = [];
9259
+ this.mid = mid;
9260
+ }
9261
+ signalStreams(simulcastEnabled, _rtxEnabled, mLine) {
9262
+ mLine.ssrcGroups = [];
9263
+ if (this.streamIds.length === 0) {
9264
+ if (simulcastEnabled) {
9265
+ this.streamIds = [
9266
+ {
9267
+ mid: this.mid,
9268
+ rid: 'low',
9269
+ },
9270
+ {
9271
+ mid: this.mid,
9272
+ rid: 'medium',
9273
+ },
9274
+ {
9275
+ mid: this.mid,
9276
+ rid: 'high',
9277
+ },
9278
+ ];
9279
+ }
9280
+ else {
9281
+ this.streamIds = [
9282
+ {
9283
+ mid: this.mid,
9284
+ },
9285
+ ];
9286
+ }
9287
+ }
9288
+ if (simulcastEnabled) {
9289
+ mLine.rids = this.streamIds.map((streamId, index) => new RidLine(streamId.rid, 'send', `max-fs=${simulcastMaxFrameSizes[index]}`));
9290
+ mLine.simulcast = new SimulcastLine(SimulcastLayerList.fromString('low;medium;high'), new SimulcastLayerList());
9291
+ addVlaExtension(mLine);
9292
+ }
9293
+ }
9294
+ getSenderIds() {
9295
+ return this.streamIds;
9296
+ }
9297
+ reset() {
9298
+ this.streamIds = [];
9299
+ }
9300
+ getEncodingIndexForStreamId(streamId) {
9301
+ return this.streamIds.findIndex((currStreamId) => compareStreamIds(currStreamId, streamId));
9302
+ }
9303
+ setCodecParameters(parameters) {
9304
+ }
9305
+ deleteCodecParameters(parameters) {
9306
+ }
9307
+ }
9308
+
9309
+ function deepCopy(source) {
9310
+ return Array.isArray(source)
9311
+ ? source.map((item) => deepCopy(item))
9312
+ : source instanceof Map
9313
+ ? new Map(source)
9314
+ : source instanceof Date
9315
+ ? new Date(source.getTime())
9316
+ : source && typeof source === 'object'
9317
+ ? Object.getOwnPropertyNames(source).reduce((o, prop) => {
9318
+ Object.defineProperty(o, prop, Object.getOwnPropertyDescriptor(source, prop));
9319
+ o[prop] = deepCopy(source[prop]);
9320
+ return o;
9321
+ }, Object.create(Object.getPrototypeOf(source)))
9322
+ : source;
9323
+ }
9324
+
9325
+ function matchMlinesInAnswer(parsedOffer, parsedAnswer, recvTransceiversByMid) {
9326
+ parsedAnswer.session.groups = parsedOffer.session.groups;
9327
+ parsedAnswer.media = parsedOffer.media.map((offerMline) => {
9328
+ if (!offerMline.mid) {
9329
+ throw new Error(`Offer mline is missing MID`);
9330
+ }
9331
+ const answerMline = parsedAnswer.media.find((m) => m.mid === offerMline.mid);
9332
+ if (answerMline) {
9333
+ if (answerMline instanceof AvMediaDescription) {
9334
+ [...answerMline.codecs.values()].forEach((ci) => {
9335
+ ci.fmtParams.set('x-google-start-bitrate', '60000');
9336
+ });
9337
+ }
9338
+ return answerMline;
9339
+ }
9340
+ if (!(offerMline instanceof AvMediaDescription)) {
9341
+ throw new Error(`Answer is missing a non-media mline: ${offerMline.mid}`);
9342
+ }
9343
+ const startingMline = parsedAnswer.avMedia.find((m) => m.type === offerMline.type);
9344
+ if (!startingMline) {
9345
+ throw new Error(`Answer has no mline of type ${offerMline.type}, can't generate synthetic answer mline for mid ${offerMline.mid}`);
9346
+ }
9347
+ const fakeCorrespondingMline = deepCopy(startingMline);
9348
+ fakeCorrespondingMline.mid = offerMline.mid;
9349
+ fakeCorrespondingMline.simulcast = undefined;
9350
+ if (offerMline.direction === 'sendrecv' || offerMline.direction === 'sendonly') {
9351
+ fakeCorrespondingMline.direction = 'recvonly';
9352
+ }
9353
+ if (offerMline.direction === 'recvonly') {
9354
+ fakeCorrespondingMline.direction = 'sendonly';
9355
+ const recvTransceiver = recvTransceiversByMid.get(offerMline.mid);
9356
+ if (!recvTransceiver) {
9357
+ throw new Error(`Can't find recv transceiver for mid ${offerMline.mid}`);
9358
+ }
9359
+ recvTransceiver.signalRemoteStreams(fakeCorrespondingMline);
9360
+ }
9361
+ return fakeCorrespondingMline;
9362
+ });
9363
+ }
9364
+
9254
9365
  class SendOnlyTransceiver extends Transceiver {
9255
- constructor(rtcpRtpTransceiver, csi) {
9256
- super(rtcpRtpTransceiver);
9366
+ constructor(rtcpRtpTransceiver, mid, csi, signaler) {
9367
+ super(rtcpRtpTransceiver, mid);
9368
+ this.rtxEnabled = false;
9257
9369
  this.requested = false;
9258
9370
  this.csi = csi;
9259
9371
  this.direction = 'sendrecv';
9260
9372
  this.handleTrackChange = this.handleTrackChange.bind(this);
9373
+ this.streamSignaler = signaler;
9261
9374
  }
9262
9375
  handleTrackChange() {
9263
9376
  var _a;
@@ -9336,88 +9449,27 @@ class SendOnlyTransceiver extends Transceiver {
9336
9449
  yield this.sender.setParameters(sendParameters);
9337
9450
  });
9338
9451
  }
9339
- }
9340
-
9341
- class StatsManager {
9342
- constructor(statsGetter, statsPreprocessor = () => __awaiter(this, void 0, void 0, function* () { })) {
9343
- this.statsGetter = statsGetter;
9344
- this.statsPreProcessor = statsPreprocessor;
9452
+ isSimulcastEnabled() {
9453
+ const params = this.sender.getParameters();
9454
+ return params.encodings.length > 1;
9345
9455
  }
9346
- getStats() {
9347
- return __awaiter(this, void 0, void 0, function* () {
9348
- const statsReport = yield this.statsGetter();
9349
- const statsMap = new Map();
9350
- statsReport.forEach((stats, key) => statsMap.set(key, stats));
9351
- yield this.statsPreProcessor(statsMap);
9352
- return statsMap;
9353
- });
9456
+ signalStreams(mLine) {
9457
+ this.streamSignaler.signalStreams(this.isSimulcastEnabled(), this.rtxEnabled, mLine);
9354
9458
  }
9355
- }
9356
-
9357
- const simulcastMaxFrameSizes = {
9358
- 0: '240',
9359
- 1: '2304',
9360
- 2: '8160',
9361
- };
9362
-
9363
- class RidIngressStreamSignaler {
9364
- constructor(mid) {
9365
- this.mid = mid;
9459
+ get senderIds() {
9460
+ return this.streamSignaler.getSenderIds();
9366
9461
  }
9367
- getReceiverId() {
9368
- return {
9369
- mid: this.mid,
9370
- rid: '1',
9371
- };
9462
+ getEncodingIndexForStreamId(id) {
9463
+ return this.streamSignaler.getEncodingIndexForStreamId(id);
9372
9464
  }
9373
- signalLocalStreams(mLine) {
9465
+ resetStreamSignaler() {
9466
+ this.streamSignaler.reset();
9374
9467
  }
9375
- signalRemoteStreams(mLine) {
9376
- }
9377
- }
9378
- class RidEgressStreamSignaler {
9379
- constructor(mid) {
9380
- this.streamIds = [];
9381
- this.mid = mid;
9468
+ setCodecParameters(parameters) {
9469
+ this.streamSignaler.setCodecParameters(parameters);
9382
9470
  }
9383
- signalStreams(simulcastEnabled, _rtxEnabled, mLine) {
9384
- mLine.ssrcGroups = [];
9385
- if (this.streamIds.length === 0) {
9386
- if (simulcastEnabled) {
9387
- this.streamIds = [
9388
- {
9389
- mid: this.mid,
9390
- rid: 'low',
9391
- },
9392
- {
9393
- mid: this.mid,
9394
- rid: 'medium',
9395
- },
9396
- {
9397
- mid: this.mid,
9398
- rid: 'high',
9399
- },
9400
- ];
9401
- }
9402
- else {
9403
- this.streamIds = [
9404
- {
9405
- mid: this.mid,
9406
- },
9407
- ];
9408
- }
9409
- }
9410
- if (simulcastEnabled) {
9411
- mLine.rids = this.streamIds.map((streamId, index) => new RidLine(streamId.rid, 'send', `max-fs=${simulcastMaxFrameSizes[index]}`));
9412
- mLine.simulcast = new SimulcastLine(SimulcastLayerList.fromString('low;medium;high'), new SimulcastLayerList());
9413
- addVlaExtension(mLine);
9414
- }
9415
- }
9416
- getSenderIds() {
9417
- return this.streamIds;
9418
- }
9419
- getEncodingIndexForStreamId(streamId) {
9420
- return this.streamIds.findIndex((currStreamId) => compareStreamIds(currStreamId, streamId));
9471
+ deleteCodecParameters(parameters) {
9472
+ this.streamSignaler.deleteCodecParameters(parameters);
9421
9473
  }
9422
9474
  }
9423
9475
 
@@ -9425,6 +9477,20 @@ function generateSsrc() {
9425
9477
  return Math.floor(Math.random() * 0xffffffff) + 1;
9426
9478
  }
9427
9479
 
9480
+ function setCustomCodecParams(mLine, paramsMap) {
9481
+ paramsMap.forEach((value, param) => {
9482
+ [...mLine.codecs.values()]
9483
+ .filter((ci) => ci.name === 'H264' || ci.name === 'opus')
9484
+ .forEach((ci) => {
9485
+ if (value === null) {
9486
+ ci.fmtParams.delete(param);
9487
+ }
9488
+ else {
9489
+ ci.fmtParams.set(param, `${value}`);
9490
+ }
9491
+ });
9492
+ });
9493
+ }
9428
9494
  class SsrcIngressStreamSignaler {
9429
9495
  constructor() {
9430
9496
  this.ssrc = generateSsrc();
@@ -9447,10 +9513,17 @@ class SsrcIngressStreamSignaler {
9447
9513
  mLine.addLine(new SsrcGroupLine('FID', [this.ssrc, this.rtxSsrc]));
9448
9514
  }
9449
9515
  }
9516
+ reset() {
9517
+ this.ssrc = generateSsrc();
9518
+ }
9450
9519
  }
9451
9520
  class SsrcEgressStreamSignaler {
9452
9521
  constructor() {
9453
9522
  this.streamIds = [];
9523
+ this.customCodecParameters = new Map();
9524
+ }
9525
+ reset() {
9526
+ this.streamIds = [];
9454
9527
  }
9455
9528
  signalStreams(simulcastEnabled, rtxEnabled, mLine) {
9456
9529
  var _a;
@@ -9520,6 +9593,7 @@ class SsrcEgressStreamSignaler {
9520
9593
  mLine.addLine(new SsrcGroupLine('SIM', this.streamIds.map((streamId) => streamId.ssrc)));
9521
9594
  addVlaExtension(mLine);
9522
9595
  }
9596
+ setCustomCodecParams(mLine, this.customCodecParameters);
9523
9597
  }
9524
9598
  getSenderIds() {
9525
9599
  return this.streamIds;
@@ -9527,64 +9601,31 @@ class SsrcEgressStreamSignaler {
9527
9601
  getEncodingIndexForStreamId(streamId) {
9528
9602
  return this.streamIds.findIndex((currStreamId) => compareStreamIds(currStreamId, streamId));
9529
9603
  }
9530
- }
9531
-
9532
- class StreamSignalerManager {
9533
- constructor(streamSignalingMode) {
9534
- this.egressStreamSignalersByMid = new Map();
9535
- this.ingressStreamsSignalersByMid = new Map();
9536
- this.ingressStreamSignalingMode = streamSignalingMode;
9537
- this.egressStreamSignalingMode = streamSignalingMode;
9538
- }
9539
- getOrCreateEgressStreamSignaler(mid) {
9540
- const existing = this.getEgressStreamSignaler(mid);
9541
- if (existing) {
9542
- return existing;
9543
- }
9544
- let newSignaler;
9545
- if (this.egressStreamSignalingMode === 'MID-RID') {
9546
- newSignaler = new RidEgressStreamSignaler(mid);
9547
- }
9548
- else {
9549
- newSignaler = new SsrcEgressStreamSignaler();
9550
- }
9551
- this.egressStreamSignalersByMid.set(mid, newSignaler);
9552
- return newSignaler;
9553
- }
9554
- getEgressStreamSignalerOrThrow(mid) {
9555
- const existing = this.getEgressStreamSignaler(mid);
9556
- if (!existing) {
9557
- throw new Error(`Couldn't find EgressStreamSignaler for mid ${mid}`);
9558
- }
9559
- return existing;
9560
- }
9561
- getEgressStreamSignaler(mid) {
9562
- return this.egressStreamSignalersByMid.get(mid);
9604
+ setCodecParameters(parameters) {
9605
+ Object.entries(parameters).forEach(([param, value]) => {
9606
+ this.customCodecParameters.set(param, value);
9607
+ });
9563
9608
  }
9564
- getOrCreateIngressStreamSignaler(mid) {
9565
- const existing = this.getIngressStreamSignaler(mid);
9566
- if (existing) {
9567
- return existing;
9568
- }
9569
- let newSignaler;
9570
- if (this.ingressStreamSignalingMode === 'MID-RID') {
9571
- newSignaler = new RidIngressStreamSignaler(mid);
9572
- }
9573
- else {
9574
- newSignaler = new SsrcIngressStreamSignaler();
9575
- }
9576
- this.ingressStreamsSignalersByMid.set(mid, newSignaler);
9577
- return newSignaler;
9609
+ deleteCodecParameters(parameters) {
9610
+ parameters.forEach((param) => {
9611
+ this.customCodecParameters.set(param, null);
9612
+ });
9578
9613
  }
9579
- getIngressStreamSignaler(mid) {
9580
- return this.ingressStreamsSignalersByMid.get(mid);
9614
+ }
9615
+
9616
+ class StatsManager {
9617
+ constructor(statsGetter, statsPreprocessor = () => __awaiter(this, void 0, void 0, function* () { })) {
9618
+ this.statsGetter = statsGetter;
9619
+ this.statsPreProcessor = statsPreprocessor;
9581
9620
  }
9582
- getIngressStreamSignalerOrThrow(mid) {
9583
- const existing = this.getIngressStreamSignaler(mid);
9584
- if (!existing) {
9585
- throw new Error(`Couldn't find IngressStreamSignaler for mid ${mid}`);
9586
- }
9587
- return existing;
9621
+ getStats() {
9622
+ return __awaiter(this, void 0, void 0, function* () {
9623
+ const statsReport = yield this.statsGetter();
9624
+ const statsMap = new Map();
9625
+ statsReport.forEach((stats, key) => statsMap.set(key, stats));
9626
+ yield this.statsPreProcessor(statsMap);
9627
+ return statsMap;
9628
+ });
9588
9629
  }
9589
9630
  }
9590
9631
 
@@ -13188,6 +13229,24 @@ function webRtcVideoContentHintToJmpVideoContentHint(hint) {
13188
13229
  }
13189
13230
  return undefined;
13190
13231
  }
13232
+ function createEgressStreamSignaler(signalingMode, mid) {
13233
+ if (signalingMode === 'MID-RID') {
13234
+ return new RidEgressStreamSignaler(mid);
13235
+ }
13236
+ if (signalingMode === 'SSRC') {
13237
+ return new SsrcEgressStreamSignaler();
13238
+ }
13239
+ throw new Error(`unknown signaling mode`);
13240
+ }
13241
+ function createIngressStreamSignaler(signalingMode, mid) {
13242
+ if (signalingMode === 'MID-RID') {
13243
+ return new RidIngressStreamSignaler(mid);
13244
+ }
13245
+ if (signalingMode === 'SSRC') {
13246
+ return new SsrcIngressStreamSignaler();
13247
+ }
13248
+ throw new Error(`unknown signaling mode`);
13249
+ }
13191
13250
  function toMediaFamily(kind) {
13192
13251
  if (kind === exports.MediaStreamTrackKind.Video) {
13193
13252
  return MediaFamily.Video;
@@ -13221,14 +13280,11 @@ class MultistreamConnection extends EventEmitter {
13221
13280
  this.pendingJmpTasks = [];
13222
13281
  this.metricsCallback = () => { };
13223
13282
  this.overuseUpdateCallback = () => { };
13224
- this.customCodecParameters = new Map();
13225
- this.midMap = new Map();
13226
- this.currentMid = 0;
13283
+ this.midPredictor = new MidPredictor();
13227
13284
  this.offerAnswerQueue = new AsyncQueue();
13228
13285
  this.options = Object.assign(Object.assign({}, defaultMultistreamConnectionOptions), userOptions);
13229
13286
  logger.info(`Creating multistream connection with options ${JSON.stringify(this.options)}`);
13230
13287
  this.initializePeerConnection();
13231
- this.streamSignalerManager = new StreamSignalerManager(this.options.streamSignalingMode);
13232
13288
  this.overuseStateManager = new OveruseStateManager((overuseState) => this.overuseUpdateCallback(overuseState));
13233
13289
  this.overuseStateManager.start();
13234
13290
  this.statsManager = new StatsManager(() => this.pc.getStats(), (stats) => this.preProcessStats(stats));
@@ -13245,16 +13301,6 @@ class MultistreamConnection extends EventEmitter {
13245
13301
  this.createSendTransceiver(MediaType.AudioSlides, contentSceneId);
13246
13302
  }
13247
13303
  }
13248
- addMid(mediaType) {
13249
- const mid = this.currentMid++;
13250
- const mids = this.midMap.get(mediaType) || [];
13251
- mids.push(`${mid}`);
13252
- this.midMap.set(mediaType, mids);
13253
- }
13254
- clearMids() {
13255
- this.midMap = new Map();
13256
- this.currentMid = 0;
13257
- }
13258
13304
  initializePeerConnection() {
13259
13305
  var _a;
13260
13306
  (_a = this.pc) === null || _a === void 0 ? void 0 : _a.close();
@@ -13293,9 +13339,18 @@ class MultistreamConnection extends EventEmitter {
13293
13339
  logger.error(`addTransceiver failed due to : ${e}`);
13294
13340
  throw e;
13295
13341
  }
13296
- this.addMid(mediaType);
13342
+ const mid = this.midPredictor.getNextMid(mediaType);
13297
13343
  const csi = generateCsi(getMediaFamily(mediaType), sceneId);
13298
- this.sendTransceivers.set(mediaType, new SendOnlyTransceiver(rtcTransceiver, csi));
13344
+ const signaler = createEgressStreamSignaler(this.options.streamSignalingMode, mid);
13345
+ const transceiver = new SendOnlyTransceiver(rtcTransceiver, mid, csi, signaler);
13346
+ if (getMediaFamily(mediaType) === MediaFamily.Video) {
13347
+ transceiver.rtxEnabled = true;
13348
+ transceiver.setCodecParameters({
13349
+ 'max-mbps': `${defaultMaxVideoEncodeMbps}`,
13350
+ 'max-fs': `${defaultMaxVideoEncodeFrameSize}`,
13351
+ });
13352
+ }
13353
+ this.sendTransceivers.set(mediaType, transceiver);
13299
13354
  this.createJmpSession(mediaType);
13300
13355
  }
13301
13356
  createJmpSession(mediaType) {
@@ -13343,7 +13398,6 @@ class MultistreamConnection extends EventEmitter {
13343
13398
  }
13344
13399
  updateRequestedStreams(mediaType, requests) {
13345
13400
  const sendTransceiver = this.getSendTransceiverOrThrow(mediaType);
13346
- const signaler = this.streamSignalerManager.getEgressStreamSignalerOrThrow(sendTransceiver.mid);
13347
13401
  const mediaFamily = getMediaFamily(mediaType);
13348
13402
  const requestedIdEncodingParamsMap = new Map();
13349
13403
  const rsRequests = requests.filter((r) => isValidReceiverSelectedInfo(r.policySpecificInfo));
@@ -13364,11 +13418,9 @@ class MultistreamConnection extends EventEmitter {
13364
13418
  }
13365
13419
  const id = ids[0];
13366
13420
  const codecInfo = codecInfos[0];
13367
- const streamIdsMatched = signaler
13368
- .getSenderIds()
13369
- .some((validId) => compareStreamIds(id, validId));
13421
+ const streamIdsMatched = sendTransceiver.senderIds.some((validId) => compareStreamIds(id, validId));
13370
13422
  if (streamIdsMatched) {
13371
- const encodingIndex = signaler.getEncodingIndexForStreamId(id);
13423
+ const encodingIndex = sendTransceiver.getEncodingIndexForStreamId(id);
13372
13424
  if (encodingIndex !== -1) {
13373
13425
  const encodingParams = { maxPayloadBitsPerSecond };
13374
13426
  if (mediaFamily === MediaFamily.Video) {
@@ -13450,10 +13502,6 @@ class MultistreamConnection extends EventEmitter {
13450
13502
  return;
13451
13503
  }
13452
13504
  const streamStates = this.getVideoStreamStates(mediaType);
13453
- if (streamStates === null) {
13454
- logger.debug(`Empty streamStates, not sending MediaRequestStatus`);
13455
- return;
13456
- }
13457
13505
  const task = () => {
13458
13506
  var _a;
13459
13507
  (_a = this.jmpSessions.get(mediaType)) === null || _a === void 0 ? void 0 : _a.sendMediaRequestStatus(streamStates);
@@ -13547,13 +13595,10 @@ class MultistreamConnection extends EventEmitter {
13547
13595
  track.off(LocalTrack.Events.Muted, onTrackMute);
13548
13596
  track.off(LocalTrack.Events.PublishedStateUpdate, onTrackPublish);
13549
13597
  track.off(LocalTrack.Events.TrackConstraintsChange, onTrackResolutionChange);
13550
- if (!track.muted) {
13551
- this.sendSourceAdvertisement(mediaType);
13552
- this.sendMediaRequestStatus(mediaType);
13553
- }
13554
13598
  }
13555
- else if (!track.muted) {
13599
+ if (!track.muted) {
13556
13600
  this.sendSourceAdvertisement(mediaType);
13601
+ this.sendMediaRequestStatus(mediaType);
13557
13602
  }
13558
13603
  };
13559
13604
  track.on(LocalTrack.Events.PublishedStateUpdate, onTrackPublish);
@@ -13561,14 +13606,10 @@ class MultistreamConnection extends EventEmitter {
13561
13606
  getVideoStreamStates(mediaType) {
13562
13607
  var _a, _b, _c;
13563
13608
  const sendTransceiver = this.getSendTransceiverOrThrow(mediaType);
13564
- const signaler = this.streamSignalerManager.getEgressStreamSignaler(sendTransceiver.mid);
13565
- if (!signaler) {
13566
- return null;
13567
- }
13568
13609
  const activeSimulcastLayerNumber = ((_a = sendTransceiver.publishedTrack) === null || _a === void 0 ? void 0 : _a.getNumActiveSimulcastLayers()) || 0;
13569
13610
  const published = (_b = sendTransceiver.publishedTrack) === null || _b === void 0 ? void 0 : _b.published;
13570
13611
  const muted = ((_c = sendTransceiver.publishedTrack) === null || _c === void 0 ? void 0 : _c.muted) === true;
13571
- return signaler.getSenderIds().map((id) => {
13612
+ return sendTransceiver.senderIds.map((id) => {
13572
13613
  let state;
13573
13614
  if (!published) {
13574
13615
  state = 'no source';
@@ -13576,7 +13617,7 @@ class MultistreamConnection extends EventEmitter {
13576
13617
  else if (muted) {
13577
13618
  state = 'avatar';
13578
13619
  }
13579
- else if (activeSimulcastLayerNumber < signaler.getEncodingIndexForStreamId(id)) {
13620
+ else if (activeSimulcastLayerNumber < sendTransceiver.getEncodingIndexForStreamId(id)) {
13580
13621
  state = 'no source';
13581
13622
  }
13582
13623
  else {
@@ -13592,21 +13633,16 @@ class MultistreamConnection extends EventEmitter {
13592
13633
  const rtcRtpTransceiver = this.pc.addTransceiver(toMediaStreamTrackKind(mediaType), {
13593
13634
  direction: 'recvonly',
13594
13635
  });
13595
- this.addMid(mediaType);
13596
- const recvOnlyTransceiver = new ReceiveOnlyTransceiver(rtcRtpTransceiver, (mid) => {
13597
- const ingressSignaler = this.streamSignalerManager.getIngressStreamSignaler(mid);
13598
- if (!ingressSignaler) {
13599
- return null;
13600
- }
13601
- return ingressSignaler.getReceiverId();
13602
- });
13603
- if (this.pc.getRemoteDescription()) {
13604
- yield this.doLocalOfferAnswer();
13605
- }
13636
+ const transceiverMid = this.midPredictor.getNextMid(mediaType);
13637
+ const ingressSignaler = createIngressStreamSignaler(this.options.streamSignalingMode, transceiverMid);
13638
+ const recvOnlyTransceiver = new ReceiveOnlyTransceiver(rtcRtpTransceiver, transceiverMid, ingressSignaler);
13606
13639
  this.recvTransceivers.set(mediaType, [
13607
13640
  ...(this.recvTransceivers.get(mediaType) || []),
13608
13641
  recvOnlyTransceiver,
13609
13642
  ]);
13643
+ if (this.pc.getRemoteDescription()) {
13644
+ yield this.doLocalOfferAnswer();
13645
+ }
13610
13646
  createReceiveSlotResolve(recvOnlyTransceiver.receiveSlot);
13611
13647
  }));
13612
13648
  });
@@ -13646,7 +13682,7 @@ class MultistreamConnection extends EventEmitter {
13646
13682
  createOffer() {
13647
13683
  return __awaiter(this, void 0, void 0, function* () {
13648
13684
  if (!this.pc.getLocalDescription()) {
13649
- this.currentMid++;
13685
+ this.midPredictor.allocateMidForDatachannel();
13650
13686
  }
13651
13687
  return new Promise((createOfferResolve) => {
13652
13688
  this.offerAnswerQueue.push(() => __awaiter(this, void 0, void 0, function* () {
@@ -13672,7 +13708,6 @@ class MultistreamConnection extends EventEmitter {
13672
13708
  }
13673
13709
  setAnswer(answer) {
13674
13710
  return __awaiter(this, void 0, void 0, function* () {
13675
- const isInitialAnswer = !this.pc.getRemoteDescription();
13676
13711
  const sdp = this.preProcessRemoteAnswer(answer);
13677
13712
  if (!this.setAnswerResolve) {
13678
13713
  throw new Error(`Call to setAnswer without having previously called createOffer`);
@@ -13685,9 +13720,6 @@ class MultistreamConnection extends EventEmitter {
13685
13720
  else {
13686
13721
  logger.debug(`setAnswerResolve function was cleared between setAnswer and result of setRemoteDescription`);
13687
13722
  }
13688
- if (isInitialAnswer && this.customCodecParameters.size > 0) {
13689
- yield this.queueLocalOfferAnswer();
13690
- }
13691
13723
  }));
13692
13724
  });
13693
13725
  }
@@ -13725,43 +13757,17 @@ class MultistreamConnection extends EventEmitter {
13725
13757
  parsed.avMedia
13726
13758
  .filter((av) => av.direction === 'recvonly')
13727
13759
  .forEach((av) => {
13728
- const ingressSignaler = this.streamSignalerManager.getOrCreateIngressStreamSignaler(av.mid);
13729
- ingressSignaler.signalLocalStreams(av);
13760
+ const transceiver = this.getRecvTransceiverByMidOrThrow(av.mid);
13761
+ transceiver.signalLocalStreams(av);
13730
13762
  });
13731
13763
  parsed.avMedia
13732
- .filter((av) => av.direction === 'sendrecv')
13764
+ .filter((av) => av.direction === 'sendrecv' || av.direction === 'inactive')
13733
13765
  .forEach((av) => {
13734
- const egressSignaler = this.streamSignalerManager.getOrCreateEgressStreamSignaler(av.mid);
13735
- const simulcastEnabled = hasSimulcast(av);
13736
- const rtxEnabled = av.type === 'video';
13737
- egressSignaler.signalStreams(simulcastEnabled, rtxEnabled, av);
13738
- if (av.type === 'video') {
13739
- [...av.codecs.values()]
13740
- .filter((ci) => ci.name === 'H264')
13741
- .forEach((ci) => {
13742
- ci.fmtParams.set('max-mbps', `${defaultMaxVideoEncodeMbps}`);
13743
- ci.fmtParams.set('max-fs', `${defaultMaxVideoEncodeFrameSize}`);
13744
- });
13745
- }
13746
- const mediaType = [...this.sendTransceivers.keys()].find((key) => { var _a; return ((_a = this.sendTransceivers.get(key)) === null || _a === void 0 ? void 0 : _a.mid) === av.mid; });
13747
- if (mediaType && this.customCodecParameters.has(mediaType)) {
13748
- [...av.codecs.values()]
13749
- .filter((ci) => ci.name === (av.type === 'audio' ? 'opus' : 'H264'))
13750
- .forEach((ci) => {
13751
- var _a;
13752
- (_a = this.customCodecParameters.get(mediaType)) === null || _a === void 0 ? void 0 : _a.forEach((value, param) => {
13753
- if (value === null) {
13754
- ci.fmtParams.delete(param);
13755
- }
13756
- else {
13757
- ci.fmtParams.set(param, `${value}`);
13758
- }
13759
- });
13760
- });
13761
- }
13766
+ const transceiver = this.getSendTransceiverByMidOrThrow(av.mid);
13767
+ transceiver.signalStreams(av);
13762
13768
  });
13763
13769
  if (getBrowserDetails().name !== 'Firefox') {
13764
- setupBundle(parsed, this.options.bundlePolicy, this.midMap);
13770
+ setupBundle(parsed, this.options.bundlePolicy, this.midPredictor.getMidMap());
13765
13771
  }
13766
13772
  return parsed.toString();
13767
13773
  }
@@ -13790,7 +13796,7 @@ class MultistreamConnection extends EventEmitter {
13790
13796
  }
13791
13797
  });
13792
13798
  if (getBrowserDetails().name === 'Firefox') {
13793
- setupBundle(parsed, this.options.bundlePolicy, this.midMap);
13799
+ setupBundle(parsed, this.options.bundlePolicy, this.midPredictor.getMidMap());
13794
13800
  if (this.options.bundlePolicy === 'max-bundle') {
13795
13801
  parsed.media.forEach((mline, index) => {
13796
13802
  if (index > 0) {
@@ -13805,9 +13811,10 @@ class MultistreamConnection extends EventEmitter {
13805
13811
  var _a;
13806
13812
  const parsedAnswer = parse(answer);
13807
13813
  const parsedOffer = parse((_a = this.pc.getLocalDescription()) === null || _a === void 0 ? void 0 : _a.sdp);
13808
- matchMlinesInAnswer(parsedOffer, parsedAnswer, this.streamSignalerManager);
13814
+ const recvTransceiversByMid = new Map([...this.recvTransceivers.values()].flat().map((t) => [t.mid, t]));
13815
+ matchMlinesInAnswer(parsedOffer, parsedAnswer, recvTransceiversByMid);
13809
13816
  if (getBrowserDetails().name === 'Firefox') {
13810
- setupBundle(parsedAnswer, this.options.bundlePolicy, this.midMap);
13817
+ setupBundle(parsedAnswer, this.options.bundlePolicy, this.midPredictor.getMidMap());
13811
13818
  if (this.options.bundlePolicy === 'max-bundle') {
13812
13819
  const { ufrag, pwd } = parsedAnswer.media[0].iceInfo;
13813
13820
  parsedAnswer.media.forEach((mline, index) => {
@@ -13827,6 +13834,20 @@ class MultistreamConnection extends EventEmitter {
13827
13834
  }
13828
13835
  return sendTransceiver;
13829
13836
  }
13837
+ getSendTransceiverByMidOrThrow(mid) {
13838
+ const transceiver = [...this.sendTransceivers.values()].find((t) => t.mid === mid);
13839
+ if (!transceiver) {
13840
+ throw new Error(`Unable to find send transceiver with mid ${mid}`);
13841
+ }
13842
+ return transceiver;
13843
+ }
13844
+ getRecvTransceiverByMidOrThrow(mid) {
13845
+ const transceiver = [...this.recvTransceivers.values()].flat().find((t) => t.mid === mid);
13846
+ if (!transceiver) {
13847
+ throw new Error(`Unable to find recv transceiver with mid ${mid}`);
13848
+ }
13849
+ return transceiver;
13850
+ }
13830
13851
  getPublishedTracks() {
13831
13852
  return [...this.sendTransceivers.values()]
13832
13853
  .map((transceiver) => transceiver.publishedTrack)
@@ -13834,11 +13855,8 @@ class MultistreamConnection extends EventEmitter {
13834
13855
  }
13835
13856
  setCodecParameters(mediaType, parameters) {
13836
13857
  return __awaiter(this, void 0, void 0, function* () {
13837
- const currentParams = this.customCodecParameters.get(mediaType) || new Map();
13838
- Object.entries(parameters).forEach(([param, value]) => {
13839
- currentParams.set(param, value);
13840
- });
13841
- this.customCodecParameters.set(mediaType, currentParams);
13858
+ const transceiver = this.sendTransceivers.get(mediaType);
13859
+ transceiver === null || transceiver === void 0 ? void 0 : transceiver.setCodecParameters(parameters);
13842
13860
  if (this.pc.getRemoteDescription()) {
13843
13861
  yield this.queueLocalOfferAnswer();
13844
13862
  }
@@ -13846,11 +13864,8 @@ class MultistreamConnection extends EventEmitter {
13846
13864
  }
13847
13865
  deleteCodecParameters(mediaType, parameters) {
13848
13866
  return __awaiter(this, void 0, void 0, function* () {
13849
- const currentParams = this.customCodecParameters.get(mediaType) || new Map();
13850
- parameters.forEach((param) => {
13851
- currentParams.set(param, null);
13852
- });
13853
- this.customCodecParameters.set(mediaType, currentParams);
13867
+ const transceiver = this.sendTransceivers.get(mediaType);
13868
+ transceiver === null || transceiver === void 0 ? void 0 : transceiver.deleteCodecParameters(parameters);
13854
13869
  if (this.pc.getRemoteDescription()) {
13855
13870
  yield this.queueLocalOfferAnswer();
13856
13871
  }
@@ -13894,32 +13909,34 @@ class MultistreamConnection extends EventEmitter {
13894
13909
  this.options = Object.assign(Object.assign({}, this.options), userOptions);
13895
13910
  }
13896
13911
  logger.info(`Renewing multistream connection with options ${JSON.stringify(this.options)}`);
13897
- this.clearMids();
13912
+ this.midPredictor.reset();
13898
13913
  this.initializePeerConnection();
13899
- this.streamSignalerManager = new StreamSignalerManager(this.options.streamSignalingMode);
13900
13914
  const mainSceneId = generateSceneId();
13901
13915
  const slidesSceneId = generateSceneId();
13902
13916
  this.sendTransceivers.forEach((transceiver, mediaType) => {
13903
13917
  var _a;
13904
13918
  const mediaContent = getMediaContent(mediaType);
13905
13919
  const sceneId = mediaContent === MediaContent.Main ? mainSceneId : slidesSceneId;
13906
- this.addMid(mediaType);
13920
+ const mid = this.midPredictor.getNextMid(mediaType);
13907
13921
  transceiver.replaceTransceiver(this.pc.addTransceiver(toMediaStreamTrackKind(mediaType), {
13908
13922
  direction: 'sendrecv',
13909
13923
  sendEncodings: getMediaFamily(mediaType) === MediaFamily.Video
13910
13924
  ? this.getVideoEncodingOptions(mediaContent)
13911
13925
  : undefined,
13912
13926
  }));
13927
+ transceiver.mid = mid;
13913
13928
  transceiver.csi = generateCsi(getMediaFamily(mediaType), sceneId);
13929
+ transceiver.resetStreamSignaler();
13914
13930
  (_a = this.jmpSessions.get(mediaType)) === null || _a === void 0 ? void 0 : _a.close();
13915
13931
  this.createJmpSession(mediaType);
13916
13932
  });
13917
13933
  this.recvTransceivers.forEach((transceivers, mediaType) => {
13918
13934
  transceivers.forEach((t) => {
13919
- this.addMid(mediaType);
13935
+ const mid = this.midPredictor.getNextMid(mediaType);
13920
13936
  t.replaceTransceiver(this.pc.addTransceiver(toMediaStreamTrackKind(mediaType), {
13921
13937
  direction: 'recvonly',
13922
13938
  }));
13939
+ t.mid = mid;
13923
13940
  });
13924
13941
  });
13925
13942
  }
@@ -13968,10 +13985,7 @@ class MultistreamConnection extends EventEmitter {
13968
13985
  statsToModify.mid = (_a = transceiver.receiveSlot.id) === null || _a === void 0 ? void 0 : _a.mid;
13969
13986
  statsToModify.csi = transceiver.receiveSlot.currentRxCsi;
13970
13987
  statsToModify.mediaType = mediaType;
13971
- const signaler = this.streamSignalerManager.getIngressStreamSignaler(statsToModify.mid);
13972
- if (signaler) {
13973
- Object.assign(statsToModify, signaler.getReceiverId());
13974
- }
13988
+ Object.assign(statsToModify, transceiver.receiverId);
13975
13989
  stats.set(receiverStats.id, statsToModify);
13976
13990
  }
13977
13991
  });