@webex/web-client-media-engine 3.10.1 → 3.11.1
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 +117 -35
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +117 -35
- package/dist/esm/index.js.map +1 -1
- package/dist/types/index.d.ts +3 -1
- package/package.json +3 -3
package/dist/cjs/index.js
CHANGED
|
@@ -490,6 +490,7 @@ exports.WebrtcCoreErrorType = void 0;
|
|
|
490
490
|
(function (WebrtcCoreErrorType) {
|
|
491
491
|
WebrtcCoreErrorType["DEVICE_PERMISSION_DENIED"] = "DEVICE_PERMISSION_DENIED";
|
|
492
492
|
WebrtcCoreErrorType["CREATE_STREAM_FAILED"] = "CREATE_STREAM_FAILED";
|
|
493
|
+
WebrtcCoreErrorType["ADD_EFFECT_FAILED"] = "ADD_EFFECT_FAILED";
|
|
493
494
|
})(exports.WebrtcCoreErrorType || (exports.WebrtcCoreErrorType = {}));
|
|
494
495
|
/**
|
|
495
496
|
* Represents a WebRTC core error, which contains error type and error message.
|
|
@@ -1250,11 +1251,12 @@ class _Stream {
|
|
|
1250
1251
|
_a$1$1 = exports.StreamEventNames.MuteStateChange, _b$1 = exports.StreamEventNames.Ended;
|
|
1251
1252
|
const Stream = AddEvents(_Stream);
|
|
1252
1253
|
|
|
1253
|
-
var _a$6, _b;
|
|
1254
|
+
var _a$6, _b, _c;
|
|
1254
1255
|
exports.LocalStreamEventNames = void 0;
|
|
1255
1256
|
(function (LocalStreamEventNames) {
|
|
1256
1257
|
LocalStreamEventNames["ConstraintsChange"] = "constraints-change";
|
|
1257
1258
|
LocalStreamEventNames["OutputTrackChange"] = "output-track-change";
|
|
1259
|
+
LocalStreamEventNames["EffectAdded"] = "effect-added";
|
|
1258
1260
|
})(exports.LocalStreamEventNames || (exports.LocalStreamEventNames = {}));
|
|
1259
1261
|
/**
|
|
1260
1262
|
* A stream which originates on the local device.
|
|
@@ -1269,6 +1271,7 @@ class _LocalStream extends Stream {
|
|
|
1269
1271
|
super(stream);
|
|
1270
1272
|
this[_a$6] = new TypedEvent$1();
|
|
1271
1273
|
this[_b] = new TypedEvent$1();
|
|
1274
|
+
this[_c] = new TypedEvent$1();
|
|
1272
1275
|
this.effects = [];
|
|
1273
1276
|
this.loadingEffects = new Map();
|
|
1274
1277
|
this.inputStream = stream;
|
|
@@ -1360,55 +1363,110 @@ class _LocalStream extends Stream {
|
|
|
1360
1363
|
/**
|
|
1361
1364
|
* Adds an effect to a local stream.
|
|
1362
1365
|
*
|
|
1363
|
-
* @param name - The name of the effect.
|
|
1364
1366
|
* @param effect - The effect to add.
|
|
1365
1367
|
*/
|
|
1366
|
-
addEffect(
|
|
1368
|
+
addEffect(effect) {
|
|
1367
1369
|
return __awaiter$2(this, void 0, void 0, function* () {
|
|
1368
|
-
//
|
|
1369
|
-
this.
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1370
|
+
// Check if the effect has already been added.
|
|
1371
|
+
if (this.effects.some((e) => e.id === effect.id)) {
|
|
1372
|
+
return;
|
|
1373
|
+
}
|
|
1374
|
+
// Load the effect. Because loading is asynchronous, keep track of the loading effects.
|
|
1375
|
+
this.loadingEffects.set(effect.kind, effect);
|
|
1376
|
+
yield effect.load(this.outputTrack);
|
|
1377
|
+
// After loading, check whether or not we still want to use this effect. If another effect of
|
|
1378
|
+
// the same kind was added while this effect was loading, we only want to use the latest effect,
|
|
1379
|
+
// so dispose this one. If the effects list was cleared while this effect was loading, also
|
|
1380
|
+
// dispose it.
|
|
1381
|
+
if (effect !== this.loadingEffects.get(effect.kind)) {
|
|
1373
1382
|
yield effect.dispose();
|
|
1374
|
-
throw new
|
|
1383
|
+
throw new WebrtcCoreError(exports.WebrtcCoreErrorType.ADD_EFFECT_FAILED, `Another effect with kind ${effect.kind} was added while effect ${effect.id} was loading, or the effects list was cleared.`);
|
|
1375
1384
|
}
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
const effectIndex = this.effects.findIndex((e) => e.name === name);
|
|
1385
|
+
this.loadingEffects.delete(effect.kind);
|
|
1386
|
+
/**
|
|
1387
|
+
* Handle when the effect's output track has been changed. This will update the input of the
|
|
1388
|
+
* next effect in the effects list of the output of the stream.
|
|
1389
|
+
*
|
|
1390
|
+
* @param track - The new output track of the effect.
|
|
1391
|
+
*/
|
|
1392
|
+
const handleEffectTrackUpdated = (track) => {
|
|
1393
|
+
var _d;
|
|
1394
|
+
const effectIndex = this.effects.findIndex((e) => e.id === effect.id);
|
|
1387
1395
|
if (effectIndex === this.effects.length - 1) {
|
|
1388
1396
|
this.changeOutputTrack(track);
|
|
1389
1397
|
}
|
|
1398
|
+
else if (effectIndex >= 0) {
|
|
1399
|
+
(_d = this.effects[effectIndex + 1]) === null || _d === void 0 ? void 0 : _d.replaceInputTrack(track);
|
|
1400
|
+
}
|
|
1390
1401
|
else {
|
|
1391
|
-
(
|
|
1402
|
+
logger$3.error(`Effect with ID ${effect.id} not found in effects list.`);
|
|
1392
1403
|
}
|
|
1393
|
-
}
|
|
1404
|
+
};
|
|
1405
|
+
/**
|
|
1406
|
+
* Handle when the effect has been disposed. This will remove all event listeners from the
|
|
1407
|
+
* effect.
|
|
1408
|
+
*/
|
|
1409
|
+
const handleEffectDisposed = () => {
|
|
1410
|
+
effect.off('track-updated', handleEffectTrackUpdated);
|
|
1411
|
+
effect.off('disposed', handleEffectDisposed);
|
|
1412
|
+
};
|
|
1413
|
+
// TODO: using EffectEvent.TrackUpdated or EffectEvent.Disposed will cause the entire
|
|
1414
|
+
// web-media-effects lib to be rebuilt and inflates the size of the webrtc-core build, so
|
|
1415
|
+
// we use type assertion here as a temporary workaround.
|
|
1416
|
+
effect.on('track-updated', handleEffectTrackUpdated);
|
|
1417
|
+
effect.on('disposed', handleEffectDisposed);
|
|
1418
|
+
// Add the effect to the effects list. If an effect of the same kind has already been added,
|
|
1419
|
+
// dispose the existing effect and replace it with the new effect. If the existing effect was
|
|
1420
|
+
// enabled, also enable the new effect.
|
|
1421
|
+
const existingEffectIndex = this.effects.findIndex((e) => e.kind === effect.kind);
|
|
1422
|
+
if (existingEffectIndex >= 0) {
|
|
1423
|
+
const [existingEffect] = this.effects.splice(existingEffectIndex, 1, effect);
|
|
1424
|
+
if (existingEffect.isEnabled) {
|
|
1425
|
+
// If the existing effect is not the first effect in the effects list, then the input of the
|
|
1426
|
+
// new effect should be the output of the previous effect in the effects list. We know the
|
|
1427
|
+
// output track of the previous effect must exist because it must have been loaded (and all
|
|
1428
|
+
// loaded effects have an output track).
|
|
1429
|
+
const inputTrack = existingEffectIndex === 0
|
|
1430
|
+
? this.inputTrack
|
|
1431
|
+
: this.effects[existingEffectIndex - 1].getOutputTrack();
|
|
1432
|
+
yield effect.replaceInputTrack(inputTrack);
|
|
1433
|
+
// Enabling the new effect will trigger the track-updated event, which will handle the new
|
|
1434
|
+
// effect's updated output track.
|
|
1435
|
+
yield effect.enable();
|
|
1436
|
+
}
|
|
1437
|
+
yield existingEffect.dispose();
|
|
1438
|
+
}
|
|
1439
|
+
else {
|
|
1440
|
+
this.effects.push(effect);
|
|
1441
|
+
}
|
|
1442
|
+
// Emit an event with the effect so others can listen to the effect events.
|
|
1443
|
+
this[exports.LocalStreamEventNames.EffectAdded].emit(effect);
|
|
1394
1444
|
});
|
|
1395
1445
|
}
|
|
1396
1446
|
/**
|
|
1397
|
-
* Get an effect from the effects list.
|
|
1447
|
+
* Get an effect from the effects list by ID.
|
|
1398
1448
|
*
|
|
1399
|
-
* @param
|
|
1449
|
+
* @param id - The id of the effect you want to get.
|
|
1400
1450
|
* @returns The effect or undefined.
|
|
1401
1451
|
*/
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1452
|
+
getEffectById(id) {
|
|
1453
|
+
return this.effects.find((effect) => effect.id === id);
|
|
1454
|
+
}
|
|
1455
|
+
/**
|
|
1456
|
+
* Get an effect from the effects list by kind.
|
|
1457
|
+
*
|
|
1458
|
+
* @param kind - The kind of the effect you want to get.
|
|
1459
|
+
* @returns The effect or undefined.
|
|
1460
|
+
*/
|
|
1461
|
+
getEffectByKind(kind) {
|
|
1462
|
+
return this.effects.find((effect) => effect.kind === kind);
|
|
1405
1463
|
}
|
|
1406
1464
|
/**
|
|
1407
1465
|
* Get all the effects from the effects list.
|
|
1408
1466
|
*
|
|
1409
|
-
* @returns A list of
|
|
1467
|
+
* @returns A list of effects.
|
|
1410
1468
|
*/
|
|
1411
|
-
|
|
1469
|
+
getEffects() {
|
|
1412
1470
|
return this.effects;
|
|
1413
1471
|
}
|
|
1414
1472
|
/**
|
|
@@ -1420,13 +1478,13 @@ class _LocalStream extends Stream {
|
|
|
1420
1478
|
// Dispose of any effects currently in use
|
|
1421
1479
|
if (this.effects.length > 0) {
|
|
1422
1480
|
this.changeOutputTrack(this.inputTrack);
|
|
1423
|
-
yield Promise.all(this.effects.map((
|
|
1481
|
+
yield Promise.all(this.effects.map((effect) => effect.dispose()));
|
|
1424
1482
|
this.effects = [];
|
|
1425
1483
|
}
|
|
1426
1484
|
});
|
|
1427
1485
|
}
|
|
1428
1486
|
}
|
|
1429
|
-
_a$6 = exports.LocalStreamEventNames.ConstraintsChange, _b = exports.LocalStreamEventNames.OutputTrackChange;
|
|
1487
|
+
_a$6 = exports.LocalStreamEventNames.ConstraintsChange, _b = exports.LocalStreamEventNames.OutputTrackChange, _c = exports.LocalStreamEventNames.EffectAdded;
|
|
1430
1488
|
const LocalStream = AddEvents(_LocalStream);
|
|
1431
1489
|
|
|
1432
1490
|
/**
|
|
@@ -9038,6 +9096,18 @@ function parse(sdp, grammar = DefaultSdpGrammar) {
|
|
|
9038
9096
|
const parsed = parseToModel(lines);
|
|
9039
9097
|
return parsed;
|
|
9040
9098
|
}
|
|
9099
|
+
|
|
9100
|
+
function disableRtcpFbValue(sdpOrAv, rtcpFbValue) {
|
|
9101
|
+
const mediaDescriptions = sdpOrAv instanceof Sdp ? sdpOrAv.avMedia : [sdpOrAv];
|
|
9102
|
+
mediaDescriptions.forEach((media) => {
|
|
9103
|
+
media.codecs.forEach((codec) => {
|
|
9104
|
+
codec.feedback = codec.feedback.filter((fb) => fb !== rtcpFbValue);
|
|
9105
|
+
});
|
|
9106
|
+
});
|
|
9107
|
+
}
|
|
9108
|
+
function disableTwcc(sdpOrAv) {
|
|
9109
|
+
disableRtcpFbValue(sdpOrAv, 'transport-cc');
|
|
9110
|
+
}
|
|
9041
9111
|
function removeCodec(sdpOrAv, codecName) {
|
|
9042
9112
|
const mediaDescriptions = sdpOrAv instanceof Sdp ? sdpOrAv.avMedia : [sdpOrAv];
|
|
9043
9113
|
mediaDescriptions.forEach((media) => {
|
|
@@ -9379,7 +9449,7 @@ class EgressSdpMunger {
|
|
|
9379
9449
|
reset() {
|
|
9380
9450
|
this.streamIds = [];
|
|
9381
9451
|
}
|
|
9382
|
-
mungeLocalDescription(mediaDescription, simulcastEnabled, rtxEnabled) {
|
|
9452
|
+
mungeLocalDescription(mediaDescription, simulcastEnabled, rtxEnabled, twccDisabled) {
|
|
9383
9453
|
var _a;
|
|
9384
9454
|
retainCodecs(mediaDescription, ['h264', 'opus', 'rtx']);
|
|
9385
9455
|
if (mediaDescription.codecs.size === 0) {
|
|
@@ -9457,6 +9527,9 @@ class EgressSdpMunger {
|
|
|
9457
9527
|
mediaDescription.addLine(new SsrcGroupLine('SIM', this.streamIds.map((streamId) => streamId.ssrc)));
|
|
9458
9528
|
}
|
|
9459
9529
|
applyFormatParameters(mediaDescription, this.customCodecParameters);
|
|
9530
|
+
if (twccDisabled) {
|
|
9531
|
+
disableTwcc(mediaDescription);
|
|
9532
|
+
}
|
|
9460
9533
|
}
|
|
9461
9534
|
mungeLocalDescriptionForRemoteServer(mediaDescription, mediaContent, csi) {
|
|
9462
9535
|
injectContentType(mediaDescription, mediaContent);
|
|
@@ -9983,13 +10056,16 @@ class IngressSdpMunger {
|
|
|
9983
10056
|
getReceiverId() {
|
|
9984
10057
|
return Object.assign({ ssrc: this.ssrc }, (this.rtxSsrc ? { rtxSsrc: this.rtxSsrc } : {}));
|
|
9985
10058
|
}
|
|
9986
|
-
mungeLocalDescription(mediaDescription) {
|
|
10059
|
+
mungeLocalDescription(mediaDescription, twccDisabled) {
|
|
9987
10060
|
retainCodecs(mediaDescription, ['h264', 'opus', 'rtx']);
|
|
9988
10061
|
if (mediaDescription.codecs.size === 0) {
|
|
9989
10062
|
logErrorAndThrow(exports.WcmeErrorType.SDP_MUNGE_MISSING_CODECS, `No codecs present in m-line with MID ${mediaDescription.mid} after filtering.`);
|
|
9990
10063
|
}
|
|
9991
10064
|
mediaDescription.bandwidth = new BandwidthLine('TIAS', 20000000);
|
|
9992
10065
|
removeMidRidExtensions(mediaDescription);
|
|
10066
|
+
if (twccDisabled) {
|
|
10067
|
+
disableTwcc(mediaDescription);
|
|
10068
|
+
}
|
|
9993
10069
|
}
|
|
9994
10070
|
mungeRemoteDescription(mediaDescription) {
|
|
9995
10071
|
if (!mediaDescription.ssrcs.length) {
|
|
@@ -10139,6 +10215,7 @@ ReceiveSlot.Events = exports.ReceiveSlotEvents;
|
|
|
10139
10215
|
|
|
10140
10216
|
class Transceiver {
|
|
10141
10217
|
constructor(rtcRtpTransceiver, mid) {
|
|
10218
|
+
this.twccDisabled = false;
|
|
10142
10219
|
this._rtcRtpTransceiver = rtcRtpTransceiver;
|
|
10143
10220
|
this.mid = mid;
|
|
10144
10221
|
}
|
|
@@ -10182,7 +10259,7 @@ class ReceiveOnlyTransceiver extends Transceiver {
|
|
|
10182
10259
|
return this.receiver.getStats();
|
|
10183
10260
|
}
|
|
10184
10261
|
mungeLocalDescription(mediaDescription) {
|
|
10185
|
-
this.munger.mungeLocalDescription(mediaDescription);
|
|
10262
|
+
this.munger.mungeLocalDescription(mediaDescription, this.twccDisabled);
|
|
10186
10263
|
}
|
|
10187
10264
|
mungeRemoteDescription(mediaDescription) {
|
|
10188
10265
|
this.munger.mungeRemoteDescription(mediaDescription);
|
|
@@ -14045,7 +14122,7 @@ class SendOnlyTransceiver extends Transceiver {
|
|
|
14045
14122
|
return params.encodings.length > 1;
|
|
14046
14123
|
}
|
|
14047
14124
|
mungeLocalDescription(mediaDescription) {
|
|
14048
|
-
this.munger.mungeLocalDescription(mediaDescription, this.isSimulcastEnabled(), this.rtxEnabled);
|
|
14125
|
+
this.munger.mungeLocalDescription(mediaDescription, this.isSimulcastEnabled(), this.rtxEnabled, this.twccDisabled);
|
|
14049
14126
|
}
|
|
14050
14127
|
mungeLocalDescriptionForRemoteServer(mediaDescription) {
|
|
14051
14128
|
this.munger.mungeLocalDescriptionForRemoteServer(mediaDescription, getMediaContent(this.mediaType), this.csi);
|
|
@@ -14231,6 +14308,7 @@ const defaultMultistreamConnectionOptions = {
|
|
|
14231
14308
|
bundlePolicy: 'max-compat',
|
|
14232
14309
|
iceServers: undefined,
|
|
14233
14310
|
disableContentSimulcast: true,
|
|
14311
|
+
disableAudioTwcc: true,
|
|
14234
14312
|
};
|
|
14235
14313
|
class MultistreamConnection extends EventEmitter$2 {
|
|
14236
14314
|
constructor(userOptions = {}) {
|
|
@@ -14308,6 +14386,8 @@ class MultistreamConnection extends EventEmitter$2 {
|
|
|
14308
14386
|
'max-fs': `${defaultMaxVideoEncodeFrameSize}`,
|
|
14309
14387
|
});
|
|
14310
14388
|
}
|
|
14389
|
+
transceiver.twccDisabled =
|
|
14390
|
+
getMediaFamily(mediaType) === exports.MediaFamily.Audio ? this.options.disableAudioTwcc : false;
|
|
14311
14391
|
transceiver.active = false;
|
|
14312
14392
|
transceiver.streamMuteStateChange.on(() => {
|
|
14313
14393
|
this.sendSourceAdvertisement(mediaType);
|
|
@@ -14568,6 +14648,8 @@ class MultistreamConnection extends EventEmitter$2 {
|
|
|
14568
14648
|
const transceiverMid = this.midPredictor.getNextMid(mediaType);
|
|
14569
14649
|
const munger = new IngressSdpMunger();
|
|
14570
14650
|
const recvOnlyTransceiver = new ReceiveOnlyTransceiver(rtcRtpTransceiver, transceiverMid, munger);
|
|
14651
|
+
recvOnlyTransceiver.twccDisabled =
|
|
14652
|
+
getMediaFamily(mediaType) === exports.MediaFamily.Audio ? this.options.disableAudioTwcc : false;
|
|
14571
14653
|
this.recvTransceivers.set(mediaType, [
|
|
14572
14654
|
...(this.recvTransceivers.get(mediaType) || []),
|
|
14573
14655
|
recvOnlyTransceiver,
|