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