@webex/web-client-media-engine 2.1.2 → 2.1.4
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 +332 -310
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +332 -310
- package/dist/esm/index.js.map +1 -1
- package/dist/types/index.d.ts +34 -10
- package/package.json +1 -1
package/dist/cjs/index.js
CHANGED
|
@@ -8859,6 +8859,30 @@ function eventTargetAgnosticAddListener(emitter, name, listener, flags) {
|
|
|
8859
8859
|
class EventEmitter extends events.exports.EventEmitter {
|
|
8860
8860
|
}
|
|
8861
8861
|
|
|
8862
|
+
class MidPredictor {
|
|
8863
|
+
constructor() {
|
|
8864
|
+
this.currentMid = 0;
|
|
8865
|
+
this.midMap = new Map();
|
|
8866
|
+
}
|
|
8867
|
+
getNextMid(mediaType) {
|
|
8868
|
+
const mid = this.currentMid++;
|
|
8869
|
+
const mids = this.midMap.get(mediaType) || [];
|
|
8870
|
+
mids.push(`${mid}`);
|
|
8871
|
+
this.midMap.set(mediaType, mids);
|
|
8872
|
+
return `${mid}`;
|
|
8873
|
+
}
|
|
8874
|
+
allocateMidForDatachannel() {
|
|
8875
|
+
this.currentMid += 1;
|
|
8876
|
+
}
|
|
8877
|
+
reset() {
|
|
8878
|
+
this.midMap = new Map();
|
|
8879
|
+
this.currentMid = 0;
|
|
8880
|
+
}
|
|
8881
|
+
getMidMap() {
|
|
8882
|
+
return this.midMap;
|
|
8883
|
+
}
|
|
8884
|
+
}
|
|
8885
|
+
|
|
8862
8886
|
var OveruseState;
|
|
8863
8887
|
(function (OveruseState) {
|
|
8864
8888
|
OveruseState[OveruseState["NOT_OVERUSED"] = 0] = "NOT_OVERUSED";
|
|
@@ -8966,8 +8990,9 @@ class ReceiveSlot extends EventEmitter {
|
|
|
8966
8990
|
ReceiveSlot.Events = exports.ReceiveSlotEvents;
|
|
8967
8991
|
|
|
8968
8992
|
class Transceiver {
|
|
8969
|
-
constructor(rtcRtpTransceiver) {
|
|
8993
|
+
constructor(rtcRtpTransceiver, mid) {
|
|
8970
8994
|
this._rtcRtpTransceiver = rtcRtpTransceiver;
|
|
8995
|
+
this.mid = mid;
|
|
8971
8996
|
}
|
|
8972
8997
|
replaceTransceiver(newRtcRtpTransceiver) {
|
|
8973
8998
|
this._rtcRtpTransceiver = newRtcRtpTransceiver;
|
|
@@ -8978,22 +9003,20 @@ class Transceiver {
|
|
|
8978
9003
|
get sender() {
|
|
8979
9004
|
return this._rtcRtpTransceiver.sender;
|
|
8980
9005
|
}
|
|
8981
|
-
get mid() {
|
|
8982
|
-
return this._rtcRtpTransceiver.mid;
|
|
8983
|
-
}
|
|
8984
9006
|
close() {
|
|
8985
9007
|
this._rtcRtpTransceiver.stop();
|
|
8986
9008
|
}
|
|
8987
9009
|
}
|
|
8988
9010
|
|
|
8989
9011
|
class ReceiveOnlyTransceiver extends Transceiver {
|
|
8990
|
-
constructor(rtcRtpTransceiver,
|
|
8991
|
-
super(rtcRtpTransceiver);
|
|
9012
|
+
constructor(rtcRtpTransceiver, mid, signaler) {
|
|
9013
|
+
super(rtcRtpTransceiver, mid);
|
|
9014
|
+
this.streamSignaler = signaler;
|
|
8992
9015
|
this._receiveSlot = new ReceiveSlot(() => {
|
|
8993
9016
|
if (!this._rtcRtpTransceiver.mid) {
|
|
8994
9017
|
return null;
|
|
8995
9018
|
}
|
|
8996
|
-
return
|
|
9019
|
+
return this.streamSignaler.getReceiverId();
|
|
8997
9020
|
}, this._rtcRtpTransceiver.receiver.track);
|
|
8998
9021
|
}
|
|
8999
9022
|
replaceTransceiver(newRtcRtpTransceiver) {
|
|
@@ -9010,62 +9033,21 @@ class ReceiveOnlyTransceiver extends Transceiver {
|
|
|
9010
9033
|
getStats() {
|
|
9011
9034
|
return this.receiver.getStats();
|
|
9012
9035
|
}
|
|
9036
|
+
signalLocalStreams(mLine) {
|
|
9037
|
+
this.streamSignaler.signalLocalStreams(mLine);
|
|
9038
|
+
}
|
|
9039
|
+
signalRemoteStreams(mLine) {
|
|
9040
|
+
this.streamSignaler.signalRemoteStreams(mLine);
|
|
9041
|
+
}
|
|
9042
|
+
get receiverId() {
|
|
9043
|
+
return this.streamSignaler.getReceiverId();
|
|
9044
|
+
}
|
|
9045
|
+
resetStreamSignaler() {
|
|
9046
|
+
this.streamSignaler.reset();
|
|
9047
|
+
}
|
|
9013
9048
|
}
|
|
9014
9049
|
ReceiveOnlyTransceiver.rid = '1';
|
|
9015
9050
|
|
|
9016
|
-
function deepCopy(source) {
|
|
9017
|
-
return Array.isArray(source)
|
|
9018
|
-
? source.map((item) => deepCopy(item))
|
|
9019
|
-
: source instanceof Map
|
|
9020
|
-
? new Map(source)
|
|
9021
|
-
: source instanceof Date
|
|
9022
|
-
? new Date(source.getTime())
|
|
9023
|
-
: source && typeof source === 'object'
|
|
9024
|
-
? Object.getOwnPropertyNames(source).reduce((o, prop) => {
|
|
9025
|
-
Object.defineProperty(o, prop, Object.getOwnPropertyDescriptor(source, prop));
|
|
9026
|
-
o[prop] = deepCopy(source[prop]);
|
|
9027
|
-
return o;
|
|
9028
|
-
}, Object.create(Object.getPrototypeOf(source)))
|
|
9029
|
-
: source;
|
|
9030
|
-
}
|
|
9031
|
-
|
|
9032
|
-
function matchMlinesInAnswer(parsedOffer, parsedAnswer, streamSignalerManager) {
|
|
9033
|
-
parsedAnswer.session.groups = parsedOffer.session.groups;
|
|
9034
|
-
parsedAnswer.media = parsedOffer.media.map((offerMline) => {
|
|
9035
|
-
if (!offerMline.mid) {
|
|
9036
|
-
throw new Error(`Offer mline is missing MID`);
|
|
9037
|
-
}
|
|
9038
|
-
const answerMline = parsedAnswer.media.find((m) => m.mid === offerMline.mid);
|
|
9039
|
-
if (answerMline) {
|
|
9040
|
-
if (answerMline instanceof AvMediaDescription) {
|
|
9041
|
-
[...answerMline.codecs.values()].forEach((ci) => {
|
|
9042
|
-
ci.fmtParams.set('x-google-start-bitrate', '60000');
|
|
9043
|
-
});
|
|
9044
|
-
}
|
|
9045
|
-
return answerMline;
|
|
9046
|
-
}
|
|
9047
|
-
if (!(offerMline instanceof AvMediaDescription)) {
|
|
9048
|
-
throw new Error(`Answer is missing a non-media mline: ${offerMline.mid}`);
|
|
9049
|
-
}
|
|
9050
|
-
const startingMline = parsedAnswer.avMedia.find((m) => m.type === offerMline.type);
|
|
9051
|
-
if (!startingMline) {
|
|
9052
|
-
throw new Error(`Answer has no mline of type ${offerMline.type}, can't generate synthetic answer mline for mid ${offerMline.mid}`);
|
|
9053
|
-
}
|
|
9054
|
-
const fakeCorrespondingMline = deepCopy(startingMline);
|
|
9055
|
-
fakeCorrespondingMline.mid = offerMline.mid;
|
|
9056
|
-
fakeCorrespondingMline.simulcast = undefined;
|
|
9057
|
-
if (offerMline.direction === 'sendrecv' || offerMline.direction === 'sendonly') {
|
|
9058
|
-
fakeCorrespondingMline.direction = 'recvonly';
|
|
9059
|
-
}
|
|
9060
|
-
if (offerMline.direction === 'recvonly') {
|
|
9061
|
-
fakeCorrespondingMline.direction = 'sendonly';
|
|
9062
|
-
const ingressSignaler = streamSignalerManager.getIngressStreamSignalerOrThrow(offerMline.mid);
|
|
9063
|
-
ingressSignaler.signalRemoteStreams(fakeCorrespondingMline);
|
|
9064
|
-
}
|
|
9065
|
-
return fakeCorrespondingMline;
|
|
9066
|
-
});
|
|
9067
|
-
}
|
|
9068
|
-
|
|
9069
9051
|
class JmpLine extends Line {
|
|
9070
9052
|
constructor(versions) {
|
|
9071
9053
|
super();
|
|
@@ -9239,9 +9221,6 @@ function injectDummyCandidates(parsedSdp) {
|
|
|
9239
9221
|
}
|
|
9240
9222
|
});
|
|
9241
9223
|
}
|
|
9242
|
-
function hasSimulcast(av) {
|
|
9243
|
-
return !!av.simulcast || av.ssrcGroups.map((sg) => sg.semantics).some((sem) => sem === 'SIM');
|
|
9244
|
-
}
|
|
9245
9224
|
function addVlaExtension(mLine) {
|
|
9246
9225
|
const vlaUri = 'http://www.webrtc.org/experiments/rtp-hdrext/video-layers-allocation00';
|
|
9247
9226
|
if (mLine.extMaps.findIndex((extMapLine) => extMapLine.uri === vlaUri) === -1) {
|
|
@@ -9251,13 +9230,147 @@ function addVlaExtension(mLine) {
|
|
|
9251
9230
|
}
|
|
9252
9231
|
}
|
|
9253
9232
|
|
|
9233
|
+
const simulcastMaxFrameSizes = {
|
|
9234
|
+
0: '240',
|
|
9235
|
+
1: '2304',
|
|
9236
|
+
2: '8160',
|
|
9237
|
+
};
|
|
9238
|
+
|
|
9239
|
+
class RidIngressStreamSignaler {
|
|
9240
|
+
constructor(mid) {
|
|
9241
|
+
this.mid = mid;
|
|
9242
|
+
}
|
|
9243
|
+
getReceiverId() {
|
|
9244
|
+
return {
|
|
9245
|
+
mid: this.mid,
|
|
9246
|
+
rid: '1',
|
|
9247
|
+
};
|
|
9248
|
+
}
|
|
9249
|
+
signalLocalStreams(mLine) {
|
|
9250
|
+
}
|
|
9251
|
+
signalRemoteStreams(mLine) {
|
|
9252
|
+
}
|
|
9253
|
+
reset() {
|
|
9254
|
+
}
|
|
9255
|
+
}
|
|
9256
|
+
class RidEgressStreamSignaler {
|
|
9257
|
+
constructor(mid) {
|
|
9258
|
+
this.streamIds = [];
|
|
9259
|
+
this.mid = mid;
|
|
9260
|
+
}
|
|
9261
|
+
signalStreams(simulcastEnabled, _rtxEnabled, mLine) {
|
|
9262
|
+
mLine.ssrcGroups = [];
|
|
9263
|
+
if (this.streamIds.length === 0) {
|
|
9264
|
+
if (simulcastEnabled) {
|
|
9265
|
+
this.streamIds = [
|
|
9266
|
+
{
|
|
9267
|
+
mid: this.mid,
|
|
9268
|
+
rid: 'low',
|
|
9269
|
+
},
|
|
9270
|
+
{
|
|
9271
|
+
mid: this.mid,
|
|
9272
|
+
rid: 'medium',
|
|
9273
|
+
},
|
|
9274
|
+
{
|
|
9275
|
+
mid: this.mid,
|
|
9276
|
+
rid: 'high',
|
|
9277
|
+
},
|
|
9278
|
+
];
|
|
9279
|
+
}
|
|
9280
|
+
else {
|
|
9281
|
+
this.streamIds = [
|
|
9282
|
+
{
|
|
9283
|
+
mid: this.mid,
|
|
9284
|
+
},
|
|
9285
|
+
];
|
|
9286
|
+
}
|
|
9287
|
+
}
|
|
9288
|
+
if (simulcastEnabled) {
|
|
9289
|
+
mLine.rids = this.streamIds.map((streamId, index) => new RidLine(streamId.rid, 'send', `max-fs=${simulcastMaxFrameSizes[index]}`));
|
|
9290
|
+
mLine.simulcast = new SimulcastLine(SimulcastLayerList.fromString('low;medium;high'), new SimulcastLayerList());
|
|
9291
|
+
addVlaExtension(mLine);
|
|
9292
|
+
}
|
|
9293
|
+
}
|
|
9294
|
+
getSenderIds() {
|
|
9295
|
+
return this.streamIds;
|
|
9296
|
+
}
|
|
9297
|
+
reset() {
|
|
9298
|
+
this.streamIds = [];
|
|
9299
|
+
}
|
|
9300
|
+
getEncodingIndexForStreamId(streamId) {
|
|
9301
|
+
return this.streamIds.findIndex((currStreamId) => compareStreamIds(currStreamId, streamId));
|
|
9302
|
+
}
|
|
9303
|
+
setCodecParameters(parameters) {
|
|
9304
|
+
}
|
|
9305
|
+
deleteCodecParameters(parameters) {
|
|
9306
|
+
}
|
|
9307
|
+
}
|
|
9308
|
+
|
|
9309
|
+
function deepCopy(source) {
|
|
9310
|
+
return Array.isArray(source)
|
|
9311
|
+
? source.map((item) => deepCopy(item))
|
|
9312
|
+
: source instanceof Map
|
|
9313
|
+
? new Map(source)
|
|
9314
|
+
: source instanceof Date
|
|
9315
|
+
? new Date(source.getTime())
|
|
9316
|
+
: source && typeof source === 'object'
|
|
9317
|
+
? Object.getOwnPropertyNames(source).reduce((o, prop) => {
|
|
9318
|
+
Object.defineProperty(o, prop, Object.getOwnPropertyDescriptor(source, prop));
|
|
9319
|
+
o[prop] = deepCopy(source[prop]);
|
|
9320
|
+
return o;
|
|
9321
|
+
}, Object.create(Object.getPrototypeOf(source)))
|
|
9322
|
+
: source;
|
|
9323
|
+
}
|
|
9324
|
+
|
|
9325
|
+
function matchMlinesInAnswer(parsedOffer, parsedAnswer, recvTransceiversByMid) {
|
|
9326
|
+
parsedAnswer.session.groups = parsedOffer.session.groups;
|
|
9327
|
+
parsedAnswer.media = parsedOffer.media.map((offerMline) => {
|
|
9328
|
+
if (!offerMline.mid) {
|
|
9329
|
+
throw new Error(`Offer mline is missing MID`);
|
|
9330
|
+
}
|
|
9331
|
+
const answerMline = parsedAnswer.media.find((m) => m.mid === offerMline.mid);
|
|
9332
|
+
if (answerMline) {
|
|
9333
|
+
if (answerMline instanceof AvMediaDescription) {
|
|
9334
|
+
[...answerMline.codecs.values()].forEach((ci) => {
|
|
9335
|
+
ci.fmtParams.set('x-google-start-bitrate', '60000');
|
|
9336
|
+
});
|
|
9337
|
+
}
|
|
9338
|
+
return answerMline;
|
|
9339
|
+
}
|
|
9340
|
+
if (!(offerMline instanceof AvMediaDescription)) {
|
|
9341
|
+
throw new Error(`Answer is missing a non-media mline: ${offerMline.mid}`);
|
|
9342
|
+
}
|
|
9343
|
+
const startingMline = parsedAnswer.avMedia.find((m) => m.type === offerMline.type);
|
|
9344
|
+
if (!startingMline) {
|
|
9345
|
+
throw new Error(`Answer has no mline of type ${offerMline.type}, can't generate synthetic answer mline for mid ${offerMline.mid}`);
|
|
9346
|
+
}
|
|
9347
|
+
const fakeCorrespondingMline = deepCopy(startingMline);
|
|
9348
|
+
fakeCorrespondingMline.mid = offerMline.mid;
|
|
9349
|
+
fakeCorrespondingMline.simulcast = undefined;
|
|
9350
|
+
if (offerMline.direction === 'sendrecv' || offerMline.direction === 'sendonly') {
|
|
9351
|
+
fakeCorrespondingMline.direction = 'recvonly';
|
|
9352
|
+
}
|
|
9353
|
+
if (offerMline.direction === 'recvonly') {
|
|
9354
|
+
fakeCorrespondingMline.direction = 'sendonly';
|
|
9355
|
+
const recvTransceiver = recvTransceiversByMid.get(offerMline.mid);
|
|
9356
|
+
if (!recvTransceiver) {
|
|
9357
|
+
throw new Error(`Can't find recv transceiver for mid ${offerMline.mid}`);
|
|
9358
|
+
}
|
|
9359
|
+
recvTransceiver.signalRemoteStreams(fakeCorrespondingMline);
|
|
9360
|
+
}
|
|
9361
|
+
return fakeCorrespondingMline;
|
|
9362
|
+
});
|
|
9363
|
+
}
|
|
9364
|
+
|
|
9254
9365
|
class SendOnlyTransceiver extends Transceiver {
|
|
9255
|
-
constructor(rtcpRtpTransceiver, csi) {
|
|
9256
|
-
super(rtcpRtpTransceiver);
|
|
9366
|
+
constructor(rtcpRtpTransceiver, mid, csi, signaler) {
|
|
9367
|
+
super(rtcpRtpTransceiver, mid);
|
|
9368
|
+
this.rtxEnabled = false;
|
|
9257
9369
|
this.requested = false;
|
|
9258
9370
|
this.csi = csi;
|
|
9259
9371
|
this.direction = 'sendrecv';
|
|
9260
9372
|
this.handleTrackChange = this.handleTrackChange.bind(this);
|
|
9373
|
+
this.streamSignaler = signaler;
|
|
9261
9374
|
}
|
|
9262
9375
|
handleTrackChange() {
|
|
9263
9376
|
var _a;
|
|
@@ -9319,12 +9432,17 @@ class SendOnlyTransceiver extends Transceiver {
|
|
|
9319
9432
|
}
|
|
9320
9433
|
updateSendParameters(requestedIdEncodingParamsMap) {
|
|
9321
9434
|
return __awaiter(this, void 0, void 0, function* () {
|
|
9435
|
+
if (!this.publishedTrack)
|
|
9436
|
+
return;
|
|
9437
|
+
this.setTrackRequested(requestedIdEncodingParamsMap.size > 0);
|
|
9322
9438
|
const sendParameters = this.sender.getParameters();
|
|
9323
9439
|
sendParameters.encodings.forEach((encoding, index) => {
|
|
9440
|
+
var _a, _b;
|
|
9324
9441
|
const encodingParams = requestedIdEncodingParamsMap.get(index);
|
|
9325
9442
|
encoding.active = !!encodingParams;
|
|
9326
9443
|
if (encodingParams) {
|
|
9327
|
-
const { maxPayloadBitsPerSecond,
|
|
9444
|
+
const { maxPayloadBitsPerSecond, maxFs, maxWidth, maxHeight } = encodingParams;
|
|
9445
|
+
const scaleDownRatio = getScaleDownRatio((_a = this.publishedTrack) === null || _a === void 0 ? void 0 : _a.getSettings().width, (_b = this.publishedTrack) === null || _b === void 0 ? void 0 : _b.getSettings().height, maxFs, maxWidth, maxHeight);
|
|
9328
9446
|
if (maxPayloadBitsPerSecond !== undefined && maxPayloadBitsPerSecond >= 0) {
|
|
9329
9447
|
encoding.maxBitrate = maxPayloadBitsPerSecond;
|
|
9330
9448
|
}
|
|
@@ -9336,88 +9454,27 @@ class SendOnlyTransceiver extends Transceiver {
|
|
|
9336
9454
|
yield this.sender.setParameters(sendParameters);
|
|
9337
9455
|
});
|
|
9338
9456
|
}
|
|
9339
|
-
|
|
9340
|
-
|
|
9341
|
-
|
|
9342
|
-
constructor(statsGetter, statsPreprocessor = () => __awaiter(this, void 0, void 0, function* () { })) {
|
|
9343
|
-
this.statsGetter = statsGetter;
|
|
9344
|
-
this.statsPreProcessor = statsPreprocessor;
|
|
9457
|
+
isSimulcastEnabled() {
|
|
9458
|
+
const params = this.sender.getParameters();
|
|
9459
|
+
return params.encodings.length > 1;
|
|
9345
9460
|
}
|
|
9346
|
-
|
|
9347
|
-
|
|
9348
|
-
const statsReport = yield this.statsGetter();
|
|
9349
|
-
const statsMap = new Map();
|
|
9350
|
-
statsReport.forEach((stats, key) => statsMap.set(key, stats));
|
|
9351
|
-
yield this.statsPreProcessor(statsMap);
|
|
9352
|
-
return statsMap;
|
|
9353
|
-
});
|
|
9461
|
+
signalStreams(mLine) {
|
|
9462
|
+
this.streamSignaler.signalStreams(this.isSimulcastEnabled(), this.rtxEnabled, mLine);
|
|
9354
9463
|
}
|
|
9355
|
-
|
|
9356
|
-
|
|
9357
|
-
const simulcastMaxFrameSizes = {
|
|
9358
|
-
0: '240',
|
|
9359
|
-
1: '2304',
|
|
9360
|
-
2: '8160',
|
|
9361
|
-
};
|
|
9362
|
-
|
|
9363
|
-
class RidIngressStreamSignaler {
|
|
9364
|
-
constructor(mid) {
|
|
9365
|
-
this.mid = mid;
|
|
9464
|
+
get senderIds() {
|
|
9465
|
+
return this.streamSignaler.getSenderIds();
|
|
9366
9466
|
}
|
|
9367
|
-
|
|
9368
|
-
return
|
|
9369
|
-
mid: this.mid,
|
|
9370
|
-
rid: '1',
|
|
9371
|
-
};
|
|
9467
|
+
getEncodingIndexForStreamId(id) {
|
|
9468
|
+
return this.streamSignaler.getEncodingIndexForStreamId(id);
|
|
9372
9469
|
}
|
|
9373
|
-
|
|
9470
|
+
resetStreamSignaler() {
|
|
9471
|
+
this.streamSignaler.reset();
|
|
9374
9472
|
}
|
|
9375
|
-
|
|
9473
|
+
setCodecParameters(parameters) {
|
|
9474
|
+
this.streamSignaler.setCodecParameters(parameters);
|
|
9376
9475
|
}
|
|
9377
|
-
|
|
9378
|
-
|
|
9379
|
-
constructor(mid) {
|
|
9380
|
-
this.streamIds = [];
|
|
9381
|
-
this.mid = mid;
|
|
9382
|
-
}
|
|
9383
|
-
signalStreams(simulcastEnabled, _rtxEnabled, mLine) {
|
|
9384
|
-
mLine.ssrcGroups = [];
|
|
9385
|
-
if (this.streamIds.length === 0) {
|
|
9386
|
-
if (simulcastEnabled) {
|
|
9387
|
-
this.streamIds = [
|
|
9388
|
-
{
|
|
9389
|
-
mid: this.mid,
|
|
9390
|
-
rid: 'low',
|
|
9391
|
-
},
|
|
9392
|
-
{
|
|
9393
|
-
mid: this.mid,
|
|
9394
|
-
rid: 'medium',
|
|
9395
|
-
},
|
|
9396
|
-
{
|
|
9397
|
-
mid: this.mid,
|
|
9398
|
-
rid: 'high',
|
|
9399
|
-
},
|
|
9400
|
-
];
|
|
9401
|
-
}
|
|
9402
|
-
else {
|
|
9403
|
-
this.streamIds = [
|
|
9404
|
-
{
|
|
9405
|
-
mid: this.mid,
|
|
9406
|
-
},
|
|
9407
|
-
];
|
|
9408
|
-
}
|
|
9409
|
-
}
|
|
9410
|
-
if (simulcastEnabled) {
|
|
9411
|
-
mLine.rids = this.streamIds.map((streamId, index) => new RidLine(streamId.rid, 'send', `max-fs=${simulcastMaxFrameSizes[index]}`));
|
|
9412
|
-
mLine.simulcast = new SimulcastLine(SimulcastLayerList.fromString('low;medium;high'), new SimulcastLayerList());
|
|
9413
|
-
addVlaExtension(mLine);
|
|
9414
|
-
}
|
|
9415
|
-
}
|
|
9416
|
-
getSenderIds() {
|
|
9417
|
-
return this.streamIds;
|
|
9418
|
-
}
|
|
9419
|
-
getEncodingIndexForStreamId(streamId) {
|
|
9420
|
-
return this.streamIds.findIndex((currStreamId) => compareStreamIds(currStreamId, streamId));
|
|
9476
|
+
deleteCodecParameters(parameters) {
|
|
9477
|
+
this.streamSignaler.deleteCodecParameters(parameters);
|
|
9421
9478
|
}
|
|
9422
9479
|
}
|
|
9423
9480
|
|
|
@@ -9425,6 +9482,20 @@ function generateSsrc() {
|
|
|
9425
9482
|
return Math.floor(Math.random() * 0xffffffff) + 1;
|
|
9426
9483
|
}
|
|
9427
9484
|
|
|
9485
|
+
function setCustomCodecParams(mLine, paramsMap) {
|
|
9486
|
+
paramsMap.forEach((value, param) => {
|
|
9487
|
+
[...mLine.codecs.values()]
|
|
9488
|
+
.filter((ci) => ci.name === 'H264' || ci.name === 'opus')
|
|
9489
|
+
.forEach((ci) => {
|
|
9490
|
+
if (value === null) {
|
|
9491
|
+
ci.fmtParams.delete(param);
|
|
9492
|
+
}
|
|
9493
|
+
else {
|
|
9494
|
+
ci.fmtParams.set(param, `${value}`);
|
|
9495
|
+
}
|
|
9496
|
+
});
|
|
9497
|
+
});
|
|
9498
|
+
}
|
|
9428
9499
|
class SsrcIngressStreamSignaler {
|
|
9429
9500
|
constructor() {
|
|
9430
9501
|
this.ssrc = generateSsrc();
|
|
@@ -9447,10 +9518,17 @@ class SsrcIngressStreamSignaler {
|
|
|
9447
9518
|
mLine.addLine(new SsrcGroupLine('FID', [this.ssrc, this.rtxSsrc]));
|
|
9448
9519
|
}
|
|
9449
9520
|
}
|
|
9521
|
+
reset() {
|
|
9522
|
+
this.ssrc = generateSsrc();
|
|
9523
|
+
}
|
|
9450
9524
|
}
|
|
9451
9525
|
class SsrcEgressStreamSignaler {
|
|
9452
9526
|
constructor() {
|
|
9453
9527
|
this.streamIds = [];
|
|
9528
|
+
this.customCodecParameters = new Map();
|
|
9529
|
+
}
|
|
9530
|
+
reset() {
|
|
9531
|
+
this.streamIds = [];
|
|
9454
9532
|
}
|
|
9455
9533
|
signalStreams(simulcastEnabled, rtxEnabled, mLine) {
|
|
9456
9534
|
var _a;
|
|
@@ -9520,6 +9598,7 @@ class SsrcEgressStreamSignaler {
|
|
|
9520
9598
|
mLine.addLine(new SsrcGroupLine('SIM', this.streamIds.map((streamId) => streamId.ssrc)));
|
|
9521
9599
|
addVlaExtension(mLine);
|
|
9522
9600
|
}
|
|
9601
|
+
setCustomCodecParams(mLine, this.customCodecParameters);
|
|
9523
9602
|
}
|
|
9524
9603
|
getSenderIds() {
|
|
9525
9604
|
return this.streamIds;
|
|
@@ -9527,64 +9606,31 @@ class SsrcEgressStreamSignaler {
|
|
|
9527
9606
|
getEncodingIndexForStreamId(streamId) {
|
|
9528
9607
|
return this.streamIds.findIndex((currStreamId) => compareStreamIds(currStreamId, streamId));
|
|
9529
9608
|
}
|
|
9530
|
-
|
|
9531
|
-
|
|
9532
|
-
|
|
9533
|
-
|
|
9534
|
-
this.egressStreamSignalersByMid = new Map();
|
|
9535
|
-
this.ingressStreamsSignalersByMid = new Map();
|
|
9536
|
-
this.ingressStreamSignalingMode = streamSignalingMode;
|
|
9537
|
-
this.egressStreamSignalingMode = streamSignalingMode;
|
|
9538
|
-
}
|
|
9539
|
-
getOrCreateEgressStreamSignaler(mid) {
|
|
9540
|
-
const existing = this.getEgressStreamSignaler(mid);
|
|
9541
|
-
if (existing) {
|
|
9542
|
-
return existing;
|
|
9543
|
-
}
|
|
9544
|
-
let newSignaler;
|
|
9545
|
-
if (this.egressStreamSignalingMode === 'MID-RID') {
|
|
9546
|
-
newSignaler = new RidEgressStreamSignaler(mid);
|
|
9547
|
-
}
|
|
9548
|
-
else {
|
|
9549
|
-
newSignaler = new SsrcEgressStreamSignaler();
|
|
9550
|
-
}
|
|
9551
|
-
this.egressStreamSignalersByMid.set(mid, newSignaler);
|
|
9552
|
-
return newSignaler;
|
|
9553
|
-
}
|
|
9554
|
-
getEgressStreamSignalerOrThrow(mid) {
|
|
9555
|
-
const existing = this.getEgressStreamSignaler(mid);
|
|
9556
|
-
if (!existing) {
|
|
9557
|
-
throw new Error(`Couldn't find EgressStreamSignaler for mid ${mid}`);
|
|
9558
|
-
}
|
|
9559
|
-
return existing;
|
|
9560
|
-
}
|
|
9561
|
-
getEgressStreamSignaler(mid) {
|
|
9562
|
-
return this.egressStreamSignalersByMid.get(mid);
|
|
9609
|
+
setCodecParameters(parameters) {
|
|
9610
|
+
Object.entries(parameters).forEach(([param, value]) => {
|
|
9611
|
+
this.customCodecParameters.set(param, value);
|
|
9612
|
+
});
|
|
9563
9613
|
}
|
|
9564
|
-
|
|
9565
|
-
|
|
9566
|
-
|
|
9567
|
-
|
|
9568
|
-
}
|
|
9569
|
-
let newSignaler;
|
|
9570
|
-
if (this.ingressStreamSignalingMode === 'MID-RID') {
|
|
9571
|
-
newSignaler = new RidIngressStreamSignaler(mid);
|
|
9572
|
-
}
|
|
9573
|
-
else {
|
|
9574
|
-
newSignaler = new SsrcIngressStreamSignaler();
|
|
9575
|
-
}
|
|
9576
|
-
this.ingressStreamsSignalersByMid.set(mid, newSignaler);
|
|
9577
|
-
return newSignaler;
|
|
9614
|
+
deleteCodecParameters(parameters) {
|
|
9615
|
+
parameters.forEach((param) => {
|
|
9616
|
+
this.customCodecParameters.set(param, null);
|
|
9617
|
+
});
|
|
9578
9618
|
}
|
|
9579
|
-
|
|
9580
|
-
|
|
9619
|
+
}
|
|
9620
|
+
|
|
9621
|
+
class StatsManager {
|
|
9622
|
+
constructor(statsGetter, statsPreprocessor = () => __awaiter(this, void 0, void 0, function* () { })) {
|
|
9623
|
+
this.statsGetter = statsGetter;
|
|
9624
|
+
this.statsPreProcessor = statsPreprocessor;
|
|
9581
9625
|
}
|
|
9582
|
-
|
|
9583
|
-
|
|
9584
|
-
|
|
9585
|
-
|
|
9586
|
-
|
|
9587
|
-
|
|
9626
|
+
getStats() {
|
|
9627
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
9628
|
+
const statsReport = yield this.statsGetter();
|
|
9629
|
+
const statsMap = new Map();
|
|
9630
|
+
statsReport.forEach((stats, key) => statsMap.set(key, stats));
|
|
9631
|
+
yield this.statsPreProcessor(statsMap);
|
|
9632
|
+
return statsMap;
|
|
9633
|
+
});
|
|
9588
9634
|
}
|
|
9589
9635
|
}
|
|
9590
9636
|
|
|
@@ -13188,6 +13234,24 @@ function webRtcVideoContentHintToJmpVideoContentHint(hint) {
|
|
|
13188
13234
|
}
|
|
13189
13235
|
return undefined;
|
|
13190
13236
|
}
|
|
13237
|
+
function createEgressStreamSignaler(signalingMode, mid) {
|
|
13238
|
+
if (signalingMode === 'MID-RID') {
|
|
13239
|
+
return new RidEgressStreamSignaler(mid);
|
|
13240
|
+
}
|
|
13241
|
+
if (signalingMode === 'SSRC') {
|
|
13242
|
+
return new SsrcEgressStreamSignaler();
|
|
13243
|
+
}
|
|
13244
|
+
throw new Error(`unknown signaling mode`);
|
|
13245
|
+
}
|
|
13246
|
+
function createIngressStreamSignaler(signalingMode, mid) {
|
|
13247
|
+
if (signalingMode === 'MID-RID') {
|
|
13248
|
+
return new RidIngressStreamSignaler(mid);
|
|
13249
|
+
}
|
|
13250
|
+
if (signalingMode === 'SSRC') {
|
|
13251
|
+
return new SsrcIngressStreamSignaler();
|
|
13252
|
+
}
|
|
13253
|
+
throw new Error(`unknown signaling mode`);
|
|
13254
|
+
}
|
|
13191
13255
|
function toMediaFamily(kind) {
|
|
13192
13256
|
if (kind === exports.MediaStreamTrackKind.Video) {
|
|
13193
13257
|
return MediaFamily.Video;
|
|
@@ -13221,14 +13285,12 @@ class MultistreamConnection extends EventEmitter {
|
|
|
13221
13285
|
this.pendingJmpTasks = [];
|
|
13222
13286
|
this.metricsCallback = () => { };
|
|
13223
13287
|
this.overuseUpdateCallback = () => { };
|
|
13224
|
-
this.
|
|
13225
|
-
this.midMap = new Map();
|
|
13226
|
-
this.currentMid = 0;
|
|
13288
|
+
this.midPredictor = new MidPredictor();
|
|
13227
13289
|
this.offerAnswerQueue = new AsyncQueue();
|
|
13290
|
+
this.requestedIdEncodingParamsMap = new Map();
|
|
13228
13291
|
this.options = Object.assign(Object.assign({}, defaultMultistreamConnectionOptions), userOptions);
|
|
13229
13292
|
logger.info(`Creating multistream connection with options ${JSON.stringify(this.options)}`);
|
|
13230
13293
|
this.initializePeerConnection();
|
|
13231
|
-
this.streamSignalerManager = new StreamSignalerManager(this.options.streamSignalingMode);
|
|
13232
13294
|
this.overuseStateManager = new OveruseStateManager((overuseState) => this.overuseUpdateCallback(overuseState));
|
|
13233
13295
|
this.overuseStateManager.start();
|
|
13234
13296
|
this.statsManager = new StatsManager(() => this.pc.getStats(), (stats) => this.preProcessStats(stats));
|
|
@@ -13245,16 +13307,6 @@ class MultistreamConnection extends EventEmitter {
|
|
|
13245
13307
|
this.createSendTransceiver(MediaType.AudioSlides, contentSceneId);
|
|
13246
13308
|
}
|
|
13247
13309
|
}
|
|
13248
|
-
addMid(mediaType) {
|
|
13249
|
-
const mid = this.currentMid++;
|
|
13250
|
-
const mids = this.midMap.get(mediaType) || [];
|
|
13251
|
-
mids.push(`${mid}`);
|
|
13252
|
-
this.midMap.set(mediaType, mids);
|
|
13253
|
-
}
|
|
13254
|
-
clearMids() {
|
|
13255
|
-
this.midMap = new Map();
|
|
13256
|
-
this.currentMid = 0;
|
|
13257
|
-
}
|
|
13258
13310
|
initializePeerConnection() {
|
|
13259
13311
|
var _a;
|
|
13260
13312
|
(_a = this.pc) === null || _a === void 0 ? void 0 : _a.close();
|
|
@@ -13293,9 +13345,18 @@ class MultistreamConnection extends EventEmitter {
|
|
|
13293
13345
|
logger.error(`addTransceiver failed due to : ${e}`);
|
|
13294
13346
|
throw e;
|
|
13295
13347
|
}
|
|
13296
|
-
this.
|
|
13348
|
+
const mid = this.midPredictor.getNextMid(mediaType);
|
|
13297
13349
|
const csi = generateCsi(getMediaFamily(mediaType), sceneId);
|
|
13298
|
-
this.
|
|
13350
|
+
const signaler = createEgressStreamSignaler(this.options.streamSignalingMode, mid);
|
|
13351
|
+
const transceiver = new SendOnlyTransceiver(rtcTransceiver, mid, csi, signaler);
|
|
13352
|
+
if (getMediaFamily(mediaType) === MediaFamily.Video) {
|
|
13353
|
+
transceiver.rtxEnabled = true;
|
|
13354
|
+
transceiver.setCodecParameters({
|
|
13355
|
+
'max-mbps': `${defaultMaxVideoEncodeMbps}`,
|
|
13356
|
+
'max-fs': `${defaultMaxVideoEncodeFrameSize}`,
|
|
13357
|
+
});
|
|
13358
|
+
}
|
|
13359
|
+
this.sendTransceivers.set(mediaType, transceiver);
|
|
13299
13360
|
this.createJmpSession(mediaType);
|
|
13300
13361
|
}
|
|
13301
13362
|
createJmpSession(mediaType) {
|
|
@@ -13343,7 +13404,6 @@ class MultistreamConnection extends EventEmitter {
|
|
|
13343
13404
|
}
|
|
13344
13405
|
updateRequestedStreams(mediaType, requests) {
|
|
13345
13406
|
const sendTransceiver = this.getSendTransceiverOrThrow(mediaType);
|
|
13346
|
-
const signaler = this.streamSignalerManager.getEgressStreamSignalerOrThrow(sendTransceiver.mid);
|
|
13347
13407
|
const mediaFamily = getMediaFamily(mediaType);
|
|
13348
13408
|
const requestedIdEncodingParamsMap = new Map();
|
|
13349
13409
|
const rsRequests = requests.filter((r) => isValidReceiverSelectedInfo(r.policySpecificInfo));
|
|
@@ -13351,7 +13411,7 @@ class MultistreamConnection extends EventEmitter {
|
|
|
13351
13411
|
logger.warn('Ignoring non-receiver-selected requests');
|
|
13352
13412
|
}
|
|
13353
13413
|
rsRequests.forEach(({ ids, policySpecificInfo, codecInfos, maxPayloadBitsPerSecond }) => {
|
|
13354
|
-
var _a, _b, _c
|
|
13414
|
+
var _a, _b, _c;
|
|
13355
13415
|
if (ids.length > 1) {
|
|
13356
13416
|
throw new Error(`More than a single ID being unexpected/invalid ${ids}`);
|
|
13357
13417
|
}
|
|
@@ -13364,18 +13424,15 @@ class MultistreamConnection extends EventEmitter {
|
|
|
13364
13424
|
}
|
|
13365
13425
|
const id = ids[0];
|
|
13366
13426
|
const codecInfo = codecInfos[0];
|
|
13367
|
-
const streamIdsMatched =
|
|
13368
|
-
.getSenderIds()
|
|
13369
|
-
.some((validId) => compareStreamIds(id, validId));
|
|
13427
|
+
const streamIdsMatched = sendTransceiver.senderIds.some((validId) => compareStreamIds(id, validId));
|
|
13370
13428
|
if (streamIdsMatched) {
|
|
13371
|
-
const encodingIndex =
|
|
13429
|
+
const encodingIndex = sendTransceiver.getEncodingIndexForStreamId(id);
|
|
13372
13430
|
if (encodingIndex !== -1) {
|
|
13373
13431
|
const encodingParams = { maxPayloadBitsPerSecond };
|
|
13374
13432
|
if (mediaFamily === MediaFamily.Video) {
|
|
13375
|
-
|
|
13376
|
-
|
|
13377
|
-
|
|
13378
|
-
}
|
|
13433
|
+
encodingParams.maxFs = (_a = codecInfo === null || codecInfo === void 0 ? void 0 : codecInfo.h264) === null || _a === void 0 ? void 0 : _a.maxFs;
|
|
13434
|
+
encodingParams.maxWidth = (_b = codecInfo === null || codecInfo === void 0 ? void 0 : codecInfo.h264) === null || _b === void 0 ? void 0 : _b.maxWidth;
|
|
13435
|
+
encodingParams.maxHeight = (_c = codecInfo === null || codecInfo === void 0 ? void 0 : codecInfo.h264) === null || _c === void 0 ? void 0 : _c.maxHeight;
|
|
13379
13436
|
}
|
|
13380
13437
|
requestedIdEncodingParamsMap.set(encodingIndex, encodingParams);
|
|
13381
13438
|
}
|
|
@@ -13387,8 +13444,8 @@ class MultistreamConnection extends EventEmitter {
|
|
|
13387
13444
|
logger.warn(`${mediaType}: Unable to find matching stream ID for requested ID: ${JSON.stringify(id)}`);
|
|
13388
13445
|
}
|
|
13389
13446
|
});
|
|
13390
|
-
sendTransceiver.setTrackRequested(requestedIdEncodingParamsMap.size > 0);
|
|
13391
13447
|
sendTransceiver.updateSendParameters(requestedIdEncodingParamsMap);
|
|
13448
|
+
this.requestedIdEncodingParamsMap = requestedIdEncodingParamsMap;
|
|
13392
13449
|
}
|
|
13393
13450
|
createDataChannel() {
|
|
13394
13451
|
const dataChannel = this.pc.createDataChannel('datachannel', {});
|
|
@@ -13450,10 +13507,6 @@ class MultistreamConnection extends EventEmitter {
|
|
|
13450
13507
|
return;
|
|
13451
13508
|
}
|
|
13452
13509
|
const streamStates = this.getVideoStreamStates(mediaType);
|
|
13453
|
-
if (streamStates === null) {
|
|
13454
|
-
logger.debug(`Empty streamStates, not sending MediaRequestStatus`);
|
|
13455
|
-
return;
|
|
13456
|
-
}
|
|
13457
13510
|
const task = () => {
|
|
13458
13511
|
var _a;
|
|
13459
13512
|
(_a = this.jmpSessions.get(mediaType)) === null || _a === void 0 ? void 0 : _a.sendMediaRequestStatus(streamStates);
|
|
@@ -13533,8 +13586,9 @@ class MultistreamConnection extends EventEmitter {
|
|
|
13533
13586
|
});
|
|
13534
13587
|
}
|
|
13535
13588
|
addTrackListeners(mediaType, track) {
|
|
13589
|
+
const sendTransceiver = this.getSendTransceiverOrThrow(mediaType);
|
|
13536
13590
|
const onTrackResolutionChange = () => {
|
|
13537
|
-
this.
|
|
13591
|
+
sendTransceiver.updateSendParameters(this.requestedIdEncodingParamsMap);
|
|
13538
13592
|
};
|
|
13539
13593
|
track.on(LocalTrack.Events.TrackConstraintsChange, onTrackResolutionChange);
|
|
13540
13594
|
const onTrackMute = () => {
|
|
@@ -13551,21 +13605,19 @@ class MultistreamConnection extends EventEmitter {
|
|
|
13551
13605
|
if (!track.muted) {
|
|
13552
13606
|
this.sendSourceAdvertisement(mediaType);
|
|
13553
13607
|
this.sendMediaRequestStatus(mediaType);
|
|
13608
|
+
if (mediaType === MediaType.VideoMain) {
|
|
13609
|
+
sendTransceiver.updateSendParameters(this.requestedIdEncodingParamsMap);
|
|
13610
|
+
}
|
|
13554
13611
|
}
|
|
13555
13612
|
};
|
|
13556
13613
|
track.on(LocalTrack.Events.PublishedStateUpdate, onTrackPublish);
|
|
13557
13614
|
}
|
|
13558
13615
|
getVideoStreamStates(mediaType) {
|
|
13559
|
-
var _a, _b
|
|
13616
|
+
var _a, _b;
|
|
13560
13617
|
const sendTransceiver = this.getSendTransceiverOrThrow(mediaType);
|
|
13561
|
-
const
|
|
13562
|
-
|
|
13563
|
-
|
|
13564
|
-
}
|
|
13565
|
-
const activeSimulcastLayerNumber = ((_a = sendTransceiver.publishedTrack) === null || _a === void 0 ? void 0 : _a.getNumActiveSimulcastLayers()) || 0;
|
|
13566
|
-
const published = (_b = sendTransceiver.publishedTrack) === null || _b === void 0 ? void 0 : _b.published;
|
|
13567
|
-
const muted = ((_c = sendTransceiver.publishedTrack) === null || _c === void 0 ? void 0 : _c.muted) === true;
|
|
13568
|
-
return signaler.getSenderIds().map((id) => {
|
|
13618
|
+
const published = (_a = sendTransceiver.publishedTrack) === null || _a === void 0 ? void 0 : _a.published;
|
|
13619
|
+
const muted = ((_b = sendTransceiver.publishedTrack) === null || _b === void 0 ? void 0 : _b.muted) === true;
|
|
13620
|
+
return sendTransceiver.senderIds.map((id) => {
|
|
13569
13621
|
let state;
|
|
13570
13622
|
if (!published) {
|
|
13571
13623
|
state = 'no source';
|
|
@@ -13573,9 +13625,6 @@ class MultistreamConnection extends EventEmitter {
|
|
|
13573
13625
|
else if (muted) {
|
|
13574
13626
|
state = 'avatar';
|
|
13575
13627
|
}
|
|
13576
|
-
else if (activeSimulcastLayerNumber < signaler.getEncodingIndexForStreamId(id)) {
|
|
13577
|
-
state = 'no source';
|
|
13578
|
-
}
|
|
13579
13628
|
else {
|
|
13580
13629
|
state = 'live';
|
|
13581
13630
|
}
|
|
@@ -13589,21 +13638,16 @@ class MultistreamConnection extends EventEmitter {
|
|
|
13589
13638
|
const rtcRtpTransceiver = this.pc.addTransceiver(toMediaStreamTrackKind(mediaType), {
|
|
13590
13639
|
direction: 'recvonly',
|
|
13591
13640
|
});
|
|
13592
|
-
this.
|
|
13593
|
-
const
|
|
13594
|
-
|
|
13595
|
-
if (!ingressSignaler) {
|
|
13596
|
-
return null;
|
|
13597
|
-
}
|
|
13598
|
-
return ingressSignaler.getReceiverId();
|
|
13599
|
-
});
|
|
13600
|
-
if (this.pc.getRemoteDescription()) {
|
|
13601
|
-
yield this.doLocalOfferAnswer();
|
|
13602
|
-
}
|
|
13641
|
+
const transceiverMid = this.midPredictor.getNextMid(mediaType);
|
|
13642
|
+
const ingressSignaler = createIngressStreamSignaler(this.options.streamSignalingMode, transceiverMid);
|
|
13643
|
+
const recvOnlyTransceiver = new ReceiveOnlyTransceiver(rtcRtpTransceiver, transceiverMid, ingressSignaler);
|
|
13603
13644
|
this.recvTransceivers.set(mediaType, [
|
|
13604
13645
|
...(this.recvTransceivers.get(mediaType) || []),
|
|
13605
13646
|
recvOnlyTransceiver,
|
|
13606
13647
|
]);
|
|
13648
|
+
if (this.pc.getRemoteDescription()) {
|
|
13649
|
+
yield this.doLocalOfferAnswer();
|
|
13650
|
+
}
|
|
13607
13651
|
createReceiveSlotResolve(recvOnlyTransceiver.receiveSlot);
|
|
13608
13652
|
}));
|
|
13609
13653
|
});
|
|
@@ -13643,7 +13687,7 @@ class MultistreamConnection extends EventEmitter {
|
|
|
13643
13687
|
createOffer() {
|
|
13644
13688
|
return __awaiter(this, void 0, void 0, function* () {
|
|
13645
13689
|
if (!this.pc.getLocalDescription()) {
|
|
13646
|
-
this.
|
|
13690
|
+
this.midPredictor.allocateMidForDatachannel();
|
|
13647
13691
|
}
|
|
13648
13692
|
return new Promise((createOfferResolve) => {
|
|
13649
13693
|
this.offerAnswerQueue.push(() => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -13669,7 +13713,6 @@ class MultistreamConnection extends EventEmitter {
|
|
|
13669
13713
|
}
|
|
13670
13714
|
setAnswer(answer) {
|
|
13671
13715
|
return __awaiter(this, void 0, void 0, function* () {
|
|
13672
|
-
const isInitialAnswer = !this.pc.getRemoteDescription();
|
|
13673
13716
|
const sdp = this.preProcessRemoteAnswer(answer);
|
|
13674
13717
|
if (!this.setAnswerResolve) {
|
|
13675
13718
|
throw new Error(`Call to setAnswer without having previously called createOffer`);
|
|
@@ -13682,9 +13725,6 @@ class MultistreamConnection extends EventEmitter {
|
|
|
13682
13725
|
else {
|
|
13683
13726
|
logger.debug(`setAnswerResolve function was cleared between setAnswer and result of setRemoteDescription`);
|
|
13684
13727
|
}
|
|
13685
|
-
if (isInitialAnswer && this.customCodecParameters.size > 0) {
|
|
13686
|
-
yield this.queueLocalOfferAnswer();
|
|
13687
|
-
}
|
|
13688
13728
|
}));
|
|
13689
13729
|
});
|
|
13690
13730
|
}
|
|
@@ -13722,43 +13762,17 @@ class MultistreamConnection extends EventEmitter {
|
|
|
13722
13762
|
parsed.avMedia
|
|
13723
13763
|
.filter((av) => av.direction === 'recvonly')
|
|
13724
13764
|
.forEach((av) => {
|
|
13725
|
-
const
|
|
13726
|
-
|
|
13765
|
+
const transceiver = this.getRecvTransceiverByMidOrThrow(av.mid);
|
|
13766
|
+
transceiver.signalLocalStreams(av);
|
|
13727
13767
|
});
|
|
13728
13768
|
parsed.avMedia
|
|
13729
|
-
.filter((av) => av.direction === 'sendrecv')
|
|
13769
|
+
.filter((av) => av.direction === 'sendrecv' || av.direction === 'inactive')
|
|
13730
13770
|
.forEach((av) => {
|
|
13731
|
-
const
|
|
13732
|
-
|
|
13733
|
-
const rtxEnabled = av.type === 'video';
|
|
13734
|
-
egressSignaler.signalStreams(simulcastEnabled, rtxEnabled, av);
|
|
13735
|
-
if (av.type === 'video') {
|
|
13736
|
-
[...av.codecs.values()]
|
|
13737
|
-
.filter((ci) => ci.name === 'H264')
|
|
13738
|
-
.forEach((ci) => {
|
|
13739
|
-
ci.fmtParams.set('max-mbps', `${defaultMaxVideoEncodeMbps}`);
|
|
13740
|
-
ci.fmtParams.set('max-fs', `${defaultMaxVideoEncodeFrameSize}`);
|
|
13741
|
-
});
|
|
13742
|
-
}
|
|
13743
|
-
const mediaType = [...this.sendTransceivers.keys()].find((key) => { var _a; return ((_a = this.sendTransceivers.get(key)) === null || _a === void 0 ? void 0 : _a.mid) === av.mid; });
|
|
13744
|
-
if (mediaType && this.customCodecParameters.has(mediaType)) {
|
|
13745
|
-
[...av.codecs.values()]
|
|
13746
|
-
.filter((ci) => ci.name === (av.type === 'audio' ? 'opus' : 'H264'))
|
|
13747
|
-
.forEach((ci) => {
|
|
13748
|
-
var _a;
|
|
13749
|
-
(_a = this.customCodecParameters.get(mediaType)) === null || _a === void 0 ? void 0 : _a.forEach((value, param) => {
|
|
13750
|
-
if (value === null) {
|
|
13751
|
-
ci.fmtParams.delete(param);
|
|
13752
|
-
}
|
|
13753
|
-
else {
|
|
13754
|
-
ci.fmtParams.set(param, `${value}`);
|
|
13755
|
-
}
|
|
13756
|
-
});
|
|
13757
|
-
});
|
|
13758
|
-
}
|
|
13771
|
+
const transceiver = this.getSendTransceiverByMidOrThrow(av.mid);
|
|
13772
|
+
transceiver.signalStreams(av);
|
|
13759
13773
|
});
|
|
13760
13774
|
if (getBrowserDetails().name !== 'Firefox') {
|
|
13761
|
-
setupBundle(parsed, this.options.bundlePolicy, this.
|
|
13775
|
+
setupBundle(parsed, this.options.bundlePolicy, this.midPredictor.getMidMap());
|
|
13762
13776
|
}
|
|
13763
13777
|
return parsed.toString();
|
|
13764
13778
|
}
|
|
@@ -13787,7 +13801,7 @@ class MultistreamConnection extends EventEmitter {
|
|
|
13787
13801
|
}
|
|
13788
13802
|
});
|
|
13789
13803
|
if (getBrowserDetails().name === 'Firefox') {
|
|
13790
|
-
setupBundle(parsed, this.options.bundlePolicy, this.
|
|
13804
|
+
setupBundle(parsed, this.options.bundlePolicy, this.midPredictor.getMidMap());
|
|
13791
13805
|
if (this.options.bundlePolicy === 'max-bundle') {
|
|
13792
13806
|
parsed.media.forEach((mline, index) => {
|
|
13793
13807
|
if (index > 0) {
|
|
@@ -13802,9 +13816,10 @@ class MultistreamConnection extends EventEmitter {
|
|
|
13802
13816
|
var _a;
|
|
13803
13817
|
const parsedAnswer = parse(answer);
|
|
13804
13818
|
const parsedOffer = parse((_a = this.pc.getLocalDescription()) === null || _a === void 0 ? void 0 : _a.sdp);
|
|
13805
|
-
|
|
13819
|
+
const recvTransceiversByMid = new Map([...this.recvTransceivers.values()].flat().map((t) => [t.mid, t]));
|
|
13820
|
+
matchMlinesInAnswer(parsedOffer, parsedAnswer, recvTransceiversByMid);
|
|
13806
13821
|
if (getBrowserDetails().name === 'Firefox') {
|
|
13807
|
-
setupBundle(parsedAnswer, this.options.bundlePolicy, this.
|
|
13822
|
+
setupBundle(parsedAnswer, this.options.bundlePolicy, this.midPredictor.getMidMap());
|
|
13808
13823
|
if (this.options.bundlePolicy === 'max-bundle') {
|
|
13809
13824
|
const { ufrag, pwd } = parsedAnswer.media[0].iceInfo;
|
|
13810
13825
|
parsedAnswer.media.forEach((mline, index) => {
|
|
@@ -13824,6 +13839,20 @@ class MultistreamConnection extends EventEmitter {
|
|
|
13824
13839
|
}
|
|
13825
13840
|
return sendTransceiver;
|
|
13826
13841
|
}
|
|
13842
|
+
getSendTransceiverByMidOrThrow(mid) {
|
|
13843
|
+
const transceiver = [...this.sendTransceivers.values()].find((t) => t.mid === mid);
|
|
13844
|
+
if (!transceiver) {
|
|
13845
|
+
throw new Error(`Unable to find send transceiver with mid ${mid}`);
|
|
13846
|
+
}
|
|
13847
|
+
return transceiver;
|
|
13848
|
+
}
|
|
13849
|
+
getRecvTransceiverByMidOrThrow(mid) {
|
|
13850
|
+
const transceiver = [...this.recvTransceivers.values()].flat().find((t) => t.mid === mid);
|
|
13851
|
+
if (!transceiver) {
|
|
13852
|
+
throw new Error(`Unable to find recv transceiver with mid ${mid}`);
|
|
13853
|
+
}
|
|
13854
|
+
return transceiver;
|
|
13855
|
+
}
|
|
13827
13856
|
getPublishedTracks() {
|
|
13828
13857
|
return [...this.sendTransceivers.values()]
|
|
13829
13858
|
.map((transceiver) => transceiver.publishedTrack)
|
|
@@ -13831,11 +13860,8 @@ class MultistreamConnection extends EventEmitter {
|
|
|
13831
13860
|
}
|
|
13832
13861
|
setCodecParameters(mediaType, parameters) {
|
|
13833
13862
|
return __awaiter(this, void 0, void 0, function* () {
|
|
13834
|
-
const
|
|
13835
|
-
|
|
13836
|
-
currentParams.set(param, value);
|
|
13837
|
-
});
|
|
13838
|
-
this.customCodecParameters.set(mediaType, currentParams);
|
|
13863
|
+
const transceiver = this.sendTransceivers.get(mediaType);
|
|
13864
|
+
transceiver === null || transceiver === void 0 ? void 0 : transceiver.setCodecParameters(parameters);
|
|
13839
13865
|
if (this.pc.getRemoteDescription()) {
|
|
13840
13866
|
yield this.queueLocalOfferAnswer();
|
|
13841
13867
|
}
|
|
@@ -13843,11 +13869,8 @@ class MultistreamConnection extends EventEmitter {
|
|
|
13843
13869
|
}
|
|
13844
13870
|
deleteCodecParameters(mediaType, parameters) {
|
|
13845
13871
|
return __awaiter(this, void 0, void 0, function* () {
|
|
13846
|
-
const
|
|
13847
|
-
|
|
13848
|
-
currentParams.set(param, null);
|
|
13849
|
-
});
|
|
13850
|
-
this.customCodecParameters.set(mediaType, currentParams);
|
|
13872
|
+
const transceiver = this.sendTransceivers.get(mediaType);
|
|
13873
|
+
transceiver === null || transceiver === void 0 ? void 0 : transceiver.deleteCodecParameters(parameters);
|
|
13851
13874
|
if (this.pc.getRemoteDescription()) {
|
|
13852
13875
|
yield this.queueLocalOfferAnswer();
|
|
13853
13876
|
}
|
|
@@ -13891,32 +13914,34 @@ class MultistreamConnection extends EventEmitter {
|
|
|
13891
13914
|
this.options = Object.assign(Object.assign({}, this.options), userOptions);
|
|
13892
13915
|
}
|
|
13893
13916
|
logger.info(`Renewing multistream connection with options ${JSON.stringify(this.options)}`);
|
|
13894
|
-
this.
|
|
13917
|
+
this.midPredictor.reset();
|
|
13895
13918
|
this.initializePeerConnection();
|
|
13896
|
-
this.streamSignalerManager = new StreamSignalerManager(this.options.streamSignalingMode);
|
|
13897
13919
|
const mainSceneId = generateSceneId();
|
|
13898
13920
|
const slidesSceneId = generateSceneId();
|
|
13899
13921
|
this.sendTransceivers.forEach((transceiver, mediaType) => {
|
|
13900
13922
|
var _a;
|
|
13901
13923
|
const mediaContent = getMediaContent(mediaType);
|
|
13902
13924
|
const sceneId = mediaContent === MediaContent.Main ? mainSceneId : slidesSceneId;
|
|
13903
|
-
this.
|
|
13925
|
+
const mid = this.midPredictor.getNextMid(mediaType);
|
|
13904
13926
|
transceiver.replaceTransceiver(this.pc.addTransceiver(toMediaStreamTrackKind(mediaType), {
|
|
13905
13927
|
direction: 'sendrecv',
|
|
13906
13928
|
sendEncodings: getMediaFamily(mediaType) === MediaFamily.Video
|
|
13907
13929
|
? this.getVideoEncodingOptions(mediaContent)
|
|
13908
13930
|
: undefined,
|
|
13909
13931
|
}));
|
|
13932
|
+
transceiver.mid = mid;
|
|
13910
13933
|
transceiver.csi = generateCsi(getMediaFamily(mediaType), sceneId);
|
|
13934
|
+
transceiver.resetStreamSignaler();
|
|
13911
13935
|
(_a = this.jmpSessions.get(mediaType)) === null || _a === void 0 ? void 0 : _a.close();
|
|
13912
13936
|
this.createJmpSession(mediaType);
|
|
13913
13937
|
});
|
|
13914
13938
|
this.recvTransceivers.forEach((transceivers, mediaType) => {
|
|
13915
13939
|
transceivers.forEach((t) => {
|
|
13916
|
-
this.
|
|
13940
|
+
const mid = this.midPredictor.getNextMid(mediaType);
|
|
13917
13941
|
t.replaceTransceiver(this.pc.addTransceiver(toMediaStreamTrackKind(mediaType), {
|
|
13918
13942
|
direction: 'recvonly',
|
|
13919
13943
|
}));
|
|
13944
|
+
t.mid = mid;
|
|
13920
13945
|
});
|
|
13921
13946
|
});
|
|
13922
13947
|
}
|
|
@@ -13965,10 +13990,7 @@ class MultistreamConnection extends EventEmitter {
|
|
|
13965
13990
|
statsToModify.mid = (_a = transceiver.receiveSlot.id) === null || _a === void 0 ? void 0 : _a.mid;
|
|
13966
13991
|
statsToModify.csi = transceiver.receiveSlot.currentRxCsi;
|
|
13967
13992
|
statsToModify.mediaType = mediaType;
|
|
13968
|
-
|
|
13969
|
-
if (signaler) {
|
|
13970
|
-
Object.assign(statsToModify, signaler.getReceiverId());
|
|
13971
|
-
}
|
|
13993
|
+
Object.assign(statsToModify, transceiver.receiverId);
|
|
13972
13994
|
stats.set(receiverStats.id, statsToModify);
|
|
13973
13995
|
}
|
|
13974
13996
|
});
|