@webex/internal-media-core 1.35.5 → 1.35.7

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
@@ -4679,6 +4679,139 @@ var media = /*#__PURE__*/Object.freeze({
4679
4679
  checkDevicePermissions: checkDevicePermissions,
4680
4680
  ensureDevicePermissions: ensureDevicePermissions
4681
4681
  });
4682
+ var ErrorTypes;
4683
+ (function (ErrorTypes) {
4684
+ ErrorTypes["DEVICE_PERMISSION_DENIED"] = "DEVICE_PERMISSION_DENIED";
4685
+ ErrorTypes["CREATE_CAMERA_TRACK_FAILED"] = "CREATE_CAMERA_TRACK_FAILED";
4686
+ ErrorTypes["CREATE_MICROPHONE_TRACK_FAILED"] = "CREATE_MICROPHONE_TRACK_FAILED";
4687
+ })(ErrorTypes || (ErrorTypes = {}));
4688
+ /**
4689
+ * Represents a WCME error, which contains error type and error message.
4690
+ */
4691
+ class WcmeError {
4692
+ /**
4693
+ * Creates new error.
4694
+ *
4695
+ * @param type - Error type.
4696
+ * @param message - Error message.
4697
+ */
4698
+ constructor(type) {
4699
+ var message = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
4700
+ this.type = type;
4701
+ this.message = message;
4702
+ }
4703
+ }
4704
+ /**
4705
+ * Creates a camera video track. Please note that the constraint params in second getUserMedia call would NOT take effect when:
4706
+ *
4707
+ * 1. Previous captured video track from the same device is not stopped .
4708
+ * 2. Previous createCameraTrack() call for the same device is in progress.
4709
+ *
4710
+ * @param constructor - Constructor for the local camera track.
4711
+ * @param constraints - Video device constraints.
4712
+ * @returns A LocalTrack object or an error.
4713
+ */
4714
+ function createCameraTrack(constructor, constraints) {
4715
+ return __awaiter$1(this, void 0, void 0, function* () {
4716
+ var stream;
4717
+ try {
4718
+ stream = yield getUserMedia({
4719
+ video: Object.assign({}, constraints)
4720
+ });
4721
+ } catch (error) {
4722
+ throw new WcmeError(ErrorTypes.CREATE_CAMERA_TRACK_FAILED, "Failed to create camera track ".concat(error));
4723
+ }
4724
+ return new constructor(stream);
4725
+ });
4726
+ }
4727
+ /**
4728
+ * Creates a microphone audio track.
4729
+ *
4730
+ * @param constructor - Constructor for the local microphone track.
4731
+ * @param constraints - Audio device constraints.
4732
+ * @returns A LocalTrack object or an error.
4733
+ */
4734
+ function createMicrophoneTrack(constructor, constraints) {
4735
+ return __awaiter$1(this, void 0, void 0, function* () {
4736
+ var stream;
4737
+ try {
4738
+ stream = yield getUserMedia({
4739
+ audio: Object.assign({}, constraints)
4740
+ });
4741
+ } catch (error) {
4742
+ throw new WcmeError(ErrorTypes.CREATE_MICROPHONE_TRACK_FAILED, "Failed to create microphone track ".concat(error));
4743
+ }
4744
+ return new constructor(stream);
4745
+ });
4746
+ }
4747
+ /**
4748
+ * Creates a display video track.
4749
+ *
4750
+ * @param constructor - Constructor for the local display track.
4751
+ * @param videoContentHint - An optional parameters to give a hint for the content of the track.
4752
+ * @returns A Promise that resolves to a LocalDisplayTrack.
4753
+ */
4754
+ function createDisplayTrack(constructor, videoContentHint) {
4755
+ return __awaiter$1(this, void 0, void 0, function* () {
4756
+ var stream = yield getDisplayMedia({
4757
+ video: true
4758
+ });
4759
+ return new constructor(stream, videoContentHint);
4760
+ });
4761
+ }
4762
+ /**
4763
+ * Enumerates the media input and output devices available.
4764
+ *
4765
+ * @param deviceKind - Optional filter to return a specific device kind.
4766
+ * @returns List of media devices in an array of MediaDeviceInfo objects.
4767
+ */
4768
+ function getDevices(deviceKind) {
4769
+ return __awaiter$1(this, void 0, void 0, function* () {
4770
+ var devices;
4771
+ try {
4772
+ devices = yield ensureDevicePermissions([DeviceKind.AudioInput, DeviceKind.VideoInput], enumerateDevices);
4773
+ } catch (error) {
4774
+ throw new WcmeError(ErrorTypes.DEVICE_PERMISSION_DENIED, 'Failed to ensure device permissions');
4775
+ }
4776
+ return devices.filter(v => deviceKind ? v.kind === deviceKind : true);
4777
+ });
4778
+ }
4779
+ /**
4780
+ * Helper function to get a list of microphone devices.
4781
+ *
4782
+ * @returns List of microphone devices in an array of MediaDeviceInfo objects.
4783
+ */
4784
+ function getAudioInputDevices() {
4785
+ return __awaiter$1(this, void 0, void 0, function* () {
4786
+ return getDevices(DeviceKind.AudioInput);
4787
+ });
4788
+ }
4789
+ /**
4790
+ * Helper function to get a list of speaker devices.
4791
+ *
4792
+ * @returns List of speaker devices in an array of MediaDeviceInfo objects.
4793
+ */
4794
+ function getAudioOutputDevices() {
4795
+ return __awaiter$1(this, void 0, void 0, function* () {
4796
+ return getDevices(DeviceKind.AudioOutput);
4797
+ });
4798
+ }
4799
+ /**
4800
+ * Helper function to get a list of camera devices.
4801
+ *
4802
+ * @returns List of camera devices in an array of MediaDeviceInfo objects.
4803
+ */
4804
+ function getVideoInputDevices() {
4805
+ return __awaiter$1(this, void 0, void 0, function* () {
4806
+ return getDevices(DeviceKind.VideoInput);
4807
+ });
4808
+ }
4809
+ /**
4810
+ * Export the setOnDeviceChangeHandler method directly from the core lib.
4811
+ */
4812
+ var {
4813
+ setOnDeviceChangeHandler
4814
+ } = media;
4682
4815
  var events$1 = {
4683
4816
  exports: {}
4684
4817
  };
@@ -5351,141 +5484,32 @@ class LocalCameraTrack extends LocalTrack {}
5351
5484
  /**
5352
5485
  * Represents a local track for a display source.
5353
5486
  */
5354
- class LocalDisplayTrack extends LocalTrack {}
5355
-
5356
- /**
5357
- * Represents a local track for a microphone source.
5358
- */
5359
- class LocalMicrophoneTrack extends LocalTrack {}
5360
- var ErrorTypes;
5361
- (function (ErrorTypes) {
5362
- ErrorTypes["DEVICE_PERMISSION_DENIED"] = "DEVICE_PERMISSION_DENIED";
5363
- ErrorTypes["CREATE_CAMERA_TRACK_FAILED"] = "CREATE_CAMERA_TRACK_FAILED";
5364
- ErrorTypes["CREATE_MICROPHONE_TRACK_FAILED"] = "CREATE_MICROPHONE_TRACK_FAILED";
5365
- })(ErrorTypes || (ErrorTypes = {}));
5366
- /**
5367
- * Represents a WCME error, which contains error type and error message.
5368
- */
5369
- class WcmeError {
5487
+ class LocalDisplayTrack extends LocalTrack {
5370
5488
  /**
5371
- * Creates new error.
5489
+ * Create a LocalDisplayTrack from the given values.
5372
5490
  *
5373
- * @param type - Error type.
5374
- * @param message - Error message.
5491
+ * @param stream - The MediaStream for this track.
5492
+ * @param videoContentHint - An optional content hint, describing the content of the track.
5375
5493
  */
5376
- constructor(type) {
5377
- var message = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
5378
- this.type = type;
5379
- this.message = message;
5494
+ constructor(stream, videoContentHint) {
5495
+ super(stream);
5496
+ this._videoContentHint = videoContentHint;
5497
+ this.underlyingTrack.contentHint = videoContentHint || '';
5498
+ }
5499
+ /**
5500
+ * Get the VideoContentHint for this track.
5501
+ *
5502
+ * @returns The VideoContentHint for this track.
5503
+ */
5504
+ get videoContentHint() {
5505
+ return this._videoContentHint;
5380
5506
  }
5381
5507
  }
5508
+
5382
5509
  /**
5383
- * Creates a camera video track. Please note that the constraint params in second getUserMedia call would NOT take effect when:
5384
- *
5385
- * 1. Previous captured video track from the same device is not stopped .
5386
- * 2. Previous createCameraTrack() call for the same device is in progress.
5387
- *
5388
- * @param constraints - Video device constraints.
5389
- * @returns A LocalTrack object or an error.
5390
- */
5391
- function createCameraTrack(constraints) {
5392
- return __awaiter$1(this, void 0, void 0, function* () {
5393
- var stream;
5394
- try {
5395
- stream = yield getUserMedia({
5396
- video: Object.assign({}, constraints)
5397
- });
5398
- } catch (error) {
5399
- throw new WcmeError(ErrorTypes.CREATE_CAMERA_TRACK_FAILED, "Failed to create camera track ".concat(error));
5400
- }
5401
- return new LocalCameraTrack(stream);
5402
- });
5403
- }
5404
- /**
5405
- * Creates a microphone audio track.
5406
- *
5407
- * @param constraints - Audio device constraints.
5408
- * @returns A LocalTrack object or an error.
5409
- */
5410
- function createMicrophoneTrack(constraints) {
5411
- return __awaiter$1(this, void 0, void 0, function* () {
5412
- var stream;
5413
- try {
5414
- stream = yield getUserMedia({
5415
- audio: Object.assign({}, constraints)
5416
- });
5417
- } catch (error) {
5418
- throw new WcmeError(ErrorTypes.CREATE_MICROPHONE_TRACK_FAILED, "Failed to create microphone track ".concat(error));
5419
- }
5420
- return new LocalMicrophoneTrack(stream);
5421
- });
5422
- }
5423
- /**
5424
- * Creates a display video track.
5425
- *
5426
- * @returns A Promise that resolves to a LocalDisplayTrack.
5427
- */
5428
- function createDisplayTrack() {
5429
- return __awaiter$1(this, void 0, void 0, function* () {
5430
- var stream = yield getDisplayMedia({
5431
- video: true
5432
- });
5433
- return new LocalDisplayTrack(stream);
5434
- });
5435
- }
5436
- /**
5437
- * Enumerates the media input and output devices available.
5438
- *
5439
- * @param deviceKind - Optional filter to return a specific device kind.
5440
- * @returns List of media devices in an array of MediaDeviceInfo objects.
5441
- */
5442
- function getDevices(deviceKind) {
5443
- return __awaiter$1(this, void 0, void 0, function* () {
5444
- var devices;
5445
- try {
5446
- devices = yield ensureDevicePermissions([DeviceKind.AudioInput, DeviceKind.VideoInput], enumerateDevices);
5447
- } catch (error) {
5448
- throw new WcmeError(ErrorTypes.DEVICE_PERMISSION_DENIED, 'Failed to ensure device permissions');
5449
- }
5450
- return devices.filter(v => deviceKind ? v.kind === deviceKind : true);
5451
- });
5452
- }
5453
- /**
5454
- * Helper function to get a list of microphone devices.
5455
- *
5456
- * @returns List of microphone devices in an array of MediaDeviceInfo objects.
5457
- */
5458
- function getAudioInputDevices() {
5459
- return __awaiter$1(this, void 0, void 0, function* () {
5460
- return getDevices(DeviceKind.AudioInput);
5461
- });
5462
- }
5463
- /**
5464
- * Helper function to get a list of speaker devices.
5465
- *
5466
- * @returns List of speaker devices in an array of MediaDeviceInfo objects.
5467
- */
5468
- function getAudioOutputDevices() {
5469
- return __awaiter$1(this, void 0, void 0, function* () {
5470
- return getDevices(DeviceKind.AudioOutput);
5471
- });
5472
- }
5473
- /**
5474
- * Helper function to get a list of camera devices.
5475
- *
5476
- * @returns List of camera devices in an array of MediaDeviceInfo objects.
5477
- */
5478
- function getVideoInputDevices() {
5479
- return __awaiter$1(this, void 0, void 0, function* () {
5480
- return getDevices(DeviceKind.VideoInput);
5481
- });
5482
- }
5483
- /**
5484
- * Export the setOnDeviceChangeHandler method directly from the core lib.
5510
+ * Represents a local track for a microphone source.
5485
5511
  */
5486
- var {
5487
- setOnDeviceChangeHandler
5488
- } = media;
5512
+ class LocalMicrophoneTrack extends LocalTrack {}
5489
5513
 
5490
5514
  // Overall connection state (based on the ICE and DTLS connection states)
5491
5515
  exports.ConnectionState = void 0;
@@ -9480,11 +9504,12 @@ function compareStreamIds(id1, id2) {
9480
9504
  return keys1.every(key => id1[key] === id2[key]);
9481
9505
  }
9482
9506
  class SourceIndicationMsg {
9483
- constructor(seqNum, numTotalSources, numLiveSources, sources) {
9507
+ constructor(seqNum, numTotalSources, numLiveSources, sources, videoContentHint) {
9484
9508
  this.seqNum = seqNum;
9485
9509
  this.numTotalSources = numTotalSources;
9486
9510
  this.numLiveSources = numLiveSources;
9487
9511
  this.sources = sources;
9512
+ this.videoContentHint = videoContentHint;
9488
9513
  }
9489
9514
  sourcesToString() {
9490
9515
  return this.sources.map(source => "Source(id=".concat(source.id, " state=").concat(source.state, " ").concat(source.csi ? "csi=".concat(source.csi) : '', ")")).join(', ');
@@ -9571,13 +9596,13 @@ class JmpSession extends EventEmitter$4 {
9571
9596
  this.logger.warn("Retransmits for message expired: ".concat(expiredJmpMsg));
9572
9597
  });
9573
9598
  }
9574
- updateSourceIndication(numTotalSources, numLiveSources, sources) {
9599
+ updateSourceIndication(numTotalSources, numLiveSources, sources, videoContentHint) {
9575
9600
  var _a;
9576
9601
  var filteredSources = sources.filter(source => {
9577
9602
  var _a;
9578
9603
  return (_a = this.lastReceivedScr) === null || _a === void 0 ? void 0 : _a.requests.some(req => req.ids.find(streamId => compareStreamIds(streamId, source.id)));
9579
9604
  });
9580
- var sourceIndicationMsg = new SourceIndicationMsg(this.currSourceIndicationSeqNum++, numTotalSources, numLiveSources, filteredSources);
9605
+ var sourceIndicationMsg = new SourceIndicationMsg(this.currSourceIndicationSeqNum++, numTotalSources, numLiveSources, filteredSources, videoContentHint);
9581
9606
  var jmpMsg = new JmpMsg(this.mediaFamily, this.mediaContent, {
9582
9607
  msgType: JmpMsgType$1.SourceIndication,
9583
9608
  payload: sourceIndicationMsg
@@ -12722,7 +12747,9 @@ class SsrcIngressStreamSignaler {
12722
12747
  mLine.addLine(new SsrcLine(this.ssrc, 'cname', "".concat(this.ssrc, "-cname")));
12723
12748
  mLine.addLine(new SsrcLine(this.ssrc, 'msid', '-', '1'));
12724
12749
  if (hasCodec('rtx', mLine)) {
12725
- this.rtxSsrc = generateSsrc();
12750
+ if (!this.rtxSsrc) {
12751
+ this.rtxSsrc = generateSsrc();
12752
+ }
12726
12753
  mLine.addLine(new SsrcLine(this.rtxSsrc, 'cname', "".concat(this.ssrc, "-cname")));
12727
12754
  mLine.addLine(new SsrcLine(this.rtxSsrc, 'msid', '-', '1'));
12728
12755
  mLine.addLine(new SsrcGroupLine('FID', [this.ssrc, this.rtxSsrc]));
@@ -12734,23 +12761,57 @@ class SsrcEgressStreamSignaler {
12734
12761
  this.streamIds = [];
12735
12762
  }
12736
12763
  signalStreams(simulcastEnabled, rtxEnabled, mLine) {
12764
+ var _a;
12737
12765
  mLine.rids = [];
12738
12766
  mLine.simulcast = undefined;
12739
- mLine.ssrcs = [];
12740
- mLine.ssrcGroups = [];
12741
12767
  mLine.extMaps = mLine.extMaps.filter(extMapLine => !/^urn:ietf:params:rtp-hdrext:sdes:(?:mid|rtp-stream-id|repaired-rtp-stream-id)$/.test(extMapLine.uri));
12742
- if (this.streamIds.length === 0) {
12743
- var numStreams = simulcastEnabled ? 3 : 1;
12744
- [...Array(numStreams).keys()].forEach(() => {
12745
- var newStreamId = {
12746
- ssrc: generateSsrc()
12747
- };
12748
- if (rtxEnabled) {
12749
- newStreamId.rtxSsrc = generateSsrc();
12768
+ var numStreams = simulcastEnabled ? 3 : 1;
12769
+ if (!this.streamIds.length) {
12770
+ if (mLine.ssrcs.length) {
12771
+ var ssrcs = [...new Set(mLine.ssrcs.map(ssrcLine => ssrcLine.ssrcId))];
12772
+ mLine.ssrcGroups.forEach(sg => {
12773
+ if (!sg.ssrcs.every(ssrc => ssrcs.includes(ssrc))) {
12774
+ throw new Error('SSRC present in SSRC groups is missing from SSRC lines');
12775
+ }
12776
+ });
12777
+ var rtxSsrcGroups = mLine.ssrcGroups.filter(sg => sg.semantics === 'FID');
12778
+ if (rtxSsrcGroups.length && rtxSsrcGroups.length !== numStreams) {
12779
+ throw new Error("Expect ".concat(numStreams, " RTX SSRC groups, got ").concat(rtxSsrcGroups.length));
12750
12780
  }
12751
- this.streamIds.push(newStreamId);
12752
- });
12781
+ rtxSsrcGroups.forEach(sg => {
12782
+ this.streamIds.push({
12783
+ ssrc: sg.ssrcs[0],
12784
+ rtxSsrc: sg.ssrcs[1]
12785
+ });
12786
+ });
12787
+ var simulcastSsrcs = (_a = mLine.ssrcGroups.find(sg => sg.semantics === 'SIM')) === null || _a === void 0 ? void 0 : _a.ssrcs;
12788
+ if (simulcastSsrcs) {
12789
+ if (simulcastSsrcs.length !== numStreams || !this.streamIds.every(streamId => simulcastSsrcs.includes(streamId.ssrc))) {
12790
+ throw new Error('SSRCs in simulcast SSRC group do not match primary SSRCs in RTX SSRC groups');
12791
+ }
12792
+ this.streamIds.sort((a, b) => simulcastSsrcs.indexOf(a.ssrc) - simulcastSsrcs.indexOf(b.ssrc));
12793
+ } else if (rtxSsrcGroups.length > 1) {
12794
+ throw new Error('Multiple RTX SSRC groups but no simulcast SSRC group found');
12795
+ }
12796
+ if (!this.streamIds.length) {
12797
+ this.streamIds.push({
12798
+ ssrc: ssrcs[0]
12799
+ });
12800
+ }
12801
+ } else {
12802
+ [...Array(numStreams).keys()].forEach(() => {
12803
+ var newStreamId = {
12804
+ ssrc: generateSsrc()
12805
+ };
12806
+ if (rtxEnabled) {
12807
+ newStreamId.rtxSsrc = generateSsrc();
12808
+ }
12809
+ this.streamIds.push(newStreamId);
12810
+ });
12811
+ }
12753
12812
  }
12813
+ mLine.ssrcs = [];
12814
+ mLine.ssrcGroups = [];
12754
12815
  this.streamIds.forEach(streamId => {
12755
12816
  var rtpSsrc = streamId.ssrc;
12756
12817
  mLine.addLine(new SsrcLine(rtpSsrc, 'cname', "".concat(rtpSsrc, "-cname")));
@@ -14505,6 +14566,15 @@ function setLogHandler(logHandler) {
14505
14566
  function toMediaStreamTrackKind(mediaType) {
14506
14567
  return [MediaType.VideoMain, MediaType.VideoSlides].includes(mediaType) ? exports.MediaStreamTrackKind.Video : exports.MediaStreamTrackKind.Audio;
14507
14568
  }
14569
+ function webRtcVideoContentHintToJmpVideoContentHint(hint) {
14570
+ if (hint === 'motion') {
14571
+ return 'motion';
14572
+ }
14573
+ if (hint === 'detail') {
14574
+ return 'sharpness';
14575
+ }
14576
+ return undefined;
14577
+ }
14508
14578
  function toMediaFamily(kind) {
14509
14579
  if (kind === exports.MediaStreamTrackKind.Video) {
14510
14580
  return MediaFamily.Video;
@@ -14700,7 +14770,7 @@ class MultistreamConnection extends EventEmitter {
14700
14770
  state: 'invalid source',
14701
14771
  csi: sendTransceiver.csi
14702
14772
  });
14703
- } else if (signaler.getEncodingIndexForStreamId(id) > activeSimulcastLayerNumber) {
14773
+ } else if (signaler.getEncodingIndexForStreamId(id) >= activeSimulcastLayerNumber) {
14704
14774
  sourceWarnings.push({
14705
14775
  id,
14706
14776
  state: 'no source',
@@ -14770,24 +14840,8 @@ class MultistreamConnection extends EventEmitter {
14770
14840
  var dataChannel = this.pc.createDataChannel('datachannel', {});
14771
14841
  dataChannel.onopen = e => {
14772
14842
  logger$4.info('DataChannel opened: ', e);
14773
- this.sendTransceivers.forEach((transceiver, mediaType) => {
14774
- var track = transceiver.publishedTrack;
14775
- if (track) {
14776
- if (getMediaFamily$1(mediaType) === MediaFamily.Audio) {
14777
- this.sendSourceIndication(mediaType, +!track.muted);
14778
- } else {
14779
- var signaler = this.streamSignalerManager.getEgressStreamSignalerOrThrow(transceiver.mid);
14780
- var state = track.muted ? 'avatar' : 'live';
14781
- var sources = signaler.getSenderIds().map(id => ({
14782
- id,
14783
- state,
14784
- csi: transceiver.csi
14785
- }));
14786
- this.sendSourceIndication(mediaType, +!track.muted, sources);
14787
- }
14788
- } else {
14789
- this.sendSourceIndication(mediaType, 0);
14790
- }
14843
+ [...this.sendTransceivers.keys()].forEach(mediaType => {
14844
+ this.maybeSendSourceIndication(mediaType);
14791
14845
  });
14792
14846
  logger$4.info("Flushing pending JMP task queue");
14793
14847
  this.pendingJmpTasks.forEach(t => t());
@@ -14835,12 +14889,31 @@ class MultistreamConnection extends EventEmitter {
14835
14889
  });
14836
14890
  this.pc.close();
14837
14891
  }
14892
+ maybeSendSourceIndication(mediaType) {
14893
+ var _a;
14894
+ var transceiver = this.getSendTransceiverOrThrow(mediaType);
14895
+ var numLiveSources = ((_a = transceiver.publishedTrack) === null || _a === void 0 ? void 0 : _a.muted) === false ? 1 : 0;
14896
+ if (getMediaFamily$1(mediaType) === MediaFamily.Video) {
14897
+ var sources = this.getVideoSources(mediaType);
14898
+ if (sources === null) {
14899
+ return;
14900
+ }
14901
+ var webRtcVideoContentHint;
14902
+ if (transceiver.publishedTrack instanceof LocalDisplayTrack) {
14903
+ webRtcVideoContentHint = transceiver.publishedTrack.videoContentHint;
14904
+ }
14905
+ this.sendSourceIndication(mediaType, numLiveSources, sources, webRtcVideoContentHintToJmpVideoContentHint(webRtcVideoContentHint));
14906
+ } else {
14907
+ this.sendSourceIndication(mediaType, numLiveSources);
14908
+ }
14909
+ }
14838
14910
  sendSourceIndication(mediaType, numLiveSources) {
14839
14911
  var sources = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
14912
+ var videoContentHint = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : undefined;
14840
14913
  var _a;
14841
14914
  var task = () => {
14842
14915
  var _a;
14843
- (_a = this.jmpSessions.get(mediaType)) === null || _a === void 0 ? void 0 : _a.updateSourceIndication(1, numLiveSources, sources);
14916
+ (_a = this.jmpSessions.get(mediaType)) === null || _a === void 0 ? void 0 : _a.updateSourceIndication(1, numLiveSources, sources, videoContentHint);
14844
14917
  };
14845
14918
  if (((_a = this.dataChannel) === null || _a === void 0 ? void 0 : _a.readyState) === 'open') {
14846
14919
  task();
@@ -14882,23 +14955,9 @@ class MultistreamConnection extends EventEmitter {
14882
14955
  });
14883
14956
  }
14884
14957
  addTrackListeners(mediaType, track) {
14885
- var onTrackResolutionChange = () => {
14886
- var sources = this.getVideoSources(mediaType);
14887
- if (sources != null) {
14888
- this.sendSourceIndication(mediaType, 1, sources);
14889
- }
14890
- };
14958
+ var onTrackResolutionChange = () => this.maybeSendSourceIndication(mediaType);
14891
14959
  track.on(LocalTrack.Events.TrackConstraintsChange, onTrackResolutionChange);
14892
- var onTrackMute = event => {
14893
- if (getMediaFamily$1(mediaType) === MediaFamily.Audio) {
14894
- this.sendSourceIndication(mediaType, +!event.trackState.muted);
14895
- } else {
14896
- var sources = this.getVideoSources(mediaType);
14897
- if (sources != null) {
14898
- this.sendSourceIndication(mediaType, +!event.trackState.muted, sources);
14899
- }
14900
- }
14901
- };
14960
+ var onTrackMute = () => this.maybeSendSourceIndication(mediaType);
14902
14961
  track.on(LocalTrack.Events.Muted, onTrackMute);
14903
14962
  var onTrackPublish = event => {
14904
14963
  if (!event.isPublished) {
@@ -14906,13 +14965,8 @@ class MultistreamConnection extends EventEmitter {
14906
14965
  track.off(LocalTrack.Events.PublishedStateUpdate, onTrackPublish);
14907
14966
  track.off(LocalTrack.Events.TrackConstraintsChange, onTrackResolutionChange);
14908
14967
  }
14909
- if (getMediaFamily$1(mediaType) === MediaFamily.Audio) {
14910
- this.sendSourceIndication(mediaType, +event.isPublished);
14911
- } else {
14912
- var sources = this.getVideoSources(mediaType);
14913
- if (sources != null) {
14914
- this.sendSourceIndication(mediaType, +event.isPublished, sources);
14915
- }
14968
+ if (!track.muted) {
14969
+ this.maybeSendSourceIndication(mediaType);
14916
14970
  }
14917
14971
  };
14918
14972
  track.on(LocalTrack.Events.PublishedStateUpdate, onTrackPublish);
@@ -15183,7 +15237,7 @@ class MultistreamConnection extends EventEmitter {
15183
15237
  }
15184
15238
  renewPeerConnection(userOptions) {
15185
15239
  if (userOptions) {
15186
- this.options = Object.assign(Object.assign({}, defaultMultistreamConnectionOptions), userOptions);
15240
+ this.options = Object.assign(Object.assign({}, this.options), userOptions);
15187
15241
  }
15188
15242
  logger$4.info("Renewing multistream connection with options ".concat(JSON.stringify(this.options)));
15189
15243
  this.clearMids();
package/dist/esm/index.js CHANGED
@@ -4668,6 +4668,139 @@ var media = /*#__PURE__*/Object.freeze({
4668
4668
  checkDevicePermissions: checkDevicePermissions,
4669
4669
  ensureDevicePermissions: ensureDevicePermissions
4670
4670
  });
4671
+ var ErrorTypes;
4672
+ (function (ErrorTypes) {
4673
+ ErrorTypes["DEVICE_PERMISSION_DENIED"] = "DEVICE_PERMISSION_DENIED";
4674
+ ErrorTypes["CREATE_CAMERA_TRACK_FAILED"] = "CREATE_CAMERA_TRACK_FAILED";
4675
+ ErrorTypes["CREATE_MICROPHONE_TRACK_FAILED"] = "CREATE_MICROPHONE_TRACK_FAILED";
4676
+ })(ErrorTypes || (ErrorTypes = {}));
4677
+ /**
4678
+ * Represents a WCME error, which contains error type and error message.
4679
+ */
4680
+ class WcmeError {
4681
+ /**
4682
+ * Creates new error.
4683
+ *
4684
+ * @param type - Error type.
4685
+ * @param message - Error message.
4686
+ */
4687
+ constructor(type) {
4688
+ var message = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
4689
+ this.type = type;
4690
+ this.message = message;
4691
+ }
4692
+ }
4693
+ /**
4694
+ * Creates a camera video track. Please note that the constraint params in second getUserMedia call would NOT take effect when:
4695
+ *
4696
+ * 1. Previous captured video track from the same device is not stopped .
4697
+ * 2. Previous createCameraTrack() call for the same device is in progress.
4698
+ *
4699
+ * @param constructor - Constructor for the local camera track.
4700
+ * @param constraints - Video device constraints.
4701
+ * @returns A LocalTrack object or an error.
4702
+ */
4703
+ function createCameraTrack(constructor, constraints) {
4704
+ return __awaiter$1(this, void 0, void 0, function* () {
4705
+ var stream;
4706
+ try {
4707
+ stream = yield getUserMedia({
4708
+ video: Object.assign({}, constraints)
4709
+ });
4710
+ } catch (error) {
4711
+ throw new WcmeError(ErrorTypes.CREATE_CAMERA_TRACK_FAILED, "Failed to create camera track ".concat(error));
4712
+ }
4713
+ return new constructor(stream);
4714
+ });
4715
+ }
4716
+ /**
4717
+ * Creates a microphone audio track.
4718
+ *
4719
+ * @param constructor - Constructor for the local microphone track.
4720
+ * @param constraints - Audio device constraints.
4721
+ * @returns A LocalTrack object or an error.
4722
+ */
4723
+ function createMicrophoneTrack(constructor, constraints) {
4724
+ return __awaiter$1(this, void 0, void 0, function* () {
4725
+ var stream;
4726
+ try {
4727
+ stream = yield getUserMedia({
4728
+ audio: Object.assign({}, constraints)
4729
+ });
4730
+ } catch (error) {
4731
+ throw new WcmeError(ErrorTypes.CREATE_MICROPHONE_TRACK_FAILED, "Failed to create microphone track ".concat(error));
4732
+ }
4733
+ return new constructor(stream);
4734
+ });
4735
+ }
4736
+ /**
4737
+ * Creates a display video track.
4738
+ *
4739
+ * @param constructor - Constructor for the local display track.
4740
+ * @param videoContentHint - An optional parameters to give a hint for the content of the track.
4741
+ * @returns A Promise that resolves to a LocalDisplayTrack.
4742
+ */
4743
+ function createDisplayTrack(constructor, videoContentHint) {
4744
+ return __awaiter$1(this, void 0, void 0, function* () {
4745
+ var stream = yield getDisplayMedia({
4746
+ video: true
4747
+ });
4748
+ return new constructor(stream, videoContentHint);
4749
+ });
4750
+ }
4751
+ /**
4752
+ * Enumerates the media input and output devices available.
4753
+ *
4754
+ * @param deviceKind - Optional filter to return a specific device kind.
4755
+ * @returns List of media devices in an array of MediaDeviceInfo objects.
4756
+ */
4757
+ function getDevices(deviceKind) {
4758
+ return __awaiter$1(this, void 0, void 0, function* () {
4759
+ var devices;
4760
+ try {
4761
+ devices = yield ensureDevicePermissions([DeviceKind.AudioInput, DeviceKind.VideoInput], enumerateDevices);
4762
+ } catch (error) {
4763
+ throw new WcmeError(ErrorTypes.DEVICE_PERMISSION_DENIED, 'Failed to ensure device permissions');
4764
+ }
4765
+ return devices.filter(v => deviceKind ? v.kind === deviceKind : true);
4766
+ });
4767
+ }
4768
+ /**
4769
+ * Helper function to get a list of microphone devices.
4770
+ *
4771
+ * @returns List of microphone devices in an array of MediaDeviceInfo objects.
4772
+ */
4773
+ function getAudioInputDevices() {
4774
+ return __awaiter$1(this, void 0, void 0, function* () {
4775
+ return getDevices(DeviceKind.AudioInput);
4776
+ });
4777
+ }
4778
+ /**
4779
+ * Helper function to get a list of speaker devices.
4780
+ *
4781
+ * @returns List of speaker devices in an array of MediaDeviceInfo objects.
4782
+ */
4783
+ function getAudioOutputDevices() {
4784
+ return __awaiter$1(this, void 0, void 0, function* () {
4785
+ return getDevices(DeviceKind.AudioOutput);
4786
+ });
4787
+ }
4788
+ /**
4789
+ * Helper function to get a list of camera devices.
4790
+ *
4791
+ * @returns List of camera devices in an array of MediaDeviceInfo objects.
4792
+ */
4793
+ function getVideoInputDevices() {
4794
+ return __awaiter$1(this, void 0, void 0, function* () {
4795
+ return getDevices(DeviceKind.VideoInput);
4796
+ });
4797
+ }
4798
+ /**
4799
+ * Export the setOnDeviceChangeHandler method directly from the core lib.
4800
+ */
4801
+ var {
4802
+ setOnDeviceChangeHandler
4803
+ } = media;
4671
4804
  var events$1 = {
4672
4805
  exports: {}
4673
4806
  };
@@ -5340,141 +5473,32 @@ class LocalCameraTrack extends LocalTrack {}
5340
5473
  /**
5341
5474
  * Represents a local track for a display source.
5342
5475
  */
5343
- class LocalDisplayTrack extends LocalTrack {}
5344
-
5345
- /**
5346
- * Represents a local track for a microphone source.
5347
- */
5348
- class LocalMicrophoneTrack extends LocalTrack {}
5349
- var ErrorTypes;
5350
- (function (ErrorTypes) {
5351
- ErrorTypes["DEVICE_PERMISSION_DENIED"] = "DEVICE_PERMISSION_DENIED";
5352
- ErrorTypes["CREATE_CAMERA_TRACK_FAILED"] = "CREATE_CAMERA_TRACK_FAILED";
5353
- ErrorTypes["CREATE_MICROPHONE_TRACK_FAILED"] = "CREATE_MICROPHONE_TRACK_FAILED";
5354
- })(ErrorTypes || (ErrorTypes = {}));
5355
- /**
5356
- * Represents a WCME error, which contains error type and error message.
5357
- */
5358
- class WcmeError {
5476
+ class LocalDisplayTrack extends LocalTrack {
5359
5477
  /**
5360
- * Creates new error.
5478
+ * Create a LocalDisplayTrack from the given values.
5361
5479
  *
5362
- * @param type - Error type.
5363
- * @param message - Error message.
5480
+ * @param stream - The MediaStream for this track.
5481
+ * @param videoContentHint - An optional content hint, describing the content of the track.
5364
5482
  */
5365
- constructor(type) {
5366
- var message = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
5367
- this.type = type;
5368
- this.message = message;
5483
+ constructor(stream, videoContentHint) {
5484
+ super(stream);
5485
+ this._videoContentHint = videoContentHint;
5486
+ this.underlyingTrack.contentHint = videoContentHint || '';
5487
+ }
5488
+ /**
5489
+ * Get the VideoContentHint for this track.
5490
+ *
5491
+ * @returns The VideoContentHint for this track.
5492
+ */
5493
+ get videoContentHint() {
5494
+ return this._videoContentHint;
5369
5495
  }
5370
5496
  }
5497
+
5371
5498
  /**
5372
- * Creates a camera video track. Please note that the constraint params in second getUserMedia call would NOT take effect when:
5373
- *
5374
- * 1. Previous captured video track from the same device is not stopped .
5375
- * 2. Previous createCameraTrack() call for the same device is in progress.
5376
- *
5377
- * @param constraints - Video device constraints.
5378
- * @returns A LocalTrack object or an error.
5379
- */
5380
- function createCameraTrack(constraints) {
5381
- return __awaiter$1(this, void 0, void 0, function* () {
5382
- var stream;
5383
- try {
5384
- stream = yield getUserMedia({
5385
- video: Object.assign({}, constraints)
5386
- });
5387
- } catch (error) {
5388
- throw new WcmeError(ErrorTypes.CREATE_CAMERA_TRACK_FAILED, "Failed to create camera track ".concat(error));
5389
- }
5390
- return new LocalCameraTrack(stream);
5391
- });
5392
- }
5393
- /**
5394
- * Creates a microphone audio track.
5395
- *
5396
- * @param constraints - Audio device constraints.
5397
- * @returns A LocalTrack object or an error.
5398
- */
5399
- function createMicrophoneTrack(constraints) {
5400
- return __awaiter$1(this, void 0, void 0, function* () {
5401
- var stream;
5402
- try {
5403
- stream = yield getUserMedia({
5404
- audio: Object.assign({}, constraints)
5405
- });
5406
- } catch (error) {
5407
- throw new WcmeError(ErrorTypes.CREATE_MICROPHONE_TRACK_FAILED, "Failed to create microphone track ".concat(error));
5408
- }
5409
- return new LocalMicrophoneTrack(stream);
5410
- });
5411
- }
5412
- /**
5413
- * Creates a display video track.
5414
- *
5415
- * @returns A Promise that resolves to a LocalDisplayTrack.
5416
- */
5417
- function createDisplayTrack() {
5418
- return __awaiter$1(this, void 0, void 0, function* () {
5419
- var stream = yield getDisplayMedia({
5420
- video: true
5421
- });
5422
- return new LocalDisplayTrack(stream);
5423
- });
5424
- }
5425
- /**
5426
- * Enumerates the media input and output devices available.
5427
- *
5428
- * @param deviceKind - Optional filter to return a specific device kind.
5429
- * @returns List of media devices in an array of MediaDeviceInfo objects.
5430
- */
5431
- function getDevices(deviceKind) {
5432
- return __awaiter$1(this, void 0, void 0, function* () {
5433
- var devices;
5434
- try {
5435
- devices = yield ensureDevicePermissions([DeviceKind.AudioInput, DeviceKind.VideoInput], enumerateDevices);
5436
- } catch (error) {
5437
- throw new WcmeError(ErrorTypes.DEVICE_PERMISSION_DENIED, 'Failed to ensure device permissions');
5438
- }
5439
- return devices.filter(v => deviceKind ? v.kind === deviceKind : true);
5440
- });
5441
- }
5442
- /**
5443
- * Helper function to get a list of microphone devices.
5444
- *
5445
- * @returns List of microphone devices in an array of MediaDeviceInfo objects.
5446
- */
5447
- function getAudioInputDevices() {
5448
- return __awaiter$1(this, void 0, void 0, function* () {
5449
- return getDevices(DeviceKind.AudioInput);
5450
- });
5451
- }
5452
- /**
5453
- * Helper function to get a list of speaker devices.
5454
- *
5455
- * @returns List of speaker devices in an array of MediaDeviceInfo objects.
5456
- */
5457
- function getAudioOutputDevices() {
5458
- return __awaiter$1(this, void 0, void 0, function* () {
5459
- return getDevices(DeviceKind.AudioOutput);
5460
- });
5461
- }
5462
- /**
5463
- * Helper function to get a list of camera devices.
5464
- *
5465
- * @returns List of camera devices in an array of MediaDeviceInfo objects.
5466
- */
5467
- function getVideoInputDevices() {
5468
- return __awaiter$1(this, void 0, void 0, function* () {
5469
- return getDevices(DeviceKind.VideoInput);
5470
- });
5471
- }
5472
- /**
5473
- * Export the setOnDeviceChangeHandler method directly from the core lib.
5499
+ * Represents a local track for a microphone source.
5474
5500
  */
5475
- var {
5476
- setOnDeviceChangeHandler
5477
- } = media;
5501
+ class LocalMicrophoneTrack extends LocalTrack {}
5478
5502
 
5479
5503
  // Overall connection state (based on the ICE and DTLS connection states)
5480
5504
  var ConnectionState;
@@ -9469,11 +9493,12 @@ function compareStreamIds(id1, id2) {
9469
9493
  return keys1.every(key => id1[key] === id2[key]);
9470
9494
  }
9471
9495
  class SourceIndicationMsg {
9472
- constructor(seqNum, numTotalSources, numLiveSources, sources) {
9496
+ constructor(seqNum, numTotalSources, numLiveSources, sources, videoContentHint) {
9473
9497
  this.seqNum = seqNum;
9474
9498
  this.numTotalSources = numTotalSources;
9475
9499
  this.numLiveSources = numLiveSources;
9476
9500
  this.sources = sources;
9501
+ this.videoContentHint = videoContentHint;
9477
9502
  }
9478
9503
  sourcesToString() {
9479
9504
  return this.sources.map(source => "Source(id=".concat(source.id, " state=").concat(source.state, " ").concat(source.csi ? "csi=".concat(source.csi) : '', ")")).join(', ');
@@ -9560,13 +9585,13 @@ class JmpSession extends EventEmitter$4 {
9560
9585
  this.logger.warn("Retransmits for message expired: ".concat(expiredJmpMsg));
9561
9586
  });
9562
9587
  }
9563
- updateSourceIndication(numTotalSources, numLiveSources, sources) {
9588
+ updateSourceIndication(numTotalSources, numLiveSources, sources, videoContentHint) {
9564
9589
  var _a;
9565
9590
  var filteredSources = sources.filter(source => {
9566
9591
  var _a;
9567
9592
  return (_a = this.lastReceivedScr) === null || _a === void 0 ? void 0 : _a.requests.some(req => req.ids.find(streamId => compareStreamIds(streamId, source.id)));
9568
9593
  });
9569
- var sourceIndicationMsg = new SourceIndicationMsg(this.currSourceIndicationSeqNum++, numTotalSources, numLiveSources, filteredSources);
9594
+ var sourceIndicationMsg = new SourceIndicationMsg(this.currSourceIndicationSeqNum++, numTotalSources, numLiveSources, filteredSources, videoContentHint);
9570
9595
  var jmpMsg = new JmpMsg(this.mediaFamily, this.mediaContent, {
9571
9596
  msgType: JmpMsgType$1.SourceIndication,
9572
9597
  payload: sourceIndicationMsg
@@ -12711,7 +12736,9 @@ class SsrcIngressStreamSignaler {
12711
12736
  mLine.addLine(new SsrcLine(this.ssrc, 'cname', "".concat(this.ssrc, "-cname")));
12712
12737
  mLine.addLine(new SsrcLine(this.ssrc, 'msid', '-', '1'));
12713
12738
  if (hasCodec('rtx', mLine)) {
12714
- this.rtxSsrc = generateSsrc();
12739
+ if (!this.rtxSsrc) {
12740
+ this.rtxSsrc = generateSsrc();
12741
+ }
12715
12742
  mLine.addLine(new SsrcLine(this.rtxSsrc, 'cname', "".concat(this.ssrc, "-cname")));
12716
12743
  mLine.addLine(new SsrcLine(this.rtxSsrc, 'msid', '-', '1'));
12717
12744
  mLine.addLine(new SsrcGroupLine('FID', [this.ssrc, this.rtxSsrc]));
@@ -12723,23 +12750,57 @@ class SsrcEgressStreamSignaler {
12723
12750
  this.streamIds = [];
12724
12751
  }
12725
12752
  signalStreams(simulcastEnabled, rtxEnabled, mLine) {
12753
+ var _a;
12726
12754
  mLine.rids = [];
12727
12755
  mLine.simulcast = undefined;
12728
- mLine.ssrcs = [];
12729
- mLine.ssrcGroups = [];
12730
12756
  mLine.extMaps = mLine.extMaps.filter(extMapLine => !/^urn:ietf:params:rtp-hdrext:sdes:(?:mid|rtp-stream-id|repaired-rtp-stream-id)$/.test(extMapLine.uri));
12731
- if (this.streamIds.length === 0) {
12732
- var numStreams = simulcastEnabled ? 3 : 1;
12733
- [...Array(numStreams).keys()].forEach(() => {
12734
- var newStreamId = {
12735
- ssrc: generateSsrc()
12736
- };
12737
- if (rtxEnabled) {
12738
- newStreamId.rtxSsrc = generateSsrc();
12757
+ var numStreams = simulcastEnabled ? 3 : 1;
12758
+ if (!this.streamIds.length) {
12759
+ if (mLine.ssrcs.length) {
12760
+ var ssrcs = [...new Set(mLine.ssrcs.map(ssrcLine => ssrcLine.ssrcId))];
12761
+ mLine.ssrcGroups.forEach(sg => {
12762
+ if (!sg.ssrcs.every(ssrc => ssrcs.includes(ssrc))) {
12763
+ throw new Error('SSRC present in SSRC groups is missing from SSRC lines');
12764
+ }
12765
+ });
12766
+ var rtxSsrcGroups = mLine.ssrcGroups.filter(sg => sg.semantics === 'FID');
12767
+ if (rtxSsrcGroups.length && rtxSsrcGroups.length !== numStreams) {
12768
+ throw new Error("Expect ".concat(numStreams, " RTX SSRC groups, got ").concat(rtxSsrcGroups.length));
12739
12769
  }
12740
- this.streamIds.push(newStreamId);
12741
- });
12770
+ rtxSsrcGroups.forEach(sg => {
12771
+ this.streamIds.push({
12772
+ ssrc: sg.ssrcs[0],
12773
+ rtxSsrc: sg.ssrcs[1]
12774
+ });
12775
+ });
12776
+ var simulcastSsrcs = (_a = mLine.ssrcGroups.find(sg => sg.semantics === 'SIM')) === null || _a === void 0 ? void 0 : _a.ssrcs;
12777
+ if (simulcastSsrcs) {
12778
+ if (simulcastSsrcs.length !== numStreams || !this.streamIds.every(streamId => simulcastSsrcs.includes(streamId.ssrc))) {
12779
+ throw new Error('SSRCs in simulcast SSRC group do not match primary SSRCs in RTX SSRC groups');
12780
+ }
12781
+ this.streamIds.sort((a, b) => simulcastSsrcs.indexOf(a.ssrc) - simulcastSsrcs.indexOf(b.ssrc));
12782
+ } else if (rtxSsrcGroups.length > 1) {
12783
+ throw new Error('Multiple RTX SSRC groups but no simulcast SSRC group found');
12784
+ }
12785
+ if (!this.streamIds.length) {
12786
+ this.streamIds.push({
12787
+ ssrc: ssrcs[0]
12788
+ });
12789
+ }
12790
+ } else {
12791
+ [...Array(numStreams).keys()].forEach(() => {
12792
+ var newStreamId = {
12793
+ ssrc: generateSsrc()
12794
+ };
12795
+ if (rtxEnabled) {
12796
+ newStreamId.rtxSsrc = generateSsrc();
12797
+ }
12798
+ this.streamIds.push(newStreamId);
12799
+ });
12800
+ }
12742
12801
  }
12802
+ mLine.ssrcs = [];
12803
+ mLine.ssrcGroups = [];
12743
12804
  this.streamIds.forEach(streamId => {
12744
12805
  var rtpSsrc = streamId.ssrc;
12745
12806
  mLine.addLine(new SsrcLine(rtpSsrc, 'cname', "".concat(rtpSsrc, "-cname")));
@@ -14494,6 +14555,15 @@ function setLogHandler(logHandler) {
14494
14555
  function toMediaStreamTrackKind(mediaType) {
14495
14556
  return [MediaType$1.VideoMain, MediaType$1.VideoSlides].includes(mediaType) ? MediaStreamTrackKind.Video : MediaStreamTrackKind.Audio;
14496
14557
  }
14558
+ function webRtcVideoContentHintToJmpVideoContentHint(hint) {
14559
+ if (hint === 'motion') {
14560
+ return 'motion';
14561
+ }
14562
+ if (hint === 'detail') {
14563
+ return 'sharpness';
14564
+ }
14565
+ return undefined;
14566
+ }
14497
14567
  function toMediaFamily(kind) {
14498
14568
  if (kind === MediaStreamTrackKind.Video) {
14499
14569
  return MediaFamily$1.Video;
@@ -14689,7 +14759,7 @@ class MultistreamConnection extends EventEmitter {
14689
14759
  state: 'invalid source',
14690
14760
  csi: sendTransceiver.csi
14691
14761
  });
14692
- } else if (signaler.getEncodingIndexForStreamId(id) > activeSimulcastLayerNumber) {
14762
+ } else if (signaler.getEncodingIndexForStreamId(id) >= activeSimulcastLayerNumber) {
14693
14763
  sourceWarnings.push({
14694
14764
  id,
14695
14765
  state: 'no source',
@@ -14759,24 +14829,8 @@ class MultistreamConnection extends EventEmitter {
14759
14829
  var dataChannel = this.pc.createDataChannel('datachannel', {});
14760
14830
  dataChannel.onopen = e => {
14761
14831
  logger$4.info('DataChannel opened: ', e);
14762
- this.sendTransceivers.forEach((transceiver, mediaType) => {
14763
- var track = transceiver.publishedTrack;
14764
- if (track) {
14765
- if (getMediaFamily$1(mediaType) === MediaFamily$1.Audio) {
14766
- this.sendSourceIndication(mediaType, +!track.muted);
14767
- } else {
14768
- var signaler = this.streamSignalerManager.getEgressStreamSignalerOrThrow(transceiver.mid);
14769
- var state = track.muted ? 'avatar' : 'live';
14770
- var sources = signaler.getSenderIds().map(id => ({
14771
- id,
14772
- state,
14773
- csi: transceiver.csi
14774
- }));
14775
- this.sendSourceIndication(mediaType, +!track.muted, sources);
14776
- }
14777
- } else {
14778
- this.sendSourceIndication(mediaType, 0);
14779
- }
14832
+ [...this.sendTransceivers.keys()].forEach(mediaType => {
14833
+ this.maybeSendSourceIndication(mediaType);
14780
14834
  });
14781
14835
  logger$4.info("Flushing pending JMP task queue");
14782
14836
  this.pendingJmpTasks.forEach(t => t());
@@ -14824,12 +14878,31 @@ class MultistreamConnection extends EventEmitter {
14824
14878
  });
14825
14879
  this.pc.close();
14826
14880
  }
14881
+ maybeSendSourceIndication(mediaType) {
14882
+ var _a;
14883
+ var transceiver = this.getSendTransceiverOrThrow(mediaType);
14884
+ var numLiveSources = ((_a = transceiver.publishedTrack) === null || _a === void 0 ? void 0 : _a.muted) === false ? 1 : 0;
14885
+ if (getMediaFamily$1(mediaType) === MediaFamily$1.Video) {
14886
+ var sources = this.getVideoSources(mediaType);
14887
+ if (sources === null) {
14888
+ return;
14889
+ }
14890
+ var webRtcVideoContentHint;
14891
+ if (transceiver.publishedTrack instanceof LocalDisplayTrack) {
14892
+ webRtcVideoContentHint = transceiver.publishedTrack.videoContentHint;
14893
+ }
14894
+ this.sendSourceIndication(mediaType, numLiveSources, sources, webRtcVideoContentHintToJmpVideoContentHint(webRtcVideoContentHint));
14895
+ } else {
14896
+ this.sendSourceIndication(mediaType, numLiveSources);
14897
+ }
14898
+ }
14827
14899
  sendSourceIndication(mediaType, numLiveSources) {
14828
14900
  var sources = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
14901
+ var videoContentHint = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : undefined;
14829
14902
  var _a;
14830
14903
  var task = () => {
14831
14904
  var _a;
14832
- (_a = this.jmpSessions.get(mediaType)) === null || _a === void 0 ? void 0 : _a.updateSourceIndication(1, numLiveSources, sources);
14905
+ (_a = this.jmpSessions.get(mediaType)) === null || _a === void 0 ? void 0 : _a.updateSourceIndication(1, numLiveSources, sources, videoContentHint);
14833
14906
  };
14834
14907
  if (((_a = this.dataChannel) === null || _a === void 0 ? void 0 : _a.readyState) === 'open') {
14835
14908
  task();
@@ -14871,23 +14944,9 @@ class MultistreamConnection extends EventEmitter {
14871
14944
  });
14872
14945
  }
14873
14946
  addTrackListeners(mediaType, track) {
14874
- var onTrackResolutionChange = () => {
14875
- var sources = this.getVideoSources(mediaType);
14876
- if (sources != null) {
14877
- this.sendSourceIndication(mediaType, 1, sources);
14878
- }
14879
- };
14947
+ var onTrackResolutionChange = () => this.maybeSendSourceIndication(mediaType);
14880
14948
  track.on(LocalTrack.Events.TrackConstraintsChange, onTrackResolutionChange);
14881
- var onTrackMute = event => {
14882
- if (getMediaFamily$1(mediaType) === MediaFamily$1.Audio) {
14883
- this.sendSourceIndication(mediaType, +!event.trackState.muted);
14884
- } else {
14885
- var sources = this.getVideoSources(mediaType);
14886
- if (sources != null) {
14887
- this.sendSourceIndication(mediaType, +!event.trackState.muted, sources);
14888
- }
14889
- }
14890
- };
14949
+ var onTrackMute = () => this.maybeSendSourceIndication(mediaType);
14891
14950
  track.on(LocalTrack.Events.Muted, onTrackMute);
14892
14951
  var onTrackPublish = event => {
14893
14952
  if (!event.isPublished) {
@@ -14895,13 +14954,8 @@ class MultistreamConnection extends EventEmitter {
14895
14954
  track.off(LocalTrack.Events.PublishedStateUpdate, onTrackPublish);
14896
14955
  track.off(LocalTrack.Events.TrackConstraintsChange, onTrackResolutionChange);
14897
14956
  }
14898
- if (getMediaFamily$1(mediaType) === MediaFamily$1.Audio) {
14899
- this.sendSourceIndication(mediaType, +event.isPublished);
14900
- } else {
14901
- var sources = this.getVideoSources(mediaType);
14902
- if (sources != null) {
14903
- this.sendSourceIndication(mediaType, +event.isPublished, sources);
14904
- }
14957
+ if (!track.muted) {
14958
+ this.maybeSendSourceIndication(mediaType);
14905
14959
  }
14906
14960
  };
14907
14961
  track.on(LocalTrack.Events.PublishedStateUpdate, onTrackPublish);
@@ -15172,7 +15226,7 @@ class MultistreamConnection extends EventEmitter {
15172
15226
  }
15173
15227
  renewPeerConnection(userOptions) {
15174
15228
  if (userOptions) {
15175
- this.options = Object.assign(Object.assign({}, defaultMultistreamConnectionOptions), userOptions);
15229
+ this.options = Object.assign(Object.assign({}, this.options), userOptions);
15176
15230
  }
15177
15231
  logger$4.info("Renewing multistream connection with options ".concat(JSON.stringify(this.options)));
15178
15232
  this.clearMids();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webex/internal-media-core",
3
- "version": "1.35.5",
3
+ "version": "1.35.7",
4
4
  "files": [
5
5
  "dist/cjs",
6
6
  "dist/esm",
@@ -45,9 +45,9 @@
45
45
  },
46
46
  "dependencies": {
47
47
  "@babel/runtime": "^7.18.9",
48
- "@webex/json-multistream": "1.20.2",
48
+ "@webex/json-multistream": "1.22.0",
49
49
  "@webex/ts-sdp": "1.3.2",
50
- "@webex/web-client-media-engine": "1.40.2",
50
+ "@webex/web-client-media-engine": "1.40.6",
51
51
  "detectrtc": "^1.4.1",
52
52
  "events": "^3.3.0",
53
53
  "typed-emitter": "^2.1.0",