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