@webex/internal-media-core 1.35.6 → 1.36.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.
package/dist/cjs/index.js CHANGED
@@ -4218,7 +4218,7 @@ function _mergeNamespaces$1(n, m) {
4218
4218
  return Object.freeze(n);
4219
4219
  }
4220
4220
 
4221
- /*! *****************************************************************************
4221
+ /******************************************************************************
4222
4222
  Copyright (c) Microsoft Corporation.
4223
4223
 
4224
4224
  Permission to use, copy, modify, and/or distribute this software for any
@@ -4532,8 +4532,13 @@ var logger$1$1 = {
4532
4532
  var Logger$2 = logger$1$1.exports;
4533
4533
  var DEFAULT_LOGGER_NAME$1 = 'webrtc-core';
4534
4534
  var logger$3 = Logger$2.get(DEFAULT_LOGGER_NAME$1);
4535
- // Set log level to debug by default.
4536
- logger$3.setLevel(Logger$2.DEBUG);
4535
+ Logger$2.useDefaults({
4536
+ defaultLevel: Logger$2.DEBUG,
4537
+ /* eslint-disable-next-line jsdoc/require-jsdoc */
4538
+ formatter: (messages, context) => {
4539
+ messages.unshift("[".concat(context.name, "]"));
4540
+ }
4541
+ });
4537
4542
  var DeviceKind;
4538
4543
  (function (DeviceKind) {
4539
4544
  DeviceKind["AudioInput"] = "audioinput";
@@ -4748,14 +4753,15 @@ function createMicrophoneTrack(constructor, constraints) {
4748
4753
  * Creates a display video track.
4749
4754
  *
4750
4755
  * @param constructor - Constructor for the local display track.
4756
+ * @param videoContentHint - An optional parameters to give a hint for the content of the track.
4751
4757
  * @returns A Promise that resolves to a LocalDisplayTrack.
4752
4758
  */
4753
- function createDisplayTrack(constructor) {
4759
+ function createDisplayTrack(constructor, videoContentHint) {
4754
4760
  return __awaiter$1(this, void 0, void 0, function* () {
4755
4761
  var stream = yield getDisplayMedia({
4756
4762
  video: true
4757
4763
  });
4758
- return new constructor(stream);
4764
+ return new constructor(stream, videoContentHint);
4759
4765
  });
4760
4766
  }
4761
4767
  /**
@@ -5410,16 +5416,26 @@ class LocalTrack extends EventEmitter$2 {
5410
5416
  }
5411
5417
  return effect;
5412
5418
  }
5419
+ /**
5420
+ * Get a copy of the effects Map.
5421
+ *
5422
+ * @returns A copy of the effects map.
5423
+ */
5424
+ getEffects() {
5425
+ return new Map(this.effects);
5426
+ }
5413
5427
  /**
5414
5428
  * Cleanup the local microphone track.
5415
5429
  */
5416
5430
  disposeEffects() {
5417
- if (this.effects.size > 0) {
5418
- this.effects.forEach(effect => effect.dispose());
5419
- this.effects.clear();
5420
- this.underlyingStream = this.originalStream;
5421
- this.emit(exports.LocalTrackEvents.UnderlyingTrackChange);
5422
- }
5431
+ return __awaiter$1(this, void 0, void 0, function* () {
5432
+ if (this.effects.size > 0) {
5433
+ yield Promise.all(Array.from(this.effects.values(), effect => effect.dispose()));
5434
+ this.effects.clear();
5435
+ this.underlyingStream = this.originalStream;
5436
+ this.emit(exports.LocalTrackEvents.UnderlyingTrackChange);
5437
+ }
5438
+ });
5423
5439
  }
5424
5440
  /**
5425
5441
  * Apply constraints to the track.
@@ -5483,7 +5499,27 @@ class LocalCameraTrack extends LocalTrack {}
5483
5499
  /**
5484
5500
  * Represents a local track for a display source.
5485
5501
  */
5486
- class LocalDisplayTrack extends LocalTrack {}
5502
+ class LocalDisplayTrack extends LocalTrack {
5503
+ /**
5504
+ * Create a LocalDisplayTrack from the given values.
5505
+ *
5506
+ * @param stream - The MediaStream for this track.
5507
+ * @param videoContentHint - An optional content hint, describing the content of the track.
5508
+ */
5509
+ constructor(stream, videoContentHint) {
5510
+ super(stream);
5511
+ this._videoContentHint = videoContentHint;
5512
+ this.underlyingTrack.contentHint = videoContentHint || '';
5513
+ }
5514
+ /**
5515
+ * Get the VideoContentHint for this track.
5516
+ *
5517
+ * @returns The VideoContentHint for this track.
5518
+ */
5519
+ get videoContentHint() {
5520
+ return this._videoContentHint;
5521
+ }
5522
+ }
5487
5523
 
5488
5524
  /**
5489
5525
  * Represents a local track for a microphone source.
@@ -8976,14 +9012,15 @@ var MediaCodecMimeType;
8976
9012
  })(MediaCodecMimeType || (MediaCodecMimeType = {}));
8977
9013
  var defaultMaxVideoEncodeFrameSize = 8160;
8978
9014
  var defaultMaxVideoEncodeMbps = 244800;
8979
- var RecommendedOpusBitrates;
9015
+ exports.RecommendedOpusBitrates = void 0;
8980
9016
  (function (RecommendedOpusBitrates) {
8981
9017
  RecommendedOpusBitrates[RecommendedOpusBitrates["NB"] = 12000] = "NB";
8982
9018
  RecommendedOpusBitrates[RecommendedOpusBitrates["WB"] = 20000] = "WB";
8983
9019
  RecommendedOpusBitrates[RecommendedOpusBitrates["FB"] = 40000] = "FB";
8984
9020
  RecommendedOpusBitrates[RecommendedOpusBitrates["FB_MONO_MUSIC"] = 64000] = "FB_MONO_MUSIC";
8985
9021
  RecommendedOpusBitrates[RecommendedOpusBitrates["FB_STEREO_MUSIC"] = 128000] = "FB_STEREO_MUSIC";
8986
- })(RecommendedOpusBitrates || (RecommendedOpusBitrates = {}));
9022
+ })(exports.RecommendedOpusBitrates || (exports.RecommendedOpusBitrates = {}));
9023
+ var maxFrameSizeToMaxBitrateMap = new Map([[60, 99000], [240, 199000], [576, 300000], [920, 640000], [1296, 720000], [2304, 880000], [3600, 2500000], [8160, 4000000]]);
8987
9024
  function areProfileLevelIdsCompatible(senderProfileLevelId, receiverProfileLevelId, levelAsymmetryAllowed) {
8988
9025
  var senderProfile = Number.parseInt("0x".concat(senderProfileLevelId), 16);
8989
9026
  var recvProfile = Number.parseInt("0x".concat(receiverProfileLevelId), 16);
@@ -9032,8 +9069,22 @@ function getFrameHeightByMaxFs(sourceAspectRatio, requestedMaxFs) {
9032
9069
  var minNumberRatiosForHeight = sourceAspectRatio[1] / _gcd;
9033
9070
  return Math.floor(Math.sqrt(requestedMaxFs * 16 * 16 / (minNumberRatiosForWidth * minNumberRatiosForHeight))) * minNumberRatiosForHeight;
9034
9071
  }
9035
- function getScaleDownRatio(sourceAspectRatio, sourceHeight, requestedMaxFs) {
9036
- return sourceHeight / getFrameHeightByMaxFs(sourceAspectRatio, requestedMaxFs);
9072
+ function getScaleDownRatio(sourceWidth, sourceHeight, maxFs, maxWidth, maxHeight) {
9073
+ if (!sourceWidth || !sourceHeight || !maxFs) {
9074
+ return undefined;
9075
+ }
9076
+ var scaleDownRatio = Math.max(sourceHeight / getFrameHeightByMaxFs([sourceWidth, sourceHeight], maxFs), 1.0);
9077
+ if (maxWidth && maxHeight) {
9078
+ scaleDownRatio = Math.max(sourceWidth / maxWidth, sourceHeight / maxHeight, scaleDownRatio);
9079
+ }
9080
+ return scaleDownRatio;
9081
+ }
9082
+ function getRecommendedMaxBitrateForFrameSize(requestedMaxFs) {
9083
+ if (requestedMaxFs < 60) {
9084
+ throw new Error("requested video max frame size can not less than 60");
9085
+ }
9086
+ var expectedHeight = [...maxFrameSizeToMaxBitrateMap.keys()].sort((a, b) => b - a).find(h => requestedMaxFs >= h);
9087
+ return maxFrameSizeToMaxBitrateMap.get(expectedHeight);
9037
9088
  }
9038
9089
  var commonjsGlobal$1 = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global$1 !== 'undefined' ? global$1 : typeof self !== 'undefined' ? self : {};
9039
9090
  var logger$2 = {
@@ -9483,11 +9534,12 @@ function compareStreamIds(id1, id2) {
9483
9534
  return keys1.every(key => id1[key] === id2[key]);
9484
9535
  }
9485
9536
  class SourceIndicationMsg {
9486
- constructor(seqNum, numTotalSources, numLiveSources, sources) {
9537
+ constructor(seqNum, numTotalSources, numLiveSources, sources, videoContentHint) {
9487
9538
  this.seqNum = seqNum;
9488
9539
  this.numTotalSources = numTotalSources;
9489
9540
  this.numLiveSources = numLiveSources;
9490
9541
  this.sources = sources;
9542
+ this.videoContentHint = videoContentHint;
9491
9543
  }
9492
9544
  sourcesToString() {
9493
9545
  return this.sources.map(source => "Source(id=".concat(source.id, " state=").concat(source.state, " ").concat(source.csi ? "csi=".concat(source.csi) : '', ")")).join(', ');
@@ -9574,13 +9626,13 @@ class JmpSession extends EventEmitter$4 {
9574
9626
  this.logger.warn("Retransmits for message expired: ".concat(expiredJmpMsg));
9575
9627
  });
9576
9628
  }
9577
- updateSourceIndication(numTotalSources, numLiveSources, sources) {
9629
+ updateSourceIndication(numTotalSources, numLiveSources, sources, videoContentHint) {
9578
9630
  var _a;
9579
9631
  var filteredSources = sources.filter(source => {
9580
9632
  var _a;
9581
9633
  return (_a = this.lastReceivedScr) === null || _a === void 0 ? void 0 : _a.requests.some(req => req.ids.find(streamId => compareStreamIds(streamId, source.id)));
9582
9634
  });
9583
- var sourceIndicationMsg = new SourceIndicationMsg(this.currSourceIndicationSeqNum++, numTotalSources, numLiveSources, filteredSources);
9635
+ var sourceIndicationMsg = new SourceIndicationMsg(this.currSourceIndicationSeqNum++, numTotalSources, numLiveSources, filteredSources, videoContentHint);
9584
9636
  var jmpMsg = new JmpMsg(this.mediaFamily, this.mediaContent, {
9585
9637
  msgType: JmpMsgType$1.SourceIndication,
9586
9638
  payload: sourceIndicationMsg
@@ -12586,40 +12638,6 @@ class SendOnlyTransceiver extends Transceiver {
12586
12638
  }
12587
12639
  });
12588
12640
  }
12589
- updateSimulcastStreamStates(requestedIdEncodingParamsMap) {
12590
- return __awaiter(this, void 0, void 0, function* () {
12591
- var sendParameters = this.sender.getParameters();
12592
- sendParameters.encodings.forEach((encoding, index) => {
12593
- var encodingParams = requestedIdEncodingParamsMap.get(index);
12594
- encoding.active = Boolean(encodingParams);
12595
- if (encodingParams) {
12596
- if (encodingParams.scaleDownRatio >= 1 && encoding.scaleResolutionDownBy !== encodingParams.scaleDownRatio) {
12597
- encoding.scaleResolutionDownBy = encodingParams.scaleDownRatio;
12598
- }
12599
- if (encodingParams.maxPayloadBitsPerSecond) {
12600
- encoding.maxBitrate = encodingParams.maxPayloadBitsPerSecond;
12601
- }
12602
- }
12603
- });
12604
- yield this.sender.setParameters(sendParameters);
12605
- });
12606
- }
12607
- getScaleDownRatio(expectedMaxFs) {
12608
- var _a;
12609
- if (!expectedMaxFs) {
12610
- return -1;
12611
- }
12612
- if (!this.publishedTrack) {
12613
- return -1;
12614
- }
12615
- var setting = (_a = this.publishedTrack) === null || _a === void 0 ? void 0 : _a.underlyingTrack.getSettings();
12616
- var sourceHeight = setting === null || setting === void 0 ? void 0 : setting.height;
12617
- var sourceWidth = setting === null || setting === void 0 ? void 0 : setting.width;
12618
- if (!sourceWidth || !sourceHeight) {
12619
- return -1;
12620
- }
12621
- return Math.max(getScaleDownRatio([sourceWidth, sourceHeight], sourceHeight, expectedMaxFs), 1.0);
12622
- }
12623
12641
  publishTrack(track) {
12624
12642
  return this.replacePublishedTrack(track);
12625
12643
  }
@@ -12634,6 +12652,28 @@ class SendOnlyTransceiver extends Transceiver {
12634
12652
  getStats() {
12635
12653
  return this.sender.getStats();
12636
12654
  }
12655
+ updateSendParameters(requestedIdEncodingParamsMap) {
12656
+ return __awaiter(this, void 0, void 0, function* () {
12657
+ var sendParameters = this.sender.getParameters();
12658
+ sendParameters.encodings.forEach((encoding, index) => {
12659
+ var encodingParams = requestedIdEncodingParamsMap.get(index);
12660
+ encoding.active = !!encodingParams;
12661
+ if (encodingParams) {
12662
+ var {
12663
+ maxPayloadBitsPerSecond,
12664
+ scaleDownRatio
12665
+ } = encodingParams;
12666
+ if (maxPayloadBitsPerSecond !== undefined && maxPayloadBitsPerSecond >= 0) {
12667
+ encoding.maxBitrate = maxPayloadBitsPerSecond;
12668
+ }
12669
+ if (scaleDownRatio !== undefined && scaleDownRatio >= 1.0) {
12670
+ encoding.scaleResolutionDownBy = scaleDownRatio;
12671
+ }
12672
+ }
12673
+ });
12674
+ yield this.sender.setParameters(sendParameters);
12675
+ });
12676
+ }
12637
12677
  }
12638
12678
  class StatsManager {
12639
12679
  constructor(statsGetter) {
@@ -12725,7 +12765,9 @@ class SsrcIngressStreamSignaler {
12725
12765
  mLine.addLine(new SsrcLine(this.ssrc, 'cname', "".concat(this.ssrc, "-cname")));
12726
12766
  mLine.addLine(new SsrcLine(this.ssrc, 'msid', '-', '1'));
12727
12767
  if (hasCodec('rtx', mLine)) {
12728
- this.rtxSsrc = generateSsrc();
12768
+ if (!this.rtxSsrc) {
12769
+ this.rtxSsrc = generateSsrc();
12770
+ }
12729
12771
  mLine.addLine(new SsrcLine(this.rtxSsrc, 'cname', "".concat(this.ssrc, "-cname")));
12730
12772
  mLine.addLine(new SsrcLine(this.rtxSsrc, 'msid', '-', '1'));
12731
12773
  mLine.addLine(new SsrcGroupLine('FID', [this.ssrc, this.rtxSsrc]));
@@ -12737,23 +12779,57 @@ class SsrcEgressStreamSignaler {
12737
12779
  this.streamIds = [];
12738
12780
  }
12739
12781
  signalStreams(simulcastEnabled, rtxEnabled, mLine) {
12782
+ var _a;
12740
12783
  mLine.rids = [];
12741
12784
  mLine.simulcast = undefined;
12742
- mLine.ssrcs = [];
12743
- mLine.ssrcGroups = [];
12744
12785
  mLine.extMaps = mLine.extMaps.filter(extMapLine => !/^urn:ietf:params:rtp-hdrext:sdes:(?:mid|rtp-stream-id|repaired-rtp-stream-id)$/.test(extMapLine.uri));
12745
- if (this.streamIds.length === 0) {
12746
- var numStreams = simulcastEnabled ? 3 : 1;
12747
- [...Array(numStreams).keys()].forEach(() => {
12748
- var newStreamId = {
12749
- ssrc: generateSsrc()
12750
- };
12751
- if (rtxEnabled) {
12752
- newStreamId.rtxSsrc = generateSsrc();
12786
+ var numStreams = simulcastEnabled ? 3 : 1;
12787
+ if (!this.streamIds.length) {
12788
+ if (mLine.ssrcs.length) {
12789
+ var ssrcs = [...new Set(mLine.ssrcs.map(ssrcLine => ssrcLine.ssrcId))];
12790
+ mLine.ssrcGroups.forEach(sg => {
12791
+ if (!sg.ssrcs.every(ssrc => ssrcs.includes(ssrc))) {
12792
+ throw new Error('SSRC present in SSRC groups is missing from SSRC lines');
12793
+ }
12794
+ });
12795
+ var rtxSsrcGroups = mLine.ssrcGroups.filter(sg => sg.semantics === 'FID');
12796
+ if (rtxSsrcGroups.length && rtxSsrcGroups.length !== numStreams) {
12797
+ throw new Error("Expect ".concat(numStreams, " RTX SSRC groups, got ").concat(rtxSsrcGroups.length));
12753
12798
  }
12754
- this.streamIds.push(newStreamId);
12755
- });
12799
+ rtxSsrcGroups.forEach(sg => {
12800
+ this.streamIds.push({
12801
+ ssrc: sg.ssrcs[0],
12802
+ rtxSsrc: sg.ssrcs[1]
12803
+ });
12804
+ });
12805
+ var simulcastSsrcs = (_a = mLine.ssrcGroups.find(sg => sg.semantics === 'SIM')) === null || _a === void 0 ? void 0 : _a.ssrcs;
12806
+ if (simulcastSsrcs) {
12807
+ if (simulcastSsrcs.length !== numStreams || !this.streamIds.every(streamId => simulcastSsrcs.includes(streamId.ssrc))) {
12808
+ throw new Error('SSRCs in simulcast SSRC group do not match primary SSRCs in RTX SSRC groups');
12809
+ }
12810
+ this.streamIds.sort((a, b) => simulcastSsrcs.indexOf(a.ssrc) - simulcastSsrcs.indexOf(b.ssrc));
12811
+ } else if (rtxSsrcGroups.length > 1) {
12812
+ throw new Error('Multiple RTX SSRC groups but no simulcast SSRC group found');
12813
+ }
12814
+ if (!this.streamIds.length) {
12815
+ this.streamIds.push({
12816
+ ssrc: ssrcs[0]
12817
+ });
12818
+ }
12819
+ } else {
12820
+ [...Array(numStreams).keys()].forEach(() => {
12821
+ var newStreamId = {
12822
+ ssrc: generateSsrc()
12823
+ };
12824
+ if (rtxEnabled) {
12825
+ newStreamId.rtxSsrc = generateSsrc();
12826
+ }
12827
+ this.streamIds.push(newStreamId);
12828
+ });
12829
+ }
12756
12830
  }
12831
+ mLine.ssrcs = [];
12832
+ mLine.ssrcGroups = [];
12757
12833
  this.streamIds.forEach(streamId => {
12758
12834
  var rtpSsrc = streamId.ssrc;
12759
12835
  mLine.addLine(new SsrcLine(rtpSsrc, 'cname', "".concat(rtpSsrc, "-cname")));
@@ -14504,10 +14580,20 @@ logger$4.setLevel(Logger$3.DEBUG);
14504
14580
  function setLogHandler(logHandler) {
14505
14581
  Logger$3.setHandler(logHandler);
14506
14582
  Logger$1.setHandler(logHandler);
14583
+ Logger$2.setHandler(logHandler);
14507
14584
  }
14508
14585
  function toMediaStreamTrackKind(mediaType) {
14509
14586
  return [MediaType.VideoMain, MediaType.VideoSlides].includes(mediaType) ? exports.MediaStreamTrackKind.Video : exports.MediaStreamTrackKind.Audio;
14510
14587
  }
14588
+ function webRtcVideoContentHintToJmpVideoContentHint(hint) {
14589
+ if (hint === 'motion') {
14590
+ return 'motion';
14591
+ }
14592
+ if (hint === 'detail') {
14593
+ return 'sharpness';
14594
+ }
14595
+ return undefined;
14596
+ }
14511
14597
  function toMediaFamily(kind) {
14512
14598
  if (kind === exports.MediaStreamTrackKind.Video) {
14513
14599
  return MediaFamily.Video;
@@ -14724,6 +14810,7 @@ class MultistreamConnection extends EventEmitter {
14724
14810
  updateRequestedStreams(mediaType, requests) {
14725
14811
  var sendTransceiver = this.getSendTransceiverOrThrow(mediaType);
14726
14812
  var signaler = this.streamSignalerManager.getEgressStreamSignalerOrThrow(sendTransceiver.mid);
14813
+ var mediaFamily = getMediaFamily$1(mediaType);
14727
14814
  var requestedIdEncodingParamsMap = new Map();
14728
14815
  var rsRequests = requests.filter(r => isValidReceiverSelectedInfo(r.policySpecificInfo));
14729
14816
  if (rsRequests.length !== requests.length) {
@@ -14736,7 +14823,7 @@ class MultistreamConnection extends EventEmitter {
14736
14823
  codecInfos,
14737
14824
  maxPayloadBitsPerSecond
14738
14825
  } = _ref6;
14739
- var _a;
14826
+ var _a, _b, _c, _d;
14740
14827
  if (ids.length > 1) {
14741
14828
  throw new Error("More than a single ID being unexpected/invalid ".concat(ids));
14742
14829
  }
@@ -14753,10 +14840,16 @@ class MultistreamConnection extends EventEmitter {
14753
14840
  if (streamIdsMatched) {
14754
14841
  var encodingIndex = signaler.getEncodingIndexForStreamId(id);
14755
14842
  if (encodingIndex !== -1) {
14756
- requestedIdEncodingParamsMap.set(encodingIndex, {
14757
- scaleDownRatio: sendTransceiver.getScaleDownRatio((_a = codecInfo === null || codecInfo === void 0 ? void 0 : codecInfo.h264) === null || _a === void 0 ? void 0 : _a.maxFs),
14843
+ var encodingParams = {
14758
14844
  maxPayloadBitsPerSecond
14759
- });
14845
+ };
14846
+ if (mediaFamily === MediaFamily.Video) {
14847
+ var trackSettings = (_a = sendTransceiver.publishedTrack) === null || _a === void 0 ? void 0 : _a.getSettings();
14848
+ if (trackSettings) {
14849
+ encodingParams.scaleDownRatio = getScaleDownRatio(trackSettings.width, trackSettings.height, (_b = codecInfo === null || codecInfo === void 0 ? void 0 : codecInfo.h264) === null || _b === void 0 ? void 0 : _b.maxFs, (_c = codecInfo === null || codecInfo === void 0 ? void 0 : codecInfo.h264) === null || _c === void 0 ? void 0 : _c.maxWidth, (_d = codecInfo === null || codecInfo === void 0 ? void 0 : codecInfo.h264) === null || _d === void 0 ? void 0 : _d.maxHeight);
14850
+ }
14851
+ }
14852
+ requestedIdEncodingParamsMap.set(encodingIndex, encodingParams);
14760
14853
  } else {
14761
14854
  logger$4.warn("".concat(mediaType, ": Unable to get encoding index for stream ID: ").concat(JSON.stringify(id)));
14762
14855
  }
@@ -14765,32 +14858,14 @@ class MultistreamConnection extends EventEmitter {
14765
14858
  }
14766
14859
  });
14767
14860
  sendTransceiver.setTrackRequested(requestedIdEncodingParamsMap.size > 0);
14768
- if (getMediaFamily$1(mediaType) === MediaFamily.Video) {
14769
- sendTransceiver.updateSimulcastStreamStates(requestedIdEncodingParamsMap);
14770
- }
14861
+ sendTransceiver.updateSendParameters(requestedIdEncodingParamsMap);
14771
14862
  }
14772
14863
  createDataChannel() {
14773
14864
  var dataChannel = this.pc.createDataChannel('datachannel', {});
14774
14865
  dataChannel.onopen = e => {
14775
14866
  logger$4.info('DataChannel opened: ', e);
14776
- this.sendTransceivers.forEach((transceiver, mediaType) => {
14777
- var track = transceiver.publishedTrack;
14778
- if (track) {
14779
- if (getMediaFamily$1(mediaType) === MediaFamily.Audio) {
14780
- this.sendSourceIndication(mediaType, +!track.muted);
14781
- } else {
14782
- var signaler = this.streamSignalerManager.getEgressStreamSignalerOrThrow(transceiver.mid);
14783
- var state = track.muted ? 'avatar' : 'live';
14784
- var sources = signaler.getSenderIds().map(id => ({
14785
- id,
14786
- state,
14787
- csi: transceiver.csi
14788
- }));
14789
- this.sendSourceIndication(mediaType, +!track.muted, sources);
14790
- }
14791
- } else {
14792
- this.sendSourceIndication(mediaType, 0);
14793
- }
14867
+ [...this.sendTransceivers.keys()].forEach(mediaType => {
14868
+ this.maybeSendSourceIndication(mediaType);
14794
14869
  });
14795
14870
  logger$4.info("Flushing pending JMP task queue");
14796
14871
  this.pendingJmpTasks.forEach(t => t());
@@ -14838,12 +14913,31 @@ class MultistreamConnection extends EventEmitter {
14838
14913
  });
14839
14914
  this.pc.close();
14840
14915
  }
14916
+ maybeSendSourceIndication(mediaType) {
14917
+ var _a;
14918
+ var transceiver = this.getSendTransceiverOrThrow(mediaType);
14919
+ var numLiveSources = ((_a = transceiver.publishedTrack) === null || _a === void 0 ? void 0 : _a.muted) === false ? 1 : 0;
14920
+ if (getMediaFamily$1(mediaType) === MediaFamily.Video) {
14921
+ var sources = this.getVideoSources(mediaType);
14922
+ if (sources === null) {
14923
+ return;
14924
+ }
14925
+ var webRtcVideoContentHint;
14926
+ if (transceiver.publishedTrack instanceof LocalDisplayTrack) {
14927
+ webRtcVideoContentHint = transceiver.publishedTrack.videoContentHint;
14928
+ }
14929
+ this.sendSourceIndication(mediaType, numLiveSources, sources, webRtcVideoContentHintToJmpVideoContentHint(webRtcVideoContentHint));
14930
+ } else {
14931
+ this.sendSourceIndication(mediaType, numLiveSources);
14932
+ }
14933
+ }
14841
14934
  sendSourceIndication(mediaType, numLiveSources) {
14842
14935
  var sources = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
14936
+ var videoContentHint = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : undefined;
14843
14937
  var _a;
14844
14938
  var task = () => {
14845
14939
  var _a;
14846
- (_a = this.jmpSessions.get(mediaType)) === null || _a === void 0 ? void 0 : _a.updateSourceIndication(1, numLiveSources, sources);
14940
+ (_a = this.jmpSessions.get(mediaType)) === null || _a === void 0 ? void 0 : _a.updateSourceIndication(1, numLiveSources, sources, videoContentHint);
14847
14941
  };
14848
14942
  if (((_a = this.dataChannel) === null || _a === void 0 ? void 0 : _a.readyState) === 'open') {
14849
14943
  task();
@@ -14885,23 +14979,9 @@ class MultistreamConnection extends EventEmitter {
14885
14979
  });
14886
14980
  }
14887
14981
  addTrackListeners(mediaType, track) {
14888
- var onTrackResolutionChange = () => {
14889
- var sources = this.getVideoSources(mediaType);
14890
- if (sources != null) {
14891
- this.sendSourceIndication(mediaType, 1, sources);
14892
- }
14893
- };
14982
+ var onTrackResolutionChange = () => this.maybeSendSourceIndication(mediaType);
14894
14983
  track.on(LocalTrack.Events.TrackConstraintsChange, onTrackResolutionChange);
14895
- var onTrackMute = event => {
14896
- if (getMediaFamily$1(mediaType) === MediaFamily.Audio) {
14897
- this.sendSourceIndication(mediaType, +!event.trackState.muted);
14898
- } else {
14899
- var sources = this.getVideoSources(mediaType);
14900
- if (sources != null) {
14901
- this.sendSourceIndication(mediaType, +!event.trackState.muted, sources);
14902
- }
14903
- }
14904
- };
14984
+ var onTrackMute = () => this.maybeSendSourceIndication(mediaType);
14905
14985
  track.on(LocalTrack.Events.Muted, onTrackMute);
14906
14986
  var onTrackPublish = event => {
14907
14987
  if (!event.isPublished) {
@@ -14909,13 +14989,8 @@ class MultistreamConnection extends EventEmitter {
14909
14989
  track.off(LocalTrack.Events.PublishedStateUpdate, onTrackPublish);
14910
14990
  track.off(LocalTrack.Events.TrackConstraintsChange, onTrackResolutionChange);
14911
14991
  }
14912
- if (getMediaFamily$1(mediaType) === MediaFamily.Audio) {
14913
- this.sendSourceIndication(mediaType, +event.isPublished);
14914
- } else {
14915
- var sources = this.getVideoSources(mediaType);
14916
- if (sources != null) {
14917
- this.sendSourceIndication(mediaType, +event.isPublished, sources);
14918
- }
14992
+ if (!track.muted) {
14993
+ this.maybeSendSourceIndication(mediaType);
14919
14994
  }
14920
14995
  };
14921
14996
  track.on(LocalTrack.Events.PublishedStateUpdate, onTrackPublish);
@@ -24484,6 +24559,7 @@ exports.getDevices = getDevices;
24484
24559
  exports.getErrorDescription = getErrorDescription;
24485
24560
  exports.getLogger = getLogger;
24486
24561
  exports.getMediaFamily = getMediaFamily;
24562
+ exports.getRecommendedMaxBitrateForFrameSize = getRecommendedMaxBitrateForFrameSize;
24487
24563
  exports.getVideoInputDevices = getVideoInputDevices;
24488
24564
  exports.isBrowserSupported = isBrowserSupported;
24489
24565
  exports.setLogger = setLogger;
package/dist/esm/index.js CHANGED
@@ -4207,7 +4207,7 @@ function _mergeNamespaces$1(n, m) {
4207
4207
  return Object.freeze(n);
4208
4208
  }
4209
4209
 
4210
- /*! *****************************************************************************
4210
+ /******************************************************************************
4211
4211
  Copyright (c) Microsoft Corporation.
4212
4212
 
4213
4213
  Permission to use, copy, modify, and/or distribute this software for any
@@ -4521,8 +4521,13 @@ var logger$1$1 = {
4521
4521
  var Logger$2 = logger$1$1.exports;
4522
4522
  var DEFAULT_LOGGER_NAME$1 = 'webrtc-core';
4523
4523
  var logger$3 = Logger$2.get(DEFAULT_LOGGER_NAME$1);
4524
- // Set log level to debug by default.
4525
- logger$3.setLevel(Logger$2.DEBUG);
4524
+ Logger$2.useDefaults({
4525
+ defaultLevel: Logger$2.DEBUG,
4526
+ /* eslint-disable-next-line jsdoc/require-jsdoc */
4527
+ formatter: (messages, context) => {
4528
+ messages.unshift("[".concat(context.name, "]"));
4529
+ }
4530
+ });
4526
4531
  var DeviceKind;
4527
4532
  (function (DeviceKind) {
4528
4533
  DeviceKind["AudioInput"] = "audioinput";
@@ -4737,14 +4742,15 @@ function createMicrophoneTrack(constructor, constraints) {
4737
4742
  * Creates a display video track.
4738
4743
  *
4739
4744
  * @param constructor - Constructor for the local display track.
4745
+ * @param videoContentHint - An optional parameters to give a hint for the content of the track.
4740
4746
  * @returns A Promise that resolves to a LocalDisplayTrack.
4741
4747
  */
4742
- function createDisplayTrack(constructor) {
4748
+ function createDisplayTrack(constructor, videoContentHint) {
4743
4749
  return __awaiter$1(this, void 0, void 0, function* () {
4744
4750
  var stream = yield getDisplayMedia({
4745
4751
  video: true
4746
4752
  });
4747
- return new constructor(stream);
4753
+ return new constructor(stream, videoContentHint);
4748
4754
  });
4749
4755
  }
4750
4756
  /**
@@ -5399,16 +5405,26 @@ class LocalTrack extends EventEmitter$2 {
5399
5405
  }
5400
5406
  return effect;
5401
5407
  }
5408
+ /**
5409
+ * Get a copy of the effects Map.
5410
+ *
5411
+ * @returns A copy of the effects map.
5412
+ */
5413
+ getEffects() {
5414
+ return new Map(this.effects);
5415
+ }
5402
5416
  /**
5403
5417
  * Cleanup the local microphone track.
5404
5418
  */
5405
5419
  disposeEffects() {
5406
- if (this.effects.size > 0) {
5407
- this.effects.forEach(effect => effect.dispose());
5408
- this.effects.clear();
5409
- this.underlyingStream = this.originalStream;
5410
- this.emit(LocalTrackEvents.UnderlyingTrackChange);
5411
- }
5420
+ return __awaiter$1(this, void 0, void 0, function* () {
5421
+ if (this.effects.size > 0) {
5422
+ yield Promise.all(Array.from(this.effects.values(), effect => effect.dispose()));
5423
+ this.effects.clear();
5424
+ this.underlyingStream = this.originalStream;
5425
+ this.emit(LocalTrackEvents.UnderlyingTrackChange);
5426
+ }
5427
+ });
5412
5428
  }
5413
5429
  /**
5414
5430
  * Apply constraints to the track.
@@ -5472,7 +5488,27 @@ class LocalCameraTrack extends LocalTrack {}
5472
5488
  /**
5473
5489
  * Represents a local track for a display source.
5474
5490
  */
5475
- class LocalDisplayTrack extends LocalTrack {}
5491
+ class LocalDisplayTrack extends LocalTrack {
5492
+ /**
5493
+ * Create a LocalDisplayTrack from the given values.
5494
+ *
5495
+ * @param stream - The MediaStream for this track.
5496
+ * @param videoContentHint - An optional content hint, describing the content of the track.
5497
+ */
5498
+ constructor(stream, videoContentHint) {
5499
+ super(stream);
5500
+ this._videoContentHint = videoContentHint;
5501
+ this.underlyingTrack.contentHint = videoContentHint || '';
5502
+ }
5503
+ /**
5504
+ * Get the VideoContentHint for this track.
5505
+ *
5506
+ * @returns The VideoContentHint for this track.
5507
+ */
5508
+ get videoContentHint() {
5509
+ return this._videoContentHint;
5510
+ }
5511
+ }
5476
5512
 
5477
5513
  /**
5478
5514
  * Represents a local track for a microphone source.
@@ -8973,6 +9009,7 @@ var RecommendedOpusBitrates;
8973
9009
  RecommendedOpusBitrates[RecommendedOpusBitrates["FB_MONO_MUSIC"] = 64000] = "FB_MONO_MUSIC";
8974
9010
  RecommendedOpusBitrates[RecommendedOpusBitrates["FB_STEREO_MUSIC"] = 128000] = "FB_STEREO_MUSIC";
8975
9011
  })(RecommendedOpusBitrates || (RecommendedOpusBitrates = {}));
9012
+ var maxFrameSizeToMaxBitrateMap = new Map([[60, 99000], [240, 199000], [576, 300000], [920, 640000], [1296, 720000], [2304, 880000], [3600, 2500000], [8160, 4000000]]);
8976
9013
  function areProfileLevelIdsCompatible(senderProfileLevelId, receiverProfileLevelId, levelAsymmetryAllowed) {
8977
9014
  var senderProfile = Number.parseInt("0x".concat(senderProfileLevelId), 16);
8978
9015
  var recvProfile = Number.parseInt("0x".concat(receiverProfileLevelId), 16);
@@ -9021,8 +9058,22 @@ function getFrameHeightByMaxFs(sourceAspectRatio, requestedMaxFs) {
9021
9058
  var minNumberRatiosForHeight = sourceAspectRatio[1] / _gcd;
9022
9059
  return Math.floor(Math.sqrt(requestedMaxFs * 16 * 16 / (minNumberRatiosForWidth * minNumberRatiosForHeight))) * minNumberRatiosForHeight;
9023
9060
  }
9024
- function getScaleDownRatio(sourceAspectRatio, sourceHeight, requestedMaxFs) {
9025
- return sourceHeight / getFrameHeightByMaxFs(sourceAspectRatio, requestedMaxFs);
9061
+ function getScaleDownRatio(sourceWidth, sourceHeight, maxFs, maxWidth, maxHeight) {
9062
+ if (!sourceWidth || !sourceHeight || !maxFs) {
9063
+ return undefined;
9064
+ }
9065
+ var scaleDownRatio = Math.max(sourceHeight / getFrameHeightByMaxFs([sourceWidth, sourceHeight], maxFs), 1.0);
9066
+ if (maxWidth && maxHeight) {
9067
+ scaleDownRatio = Math.max(sourceWidth / maxWidth, sourceHeight / maxHeight, scaleDownRatio);
9068
+ }
9069
+ return scaleDownRatio;
9070
+ }
9071
+ function getRecommendedMaxBitrateForFrameSize(requestedMaxFs) {
9072
+ if (requestedMaxFs < 60) {
9073
+ throw new Error("requested video max frame size can not less than 60");
9074
+ }
9075
+ var expectedHeight = [...maxFrameSizeToMaxBitrateMap.keys()].sort((a, b) => b - a).find(h => requestedMaxFs >= h);
9076
+ return maxFrameSizeToMaxBitrateMap.get(expectedHeight);
9026
9077
  }
9027
9078
  var commonjsGlobal$1 = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global$1 !== 'undefined' ? global$1 : typeof self !== 'undefined' ? self : {};
9028
9079
  var logger$2 = {
@@ -9472,11 +9523,12 @@ function compareStreamIds(id1, id2) {
9472
9523
  return keys1.every(key => id1[key] === id2[key]);
9473
9524
  }
9474
9525
  class SourceIndicationMsg {
9475
- constructor(seqNum, numTotalSources, numLiveSources, sources) {
9526
+ constructor(seqNum, numTotalSources, numLiveSources, sources, videoContentHint) {
9476
9527
  this.seqNum = seqNum;
9477
9528
  this.numTotalSources = numTotalSources;
9478
9529
  this.numLiveSources = numLiveSources;
9479
9530
  this.sources = sources;
9531
+ this.videoContentHint = videoContentHint;
9480
9532
  }
9481
9533
  sourcesToString() {
9482
9534
  return this.sources.map(source => "Source(id=".concat(source.id, " state=").concat(source.state, " ").concat(source.csi ? "csi=".concat(source.csi) : '', ")")).join(', ');
@@ -9563,13 +9615,13 @@ class JmpSession extends EventEmitter$4 {
9563
9615
  this.logger.warn("Retransmits for message expired: ".concat(expiredJmpMsg));
9564
9616
  });
9565
9617
  }
9566
- updateSourceIndication(numTotalSources, numLiveSources, sources) {
9618
+ updateSourceIndication(numTotalSources, numLiveSources, sources, videoContentHint) {
9567
9619
  var _a;
9568
9620
  var filteredSources = sources.filter(source => {
9569
9621
  var _a;
9570
9622
  return (_a = this.lastReceivedScr) === null || _a === void 0 ? void 0 : _a.requests.some(req => req.ids.find(streamId => compareStreamIds(streamId, source.id)));
9571
9623
  });
9572
- var sourceIndicationMsg = new SourceIndicationMsg(this.currSourceIndicationSeqNum++, numTotalSources, numLiveSources, filteredSources);
9624
+ var sourceIndicationMsg = new SourceIndicationMsg(this.currSourceIndicationSeqNum++, numTotalSources, numLiveSources, filteredSources, videoContentHint);
9573
9625
  var jmpMsg = new JmpMsg(this.mediaFamily, this.mediaContent, {
9574
9626
  msgType: JmpMsgType$1.SourceIndication,
9575
9627
  payload: sourceIndicationMsg
@@ -12575,40 +12627,6 @@ class SendOnlyTransceiver extends Transceiver {
12575
12627
  }
12576
12628
  });
12577
12629
  }
12578
- updateSimulcastStreamStates(requestedIdEncodingParamsMap) {
12579
- return __awaiter(this, void 0, void 0, function* () {
12580
- var sendParameters = this.sender.getParameters();
12581
- sendParameters.encodings.forEach((encoding, index) => {
12582
- var encodingParams = requestedIdEncodingParamsMap.get(index);
12583
- encoding.active = Boolean(encodingParams);
12584
- if (encodingParams) {
12585
- if (encodingParams.scaleDownRatio >= 1 && encoding.scaleResolutionDownBy !== encodingParams.scaleDownRatio) {
12586
- encoding.scaleResolutionDownBy = encodingParams.scaleDownRatio;
12587
- }
12588
- if (encodingParams.maxPayloadBitsPerSecond) {
12589
- encoding.maxBitrate = encodingParams.maxPayloadBitsPerSecond;
12590
- }
12591
- }
12592
- });
12593
- yield this.sender.setParameters(sendParameters);
12594
- });
12595
- }
12596
- getScaleDownRatio(expectedMaxFs) {
12597
- var _a;
12598
- if (!expectedMaxFs) {
12599
- return -1;
12600
- }
12601
- if (!this.publishedTrack) {
12602
- return -1;
12603
- }
12604
- var setting = (_a = this.publishedTrack) === null || _a === void 0 ? void 0 : _a.underlyingTrack.getSettings();
12605
- var sourceHeight = setting === null || setting === void 0 ? void 0 : setting.height;
12606
- var sourceWidth = setting === null || setting === void 0 ? void 0 : setting.width;
12607
- if (!sourceWidth || !sourceHeight) {
12608
- return -1;
12609
- }
12610
- return Math.max(getScaleDownRatio([sourceWidth, sourceHeight], sourceHeight, expectedMaxFs), 1.0);
12611
- }
12612
12630
  publishTrack(track) {
12613
12631
  return this.replacePublishedTrack(track);
12614
12632
  }
@@ -12623,6 +12641,28 @@ class SendOnlyTransceiver extends Transceiver {
12623
12641
  getStats() {
12624
12642
  return this.sender.getStats();
12625
12643
  }
12644
+ updateSendParameters(requestedIdEncodingParamsMap) {
12645
+ return __awaiter(this, void 0, void 0, function* () {
12646
+ var sendParameters = this.sender.getParameters();
12647
+ sendParameters.encodings.forEach((encoding, index) => {
12648
+ var encodingParams = requestedIdEncodingParamsMap.get(index);
12649
+ encoding.active = !!encodingParams;
12650
+ if (encodingParams) {
12651
+ var {
12652
+ maxPayloadBitsPerSecond,
12653
+ scaleDownRatio
12654
+ } = encodingParams;
12655
+ if (maxPayloadBitsPerSecond !== undefined && maxPayloadBitsPerSecond >= 0) {
12656
+ encoding.maxBitrate = maxPayloadBitsPerSecond;
12657
+ }
12658
+ if (scaleDownRatio !== undefined && scaleDownRatio >= 1.0) {
12659
+ encoding.scaleResolutionDownBy = scaleDownRatio;
12660
+ }
12661
+ }
12662
+ });
12663
+ yield this.sender.setParameters(sendParameters);
12664
+ });
12665
+ }
12626
12666
  }
12627
12667
  class StatsManager {
12628
12668
  constructor(statsGetter) {
@@ -12714,7 +12754,9 @@ class SsrcIngressStreamSignaler {
12714
12754
  mLine.addLine(new SsrcLine(this.ssrc, 'cname', "".concat(this.ssrc, "-cname")));
12715
12755
  mLine.addLine(new SsrcLine(this.ssrc, 'msid', '-', '1'));
12716
12756
  if (hasCodec('rtx', mLine)) {
12717
- this.rtxSsrc = generateSsrc();
12757
+ if (!this.rtxSsrc) {
12758
+ this.rtxSsrc = generateSsrc();
12759
+ }
12718
12760
  mLine.addLine(new SsrcLine(this.rtxSsrc, 'cname', "".concat(this.ssrc, "-cname")));
12719
12761
  mLine.addLine(new SsrcLine(this.rtxSsrc, 'msid', '-', '1'));
12720
12762
  mLine.addLine(new SsrcGroupLine('FID', [this.ssrc, this.rtxSsrc]));
@@ -12726,23 +12768,57 @@ class SsrcEgressStreamSignaler {
12726
12768
  this.streamIds = [];
12727
12769
  }
12728
12770
  signalStreams(simulcastEnabled, rtxEnabled, mLine) {
12771
+ var _a;
12729
12772
  mLine.rids = [];
12730
12773
  mLine.simulcast = undefined;
12731
- mLine.ssrcs = [];
12732
- mLine.ssrcGroups = [];
12733
12774
  mLine.extMaps = mLine.extMaps.filter(extMapLine => !/^urn:ietf:params:rtp-hdrext:sdes:(?:mid|rtp-stream-id|repaired-rtp-stream-id)$/.test(extMapLine.uri));
12734
- if (this.streamIds.length === 0) {
12735
- var numStreams = simulcastEnabled ? 3 : 1;
12736
- [...Array(numStreams).keys()].forEach(() => {
12737
- var newStreamId = {
12738
- ssrc: generateSsrc()
12739
- };
12740
- if (rtxEnabled) {
12741
- newStreamId.rtxSsrc = generateSsrc();
12775
+ var numStreams = simulcastEnabled ? 3 : 1;
12776
+ if (!this.streamIds.length) {
12777
+ if (mLine.ssrcs.length) {
12778
+ var ssrcs = [...new Set(mLine.ssrcs.map(ssrcLine => ssrcLine.ssrcId))];
12779
+ mLine.ssrcGroups.forEach(sg => {
12780
+ if (!sg.ssrcs.every(ssrc => ssrcs.includes(ssrc))) {
12781
+ throw new Error('SSRC present in SSRC groups is missing from SSRC lines');
12782
+ }
12783
+ });
12784
+ var rtxSsrcGroups = mLine.ssrcGroups.filter(sg => sg.semantics === 'FID');
12785
+ if (rtxSsrcGroups.length && rtxSsrcGroups.length !== numStreams) {
12786
+ throw new Error("Expect ".concat(numStreams, " RTX SSRC groups, got ").concat(rtxSsrcGroups.length));
12742
12787
  }
12743
- this.streamIds.push(newStreamId);
12744
- });
12788
+ rtxSsrcGroups.forEach(sg => {
12789
+ this.streamIds.push({
12790
+ ssrc: sg.ssrcs[0],
12791
+ rtxSsrc: sg.ssrcs[1]
12792
+ });
12793
+ });
12794
+ var simulcastSsrcs = (_a = mLine.ssrcGroups.find(sg => sg.semantics === 'SIM')) === null || _a === void 0 ? void 0 : _a.ssrcs;
12795
+ if (simulcastSsrcs) {
12796
+ if (simulcastSsrcs.length !== numStreams || !this.streamIds.every(streamId => simulcastSsrcs.includes(streamId.ssrc))) {
12797
+ throw new Error('SSRCs in simulcast SSRC group do not match primary SSRCs in RTX SSRC groups');
12798
+ }
12799
+ this.streamIds.sort((a, b) => simulcastSsrcs.indexOf(a.ssrc) - simulcastSsrcs.indexOf(b.ssrc));
12800
+ } else if (rtxSsrcGroups.length > 1) {
12801
+ throw new Error('Multiple RTX SSRC groups but no simulcast SSRC group found');
12802
+ }
12803
+ if (!this.streamIds.length) {
12804
+ this.streamIds.push({
12805
+ ssrc: ssrcs[0]
12806
+ });
12807
+ }
12808
+ } else {
12809
+ [...Array(numStreams).keys()].forEach(() => {
12810
+ var newStreamId = {
12811
+ ssrc: generateSsrc()
12812
+ };
12813
+ if (rtxEnabled) {
12814
+ newStreamId.rtxSsrc = generateSsrc();
12815
+ }
12816
+ this.streamIds.push(newStreamId);
12817
+ });
12818
+ }
12745
12819
  }
12820
+ mLine.ssrcs = [];
12821
+ mLine.ssrcGroups = [];
12746
12822
  this.streamIds.forEach(streamId => {
12747
12823
  var rtpSsrc = streamId.ssrc;
12748
12824
  mLine.addLine(new SsrcLine(rtpSsrc, 'cname', "".concat(rtpSsrc, "-cname")));
@@ -14493,10 +14569,20 @@ logger$4.setLevel(Logger$3.DEBUG);
14493
14569
  function setLogHandler(logHandler) {
14494
14570
  Logger$3.setHandler(logHandler);
14495
14571
  Logger$1.setHandler(logHandler);
14572
+ Logger$2.setHandler(logHandler);
14496
14573
  }
14497
14574
  function toMediaStreamTrackKind(mediaType) {
14498
14575
  return [MediaType$1.VideoMain, MediaType$1.VideoSlides].includes(mediaType) ? MediaStreamTrackKind.Video : MediaStreamTrackKind.Audio;
14499
14576
  }
14577
+ function webRtcVideoContentHintToJmpVideoContentHint(hint) {
14578
+ if (hint === 'motion') {
14579
+ return 'motion';
14580
+ }
14581
+ if (hint === 'detail') {
14582
+ return 'sharpness';
14583
+ }
14584
+ return undefined;
14585
+ }
14500
14586
  function toMediaFamily(kind) {
14501
14587
  if (kind === MediaStreamTrackKind.Video) {
14502
14588
  return MediaFamily$1.Video;
@@ -14713,6 +14799,7 @@ class MultistreamConnection extends EventEmitter {
14713
14799
  updateRequestedStreams(mediaType, requests) {
14714
14800
  var sendTransceiver = this.getSendTransceiverOrThrow(mediaType);
14715
14801
  var signaler = this.streamSignalerManager.getEgressStreamSignalerOrThrow(sendTransceiver.mid);
14802
+ var mediaFamily = getMediaFamily$1(mediaType);
14716
14803
  var requestedIdEncodingParamsMap = new Map();
14717
14804
  var rsRequests = requests.filter(r => isValidReceiverSelectedInfo(r.policySpecificInfo));
14718
14805
  if (rsRequests.length !== requests.length) {
@@ -14725,7 +14812,7 @@ class MultistreamConnection extends EventEmitter {
14725
14812
  codecInfos,
14726
14813
  maxPayloadBitsPerSecond
14727
14814
  } = _ref6;
14728
- var _a;
14815
+ var _a, _b, _c, _d;
14729
14816
  if (ids.length > 1) {
14730
14817
  throw new Error("More than a single ID being unexpected/invalid ".concat(ids));
14731
14818
  }
@@ -14742,10 +14829,16 @@ class MultistreamConnection extends EventEmitter {
14742
14829
  if (streamIdsMatched) {
14743
14830
  var encodingIndex = signaler.getEncodingIndexForStreamId(id);
14744
14831
  if (encodingIndex !== -1) {
14745
- requestedIdEncodingParamsMap.set(encodingIndex, {
14746
- scaleDownRatio: sendTransceiver.getScaleDownRatio((_a = codecInfo === null || codecInfo === void 0 ? void 0 : codecInfo.h264) === null || _a === void 0 ? void 0 : _a.maxFs),
14832
+ var encodingParams = {
14747
14833
  maxPayloadBitsPerSecond
14748
- });
14834
+ };
14835
+ if (mediaFamily === MediaFamily$1.Video) {
14836
+ var trackSettings = (_a = sendTransceiver.publishedTrack) === null || _a === void 0 ? void 0 : _a.getSettings();
14837
+ if (trackSettings) {
14838
+ encodingParams.scaleDownRatio = getScaleDownRatio(trackSettings.width, trackSettings.height, (_b = codecInfo === null || codecInfo === void 0 ? void 0 : codecInfo.h264) === null || _b === void 0 ? void 0 : _b.maxFs, (_c = codecInfo === null || codecInfo === void 0 ? void 0 : codecInfo.h264) === null || _c === void 0 ? void 0 : _c.maxWidth, (_d = codecInfo === null || codecInfo === void 0 ? void 0 : codecInfo.h264) === null || _d === void 0 ? void 0 : _d.maxHeight);
14839
+ }
14840
+ }
14841
+ requestedIdEncodingParamsMap.set(encodingIndex, encodingParams);
14749
14842
  } else {
14750
14843
  logger$4.warn("".concat(mediaType, ": Unable to get encoding index for stream ID: ").concat(JSON.stringify(id)));
14751
14844
  }
@@ -14754,32 +14847,14 @@ class MultistreamConnection extends EventEmitter {
14754
14847
  }
14755
14848
  });
14756
14849
  sendTransceiver.setTrackRequested(requestedIdEncodingParamsMap.size > 0);
14757
- if (getMediaFamily$1(mediaType) === MediaFamily$1.Video) {
14758
- sendTransceiver.updateSimulcastStreamStates(requestedIdEncodingParamsMap);
14759
- }
14850
+ sendTransceiver.updateSendParameters(requestedIdEncodingParamsMap);
14760
14851
  }
14761
14852
  createDataChannel() {
14762
14853
  var dataChannel = this.pc.createDataChannel('datachannel', {});
14763
14854
  dataChannel.onopen = e => {
14764
14855
  logger$4.info('DataChannel opened: ', e);
14765
- this.sendTransceivers.forEach((transceiver, mediaType) => {
14766
- var track = transceiver.publishedTrack;
14767
- if (track) {
14768
- if (getMediaFamily$1(mediaType) === MediaFamily$1.Audio) {
14769
- this.sendSourceIndication(mediaType, +!track.muted);
14770
- } else {
14771
- var signaler = this.streamSignalerManager.getEgressStreamSignalerOrThrow(transceiver.mid);
14772
- var state = track.muted ? 'avatar' : 'live';
14773
- var sources = signaler.getSenderIds().map(id => ({
14774
- id,
14775
- state,
14776
- csi: transceiver.csi
14777
- }));
14778
- this.sendSourceIndication(mediaType, +!track.muted, sources);
14779
- }
14780
- } else {
14781
- this.sendSourceIndication(mediaType, 0);
14782
- }
14856
+ [...this.sendTransceivers.keys()].forEach(mediaType => {
14857
+ this.maybeSendSourceIndication(mediaType);
14783
14858
  });
14784
14859
  logger$4.info("Flushing pending JMP task queue");
14785
14860
  this.pendingJmpTasks.forEach(t => t());
@@ -14827,12 +14902,31 @@ class MultistreamConnection extends EventEmitter {
14827
14902
  });
14828
14903
  this.pc.close();
14829
14904
  }
14905
+ maybeSendSourceIndication(mediaType) {
14906
+ var _a;
14907
+ var transceiver = this.getSendTransceiverOrThrow(mediaType);
14908
+ var numLiveSources = ((_a = transceiver.publishedTrack) === null || _a === void 0 ? void 0 : _a.muted) === false ? 1 : 0;
14909
+ if (getMediaFamily$1(mediaType) === MediaFamily$1.Video) {
14910
+ var sources = this.getVideoSources(mediaType);
14911
+ if (sources === null) {
14912
+ return;
14913
+ }
14914
+ var webRtcVideoContentHint;
14915
+ if (transceiver.publishedTrack instanceof LocalDisplayTrack) {
14916
+ webRtcVideoContentHint = transceiver.publishedTrack.videoContentHint;
14917
+ }
14918
+ this.sendSourceIndication(mediaType, numLiveSources, sources, webRtcVideoContentHintToJmpVideoContentHint(webRtcVideoContentHint));
14919
+ } else {
14920
+ this.sendSourceIndication(mediaType, numLiveSources);
14921
+ }
14922
+ }
14830
14923
  sendSourceIndication(mediaType, numLiveSources) {
14831
14924
  var sources = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
14925
+ var videoContentHint = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : undefined;
14832
14926
  var _a;
14833
14927
  var task = () => {
14834
14928
  var _a;
14835
- (_a = this.jmpSessions.get(mediaType)) === null || _a === void 0 ? void 0 : _a.updateSourceIndication(1, numLiveSources, sources);
14929
+ (_a = this.jmpSessions.get(mediaType)) === null || _a === void 0 ? void 0 : _a.updateSourceIndication(1, numLiveSources, sources, videoContentHint);
14836
14930
  };
14837
14931
  if (((_a = this.dataChannel) === null || _a === void 0 ? void 0 : _a.readyState) === 'open') {
14838
14932
  task();
@@ -14874,23 +14968,9 @@ class MultistreamConnection extends EventEmitter {
14874
14968
  });
14875
14969
  }
14876
14970
  addTrackListeners(mediaType, track) {
14877
- var onTrackResolutionChange = () => {
14878
- var sources = this.getVideoSources(mediaType);
14879
- if (sources != null) {
14880
- this.sendSourceIndication(mediaType, 1, sources);
14881
- }
14882
- };
14971
+ var onTrackResolutionChange = () => this.maybeSendSourceIndication(mediaType);
14883
14972
  track.on(LocalTrack.Events.TrackConstraintsChange, onTrackResolutionChange);
14884
- var onTrackMute = event => {
14885
- if (getMediaFamily$1(mediaType) === MediaFamily$1.Audio) {
14886
- this.sendSourceIndication(mediaType, +!event.trackState.muted);
14887
- } else {
14888
- var sources = this.getVideoSources(mediaType);
14889
- if (sources != null) {
14890
- this.sendSourceIndication(mediaType, +!event.trackState.muted, sources);
14891
- }
14892
- }
14893
- };
14973
+ var onTrackMute = () => this.maybeSendSourceIndication(mediaType);
14894
14974
  track.on(LocalTrack.Events.Muted, onTrackMute);
14895
14975
  var onTrackPublish = event => {
14896
14976
  if (!event.isPublished) {
@@ -14898,13 +14978,8 @@ class MultistreamConnection extends EventEmitter {
14898
14978
  track.off(LocalTrack.Events.PublishedStateUpdate, onTrackPublish);
14899
14979
  track.off(LocalTrack.Events.TrackConstraintsChange, onTrackResolutionChange);
14900
14980
  }
14901
- if (getMediaFamily$1(mediaType) === MediaFamily$1.Audio) {
14902
- this.sendSourceIndication(mediaType, +event.isPublished);
14903
- } else {
14904
- var sources = this.getVideoSources(mediaType);
14905
- if (sources != null) {
14906
- this.sendSourceIndication(mediaType, +event.isPublished, sources);
14907
- }
14981
+ if (!track.muted) {
14982
+ this.maybeSendSourceIndication(mediaType);
14908
14983
  }
14909
14984
  };
14910
14985
  track.on(LocalTrack.Events.PublishedStateUpdate, onTrackPublish);
@@ -24448,4 +24523,4 @@ var Media = {
24448
24523
  isBrowserSupported
24449
24524
  };
24450
24525
 
24451
- export { ActiveSpeakerInfo, CodecInfo, ConnectionState, ErrorType, Errors, Event$1 as Event, H264Codec, LocalCameraTrack, LocalDisplayTrack, LocalMicrophoneTrack, LocalTrack, LocalTrackEvents, Media, MediaFamily, MediaRequest, MediaStreamTrackKind, MediaType, MultistreamRoapMediaConnection, PeerConnection, Policy, ReceiveSlot, ReceiveSlotEvents, ReceiverSelectedInfo, RemoteTrackType, RoapMediaConnection, WcmeError, createCameraTrack, createDisplayTrack, createMicrophoneTrack, getAudioInputDevices, getAudioOutputDevices, getDevices, getErrorDescription, getLogger, getMediaFamily, getVideoInputDevices, isBrowserSupported, setLogger, setOnDeviceChangeHandler };
24526
+ export { ActiveSpeakerInfo, CodecInfo, ConnectionState, ErrorType, Errors, Event$1 as Event, H264Codec, LocalCameraTrack, LocalDisplayTrack, LocalMicrophoneTrack, LocalTrack, LocalTrackEvents, Media, MediaFamily, MediaRequest, MediaStreamTrackKind, MediaType, MultistreamRoapMediaConnection, PeerConnection, Policy, ReceiveSlot, ReceiveSlotEvents, ReceiverSelectedInfo, RecommendedOpusBitrates, RemoteTrackType, RoapMediaConnection, WcmeError, createCameraTrack, createDisplayTrack, createMicrophoneTrack, getAudioInputDevices, getAudioOutputDevices, getDevices, getErrorDescription, getLogger, getMediaFamily, getRecommendedMaxBitrateForFrameSize, getVideoInputDevices, isBrowserSupported, setLogger, setOnDeviceChangeHandler };
@@ -4,7 +4,7 @@ import { LocalTrack, MediaRequest, ReceiveSlot, TransceiverStats } from '@webex/
4
4
  import { MediaType } from '@webex/json-multistream';
5
5
  import { ConnectionState, RoapMessage } from './eventTypes';
6
6
  import { MultistreamConnectionConfig } from './config';
7
- export { MediaRequest, ReceiveSlot, ReceiveSlotEvents, getAudioOutputDevices, getVideoInputDevices, setOnDeviceChangeHandler, WcmeError, AudioDeviceConstraints, VideoDeviceConstraints, LocalTrackEvents, TrackPublishEvent, TrackMuteEvent, TrackEndEvent, LocalCameraTrack, LocalDisplayTrack, LocalMicrophoneTrack, LocalTrack, MediaStreamTrackKind, PeerConnection, createCameraTrack, createDisplayTrack, createMicrophoneTrack, getDevices, getAudioInputDevices, } from '@webex/web-client-media-engine';
7
+ export { MediaRequest, ReceiveSlot, ReceiveSlotEvents, getAudioOutputDevices, getVideoInputDevices, setOnDeviceChangeHandler, WcmeError, AudioDeviceConstraints, VideoDeviceConstraints, LocalTrackEvents, TrackPublishEvent, TrackMuteEvent, TrackEndEvent, LocalCameraTrack, LocalDisplayTrack, LocalMicrophoneTrack, LocalTrack, MediaStreamTrackKind, PeerConnection, createCameraTrack, createDisplayTrack, createMicrophoneTrack, getDevices, getAudioInputDevices, getRecommendedMaxBitrateForFrameSize, RecommendedOpusBitrates, } from '@webex/web-client-media-engine';
8
8
  export { ActiveSpeakerInfo, CodecInfo, getMediaFamily, H264Codec, MediaFamily, MediaType, SourceState, Policy, PolicySpecificInfo, ReceiverSelectedInfo, } from '@webex/json-multistream';
9
9
  export declare class MultistreamRoapMediaConnection extends EventEmitter {
10
10
  private id?;
@@ -1 +1 @@
1
- {"version":3,"file":"MultistreamRoapMediaConnection.d.ts","sourceRoot":"","sources":["../../../src/MediaConnection/MultistreamRoapMediaConnection.ts"],"names":[],"mappings":";AAAA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAElC,OAAO,EAEL,UAAU,EACV,YAAY,EAGZ,WAAW,EACX,gBAAgB,EACjB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAA6C,SAAS,EAAC,MAAM,yBAAyB,CAAC;AAG9F,OAAO,EAAQ,eAAe,EAAE,WAAW,EAAmB,MAAM,cAAc,CAAC;AAKnF,OAAO,EAAC,2BAA2B,EAAC,MAAM,UAAU,CAAC;AAGrD,OAAO,EAEL,YAAY,EACZ,WAAW,EACX,iBAAiB,EAEjB,qBAAqB,EACrB,oBAAoB,EACpB,wBAAwB,EACxB,SAAS,EACT,sBAAsB,EACtB,sBAAsB,EACtB,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,UAAU,EACV,oBAAoB,EACpB,cAAc,EACd,iBAAiB,EACjB,kBAAkB,EAClB,qBAAqB,EACrB,UAAU,EACV,oBAAoB,GACrB,MAAM,gCAAgC,CAAC;AAExC,OAAO,EACL,iBAAiB,EACjB,SAAS,EACT,cAAc,EACd,SAAS,EACT,WAAW,EACX,SAAS,EACT,WAAW,EACX,MAAM,EACN,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,yBAAyB,CAAC;AAGjC,qBAAa,8BAA+B,SAAQ,YAAY;IAC9D,OAAO,CAAC,EAAE,CAAC,CAAS;IAEpB,OAAO,CAAC,OAAO,CAAC,CAAS;IAEzB,OAAO,CAAC,qBAAqB,CAAwB;IAErD,OAAO,CAAC,IAAI,CAAO;IAEnB,OAAO,CAAC,qBAAqB,CAAS;gBAS1B,qBAAqB,EAAE,2BAA2B,EAAE,OAAO,CAAC,EAAE,MAAM;IAehF,OAAO,CAAC,mBAAmB;IAqC3B,OAAO,CAAC,GAAG;IAIX,OAAO,CAAC,KAAK;IAIb,OAAO,CAAC,2BAA2B;IAyCnC,OAAO,CAAC,UAAU;IA4BX,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAiB9B,KAAK,IAAI,IAAI;IAOpB,OAAO,CAAC,oBAAoB;IAK5B,OAAO,CAAC,eAAe;IAiBhB,SAAS,CAAC,UAAU,EAAE,YAAY,EAAE,EAAE,aAAa,UAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IA2B1E,kBAAkB,IAAI,eAAe;IAWrC,QAAQ,IAAI,OAAO,CAAC,cAAc,CAAC;IAOnC,mBAAmB,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAShD,mBAAmB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI;IAanD,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAYvD,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAM9C,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAMhD,iBAAiB,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;IAM7D,YAAY,CAAC,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,YAAY,EAAE,GAAG,IAAI;IAM9E,OAAO,CAAC,gBAAgB;IAkBxB,OAAO,CAAC,iBAAiB;IAKzB,OAAO,CAAC,kBAAkB;CAkB3B"}
1
+ {"version":3,"file":"MultistreamRoapMediaConnection.d.ts","sourceRoot":"","sources":["../../../src/MediaConnection/MultistreamRoapMediaConnection.ts"],"names":[],"mappings":";AAAA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAElC,OAAO,EAEL,UAAU,EACV,YAAY,EAGZ,WAAW,EACX,gBAAgB,EACjB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAA6C,SAAS,EAAC,MAAM,yBAAyB,CAAC;AAG9F,OAAO,EAAQ,eAAe,EAAE,WAAW,EAAmB,MAAM,cAAc,CAAC;AAKnF,OAAO,EAAC,2BAA2B,EAAC,MAAM,UAAU,CAAC;AAGrD,OAAO,EAEL,YAAY,EACZ,WAAW,EACX,iBAAiB,EAEjB,qBAAqB,EACrB,oBAAoB,EACpB,wBAAwB,EACxB,SAAS,EACT,sBAAsB,EACtB,sBAAsB,EACtB,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,UAAU,EACV,oBAAoB,EACpB,cAAc,EACd,iBAAiB,EACjB,kBAAkB,EAClB,qBAAqB,EACrB,UAAU,EACV,oBAAoB,EAEpB,oCAAoC,EACpC,uBAAuB,GACxB,MAAM,gCAAgC,CAAC;AAExC,OAAO,EACL,iBAAiB,EACjB,SAAS,EACT,cAAc,EACd,SAAS,EACT,WAAW,EACX,SAAS,EACT,WAAW,EACX,MAAM,EACN,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,yBAAyB,CAAC;AAGjC,qBAAa,8BAA+B,SAAQ,YAAY;IAC9D,OAAO,CAAC,EAAE,CAAC,CAAS;IAEpB,OAAO,CAAC,OAAO,CAAC,CAAS;IAEzB,OAAO,CAAC,qBAAqB,CAAwB;IAErD,OAAO,CAAC,IAAI,CAAO;IAEnB,OAAO,CAAC,qBAAqB,CAAS;gBAS1B,qBAAqB,EAAE,2BAA2B,EAAE,OAAO,CAAC,EAAE,MAAM;IAehF,OAAO,CAAC,mBAAmB;IAqC3B,OAAO,CAAC,GAAG;IAIX,OAAO,CAAC,KAAK;IAIb,OAAO,CAAC,2BAA2B;IAyCnC,OAAO,CAAC,UAAU;IA4BX,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAiB9B,KAAK,IAAI,IAAI;IAOpB,OAAO,CAAC,oBAAoB;IAK5B,OAAO,CAAC,eAAe;IAiBhB,SAAS,CAAC,UAAU,EAAE,YAAY,EAAE,EAAE,aAAa,UAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IA2B1E,kBAAkB,IAAI,eAAe;IAWrC,QAAQ,IAAI,OAAO,CAAC,cAAc,CAAC;IAOnC,mBAAmB,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAShD,mBAAmB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI;IAanD,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAYvD,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAM9C,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAMhD,iBAAiB,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;IAM7D,YAAY,CAAC,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,YAAY,EAAE,GAAG,IAAI;IAM9E,OAAO,CAAC,gBAAgB;IAkBxB,OAAO,CAAC,iBAAiB;IAKzB,OAAO,CAAC,kBAAkB;CAkB3B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webex/internal-media-core",
3
- "version": "1.35.6",
3
+ "version": "1.36.0",
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.4",
50
+ "@webex/web-client-media-engine": "1.41.0",
51
51
  "detectrtc": "^1.4.1",
52
52
  "events": "^3.3.0",
53
53
  "typed-emitter": "^2.1.0",