@webex/web-client-media-engine 1.40.4 → 1.40.5

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
@@ -547,12 +547,13 @@ function createMicrophoneTrack(constructor, constraints) {
547
547
  * Creates a display video track.
548
548
  *
549
549
  * @param constructor - Constructor for the local display track.
550
+ * @param videoContentHint - An optional parameters to give a hint for the content of the track.
550
551
  * @returns A Promise that resolves to a LocalDisplayTrack.
551
552
  */
552
- function createDisplayTrack(constructor) {
553
+ function createDisplayTrack(constructor, videoContentHint) {
553
554
  return __awaiter$1(this, void 0, void 0, function* () {
554
555
  const stream = yield getDisplayMedia({ video: true });
555
- return new constructor(stream);
556
+ return new constructor(stream, videoContentHint);
556
557
  });
557
558
  }
558
559
  /**
@@ -1358,6 +1359,25 @@ class LocalCameraTrack extends LocalTrack {
1358
1359
  * Represents a local track for a display source.
1359
1360
  */
1360
1361
  class LocalDisplayTrack extends LocalTrack {
1362
+ /**
1363
+ * Create a LocalDisplayTrack from the given values.
1364
+ *
1365
+ * @param stream - The MediaStream for this track.
1366
+ * @param videoContentHint - An optional content hint, describing the content of the track.
1367
+ */
1368
+ constructor(stream, videoContentHint) {
1369
+ super(stream);
1370
+ this._videoContentHint = videoContentHint;
1371
+ this.underlyingTrack.contentHint = videoContentHint || '';
1372
+ }
1373
+ /**
1374
+ * Get the VideoContentHint for this track.
1375
+ *
1376
+ * @returns The VideoContentHint for this track.
1377
+ */
1378
+ get videoContentHint() {
1379
+ return this._videoContentHint;
1380
+ }
1361
1381
  }
1362
1382
 
1363
1383
  /**
@@ -5709,11 +5729,12 @@ function compareStreamIds(id1, id2) {
5709
5729
  }
5710
5730
 
5711
5731
  class SourceIndicationMsg {
5712
- constructor(seqNum, numTotalSources, numLiveSources, sources) {
5732
+ constructor(seqNum, numTotalSources, numLiveSources, sources, videoContentHint) {
5713
5733
  this.seqNum = seqNum;
5714
5734
  this.numTotalSources = numTotalSources;
5715
5735
  this.numLiveSources = numLiveSources;
5716
5736
  this.sources = sources;
5737
+ this.videoContentHint = videoContentHint;
5717
5738
  }
5718
5739
  sourcesToString() {
5719
5740
  return this.sources
@@ -5809,13 +5830,13 @@ class JmpSession extends events$2.EventEmitter {
5809
5830
  this.logger.warn(`Retransmits for message expired: ${expiredJmpMsg}`);
5810
5831
  });
5811
5832
  }
5812
- updateSourceIndication(numTotalSources, numLiveSources, sources) {
5833
+ updateSourceIndication(numTotalSources, numLiveSources, sources, videoContentHint) {
5813
5834
  var _a;
5814
5835
  const filteredSources = sources.filter((source) => {
5815
5836
  var _a;
5816
5837
  return (_a = this.lastReceivedScr) === null || _a === void 0 ? void 0 : _a.requests.some((req) => req.ids.find((streamId) => compareStreamIds(streamId, source.id)));
5817
5838
  });
5818
- const sourceIndicationMsg = new SourceIndicationMsg(this.currSourceIndicationSeqNum++, numTotalSources, numLiveSources, filteredSources);
5839
+ const sourceIndicationMsg = new SourceIndicationMsg(this.currSourceIndicationSeqNum++, numTotalSources, numLiveSources, filteredSources, videoContentHint);
5819
5840
  const jmpMsg = new JmpMsg(this.mediaFamily, this.mediaContent, {
5820
5841
  msgType: JmpMsgType.SourceIndication,
5821
5842
  payload: sourceIndicationMsg,
@@ -9201,23 +9222,58 @@ class SsrcEgressStreamSignaler {
9201
9222
  this.streamIds = [];
9202
9223
  }
9203
9224
  signalStreams(simulcastEnabled, rtxEnabled, mLine) {
9225
+ var _a;
9204
9226
  mLine.rids = [];
9205
9227
  mLine.simulcast = undefined;
9206
- mLine.ssrcs = [];
9207
- mLine.ssrcGroups = [];
9208
9228
  mLine.extMaps = mLine.extMaps.filter((extMapLine) => !/^urn:ietf:params:rtp-hdrext:sdes:(?:mid|rtp-stream-id|repaired-rtp-stream-id)$/.test(extMapLine.uri));
9209
- if (this.streamIds.length === 0) {
9210
- const numStreams = simulcastEnabled ? 3 : 1;
9211
- [...Array(numStreams).keys()].forEach(() => {
9212
- const newStreamId = {
9213
- ssrc: generateSsrc(),
9214
- };
9215
- if (rtxEnabled) {
9216
- newStreamId.rtxSsrc = generateSsrc();
9229
+ const numStreams = simulcastEnabled ? 3 : 1;
9230
+ if (!this.streamIds.length) {
9231
+ if (mLine.ssrcs.length) {
9232
+ const ssrcs = [...new Set(mLine.ssrcs.map((ssrcLine) => ssrcLine.ssrcId))];
9233
+ mLine.ssrcGroups.forEach((sg) => {
9234
+ if (!sg.ssrcs.every((ssrc) => ssrcs.includes(ssrc))) {
9235
+ throw new Error('SSRC present in SSRC groups is missing from SSRC lines');
9236
+ }
9237
+ });
9238
+ const rtxSsrcGroups = mLine.ssrcGroups.filter((sg) => sg.semantics === 'FID');
9239
+ if (rtxSsrcGroups.length && rtxSsrcGroups.length !== numStreams) {
9240
+ throw new Error(`Expect ${numStreams} RTX SSRC groups, got ${rtxSsrcGroups.length}`);
9217
9241
  }
9218
- this.streamIds.push(newStreamId);
9219
- });
9242
+ rtxSsrcGroups.forEach((sg) => {
9243
+ this.streamIds.push({
9244
+ ssrc: sg.ssrcs[0],
9245
+ rtxSsrc: sg.ssrcs[1],
9246
+ });
9247
+ });
9248
+ const simulcastSsrcs = (_a = mLine.ssrcGroups.find((sg) => sg.semantics === 'SIM')) === null || _a === void 0 ? void 0 : _a.ssrcs;
9249
+ if (simulcastSsrcs) {
9250
+ if (simulcastSsrcs.length !== numStreams ||
9251
+ !this.streamIds.every((streamId) => simulcastSsrcs.includes(streamId.ssrc))) {
9252
+ throw new Error('SSRCs in simulcast SSRC group do not match primary SSRCs in RTX SSRC groups');
9253
+ }
9254
+ this.streamIds.sort((a, b) => simulcastSsrcs.indexOf(a.ssrc) - simulcastSsrcs.indexOf(b.ssrc));
9255
+ }
9256
+ else if (rtxSsrcGroups.length > 1) {
9257
+ throw new Error('Multiple RTX SSRC groups but no simulcast SSRC group found');
9258
+ }
9259
+ if (!this.streamIds.length) {
9260
+ this.streamIds.push({ ssrc: ssrcs[0] });
9261
+ }
9262
+ }
9263
+ else {
9264
+ [...Array(numStreams).keys()].forEach(() => {
9265
+ const newStreamId = {
9266
+ ssrc: generateSsrc(),
9267
+ };
9268
+ if (rtxEnabled) {
9269
+ newStreamId.rtxSsrc = generateSsrc();
9270
+ }
9271
+ this.streamIds.push(newStreamId);
9272
+ });
9273
+ }
9220
9274
  }
9275
+ mLine.ssrcs = [];
9276
+ mLine.ssrcGroups = [];
9221
9277
  this.streamIds.forEach((streamId) => {
9222
9278
  const rtpSsrc = streamId.ssrc;
9223
9279
  mLine.addLine(new SsrcLine(rtpSsrc, 'cname', `${rtpSsrc}-cname`));
@@ -9685,6 +9741,15 @@ function toMediaStreamTrackKind(mediaType) {
9685
9741
  ? exports.MediaStreamTrackKind.Video
9686
9742
  : exports.MediaStreamTrackKind.Audio;
9687
9743
  }
9744
+ function webRtcVideoContentHintToJmpVideoContentHint(hint) {
9745
+ if (hint === 'motion') {
9746
+ return 'motion';
9747
+ }
9748
+ if (hint === 'detail') {
9749
+ return 'sharpness';
9750
+ }
9751
+ return undefined;
9752
+ }
9688
9753
  function toMediaFamily(kind) {
9689
9754
  if (kind === exports.MediaStreamTrackKind.Video) {
9690
9755
  return MediaFamily.Video;
@@ -9933,24 +9998,8 @@ class MultistreamConnection extends EventEmitter {
9933
9998
  const dataChannel = this.pc.createDataChannel('datachannel', {});
9934
9999
  dataChannel.onopen = (e) => {
9935
10000
  logger.info('DataChannel opened: ', e);
9936
- this.sendTransceivers.forEach((transceiver, mediaType) => {
9937
- const track = transceiver.publishedTrack;
9938
- if (track) {
9939
- if (getMediaFamily(mediaType) === MediaFamily.Audio) {
9940
- this.sendSourceIndication(mediaType, +!track.muted);
9941
- }
9942
- else {
9943
- const signaler = this.streamSignalerManager.getEgressStreamSignalerOrThrow(transceiver.mid);
9944
- const state = track.muted ? 'avatar' : 'live';
9945
- const sources = signaler
9946
- .getSenderIds()
9947
- .map((id) => ({ id, state, csi: transceiver.csi }));
9948
- this.sendSourceIndication(mediaType, +!track.muted, sources);
9949
- }
9950
- }
9951
- else {
9952
- this.sendSourceIndication(mediaType, 0);
9953
- }
10001
+ [...this.sendTransceivers.keys()].forEach((mediaType) => {
10002
+ this.maybeSendSourceIndication(mediaType);
9954
10003
  });
9955
10004
  logger.info(`Flushing pending JMP task queue`);
9956
10005
  this.pendingJmpTasks.forEach((t) => t());
@@ -9999,11 +10048,31 @@ class MultistreamConnection extends EventEmitter {
9999
10048
  });
10000
10049
  this.pc.close();
10001
10050
  }
10002
- sendSourceIndication(mediaType, numLiveSources, sources = []) {
10051
+ maybeSendSourceIndication(mediaType) {
10052
+ var _a;
10053
+ const transceiver = this.getSendTransceiverOrThrow(mediaType);
10054
+ const numLiveSources = ((_a = transceiver.publishedTrack) === null || _a === void 0 ? void 0 : _a.muted) === false ? 1 : 0;
10055
+ if (getMediaFamily(mediaType) === MediaFamily.Video) {
10056
+ const sources = this.getVideoSources(mediaType);
10057
+ if (sources === null) {
10058
+ return;
10059
+ }
10060
+ let webRtcVideoContentHint;
10061
+ if (transceiver.publishedTrack instanceof LocalDisplayTrack) {
10062
+ webRtcVideoContentHint = transceiver.publishedTrack.videoContentHint;
10063
+ }
10064
+ this.sendSourceIndication(mediaType, numLiveSources, sources, webRtcVideoContentHintToJmpVideoContentHint(webRtcVideoContentHint));
10065
+ }
10066
+ else {
10067
+ this.sendSourceIndication(mediaType, numLiveSources);
10068
+ }
10069
+ }
10070
+ sendSourceIndication(mediaType, numLiveSources, sources = [], videoContentHint = undefined) {
10003
10071
  var _a;
10004
10072
  const task = () => {
10005
10073
  var _a;
10006
- (_a = this.jmpSessions.get(mediaType)) === null || _a === void 0 ? void 0 : _a.updateSourceIndication(1, numLiveSources, sources);
10074
+ (_a = this.jmpSessions
10075
+ .get(mediaType)) === null || _a === void 0 ? void 0 : _a.updateSourceIndication(1, numLiveSources, sources, videoContentHint);
10007
10076
  };
10008
10077
  if (((_a = this.dataChannel) === null || _a === void 0 ? void 0 : _a.readyState) === 'open') {
10009
10078
  task();
@@ -10048,24 +10117,9 @@ class MultistreamConnection extends EventEmitter {
10048
10117
  });
10049
10118
  }
10050
10119
  addTrackListeners(mediaType, track) {
10051
- const onTrackResolutionChange = () => {
10052
- const sources = this.getVideoSources(mediaType);
10053
- if (sources != null) {
10054
- this.sendSourceIndication(mediaType, 1, sources);
10055
- }
10056
- };
10120
+ const onTrackResolutionChange = () => this.maybeSendSourceIndication(mediaType);
10057
10121
  track.on(LocalTrack.Events.TrackConstraintsChange, onTrackResolutionChange);
10058
- const onTrackMute = (event) => {
10059
- if (getMediaFamily(mediaType) === MediaFamily.Audio) {
10060
- this.sendSourceIndication(mediaType, +!event.trackState.muted);
10061
- }
10062
- else {
10063
- const sources = this.getVideoSources(mediaType);
10064
- if (sources != null) {
10065
- this.sendSourceIndication(mediaType, +!event.trackState.muted, sources);
10066
- }
10067
- }
10068
- };
10122
+ const onTrackMute = () => this.maybeSendSourceIndication(mediaType);
10069
10123
  track.on(LocalTrack.Events.Muted, onTrackMute);
10070
10124
  const onTrackPublish = (event) => {
10071
10125
  if (!event.isPublished) {
@@ -10073,14 +10127,8 @@ class MultistreamConnection extends EventEmitter {
10073
10127
  track.off(LocalTrack.Events.PublishedStateUpdate, onTrackPublish);
10074
10128
  track.off(LocalTrack.Events.TrackConstraintsChange, onTrackResolutionChange);
10075
10129
  }
10076
- if (getMediaFamily(mediaType) === MediaFamily.Audio) {
10077
- this.sendSourceIndication(mediaType, +event.isPublished);
10078
- }
10079
- else {
10080
- const sources = this.getVideoSources(mediaType);
10081
- if (sources != null) {
10082
- this.sendSourceIndication(mediaType, +event.isPublished, sources);
10083
- }
10130
+ if (!track.muted) {
10131
+ this.maybeSendSourceIndication(mediaType);
10084
10132
  }
10085
10133
  };
10086
10134
  track.on(LocalTrack.Events.PublishedStateUpdate, onTrackPublish);