mediasoup-client 3.24.1 → 3.24.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/lib/Producer.d.ts.map +1 -1
- package/lib/Producer.js +18 -4
- package/lib/Transport.d.ts.map +1 -1
- package/lib/Transport.js +30 -11
- package/lib/handlers/Chrome111.d.ts.map +1 -1
- package/lib/handlers/Chrome111.js +130 -95
- package/lib/handlers/Chrome74.d.ts.map +1 -1
- package/lib/handlers/Chrome74.js +166 -129
- package/lib/handlers/Firefox120.d.ts.map +1 -1
- package/lib/handlers/Firefox120.js +142 -102
- package/lib/handlers/ReactNative106.d.ts.map +1 -1
- package/lib/handlers/ReactNative106.js +183 -146
- package/lib/handlers/Safari12.d.ts.map +1 -1
- package/lib/handlers/Safari12.js +147 -113
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/ortc.d.ts.map +1 -1
- package/lib/ortc.js +9 -5
- package/lib/test/test.js +60 -1
- package/package.json +5 -5
package/lib/handlers/Safari12.js
CHANGED
|
@@ -238,115 +238,131 @@ class Safari12 extends enhancedEvents_1.EnhancedEventEmitter {
|
|
|
238
238
|
this.assertNotClosed();
|
|
239
239
|
this.assertSendDirection();
|
|
240
240
|
logger.debug('send() [kind:%s, track.id:%s, streamId:%s]', track.kind, track.id, streamId);
|
|
241
|
+
if (encodings && encodings.length > 1) {
|
|
242
|
+
// Set rid and verify scalabilityMode in each encoding.
|
|
243
|
+
// NOTE: Even if WebRTC allows different scalabilityMode (different number
|
|
244
|
+
// of temporal layers) per simulcast stream, we need that those are the
|
|
245
|
+
// same in all them, so let's pick up the highest value.
|
|
246
|
+
// NOTE: If scalabilityMode is not given, Safari will use L1T3.
|
|
247
|
+
let maxTemporalLayers = 1;
|
|
248
|
+
for (const encoding of encodings) {
|
|
249
|
+
const temporalLayers = encoding.scalabilityMode
|
|
250
|
+
? (0, scalabilityModes_1.parse)(encoding.scalabilityMode).temporalLayers
|
|
251
|
+
: 3;
|
|
252
|
+
if (temporalLayers > maxTemporalLayers) {
|
|
253
|
+
maxTemporalLayers = temporalLayers;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
encodings.forEach((encoding, idx) => {
|
|
257
|
+
encoding.rid = `r${idx}`;
|
|
258
|
+
encoding.scalabilityMode = `L1T${maxTemporalLayers}`;
|
|
259
|
+
});
|
|
260
|
+
}
|
|
241
261
|
const mediaSectionIdx = this._remoteSdp.getNextMediaSectionIdx();
|
|
242
262
|
const transceiver = this._pc.addTransceiver(track, {
|
|
243
263
|
direction: 'sendonly',
|
|
244
264
|
streams: [this._sendStream],
|
|
245
265
|
sendEncodings: encodings,
|
|
246
266
|
});
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
onRtpSender
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
267
|
+
try {
|
|
268
|
+
if (this._forcedRtpExtensions) {
|
|
269
|
+
ortcUtils.applyForcedRtpExtensions(transceiver, this._forcedRtpExtensions);
|
|
270
|
+
}
|
|
271
|
+
if (onRtpSender) {
|
|
272
|
+
onRtpSender(transceiver.sender);
|
|
273
|
+
}
|
|
274
|
+
const offer = await this._pc.createOffer();
|
|
275
|
+
let localSdpObject = sdpTransform.parse(offer.sdp);
|
|
276
|
+
if (localSdpObject.extmapAllowMixed) {
|
|
277
|
+
this._remoteSdp.setSessionExtmapAllowMixed();
|
|
278
|
+
}
|
|
279
|
+
const nativeRtpCapabilities = Safari12.getLocalRtpCapabilities(localSdpObject);
|
|
280
|
+
const sendExtendedRtpCapabilities = this._getSendExtendedRtpCapabilities(nativeRtpCapabilities);
|
|
281
|
+
// Generic sending RTP parameters.
|
|
282
|
+
const sendingRtpParameters = ortc.getSendingRtpParameters(track.kind, sendExtendedRtpCapabilities);
|
|
283
|
+
// This may throw.
|
|
284
|
+
sendingRtpParameters.codecs = ortc.reduceCodecs(sendingRtpParameters.codecs, codec);
|
|
285
|
+
// Generic sending RTP parameters suitable for the SDP remote answer.
|
|
286
|
+
const sendingRemoteRtpParameters = ortc.getSendingRemoteRtpParameters(track.kind, sendExtendedRtpCapabilities);
|
|
287
|
+
// This may throw.
|
|
288
|
+
sendingRemoteRtpParameters.codecs = ortc.reduceCodecs(sendingRemoteRtpParameters.codecs, codec);
|
|
289
|
+
if (!this._transportReady) {
|
|
290
|
+
await this.setupTransport({
|
|
291
|
+
localDtlsRole: this._forcedLocalDtlsRole ?? 'client',
|
|
292
|
+
localSdpObject,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
logger.debug('send() | calling pc.setLocalDescription() [offer:%o]', offer);
|
|
296
|
+
await this._pc.setLocalDescription(offer);
|
|
297
|
+
// We can now get the transceiver.mid.
|
|
298
|
+
const localId = transceiver.mid;
|
|
299
|
+
// Set MID.
|
|
300
|
+
sendingRtpParameters.mid = localId;
|
|
301
|
+
localSdpObject = sdpTransform.parse(this._pc.localDescription.sdp);
|
|
302
|
+
const offerMediaObject = localSdpObject.media[mediaSectionIdx.idx];
|
|
303
|
+
// Set RTCP CNAME.
|
|
304
|
+
sendingRtpParameters.rtcp.cname = sdpCommonUtils.getCname({
|
|
305
|
+
offerMediaObject,
|
|
273
306
|
});
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
307
|
+
// Set msid.
|
|
308
|
+
sendingRtpParameters.msid = `${streamId ?? this._sendStream.id} ${track.id}`;
|
|
309
|
+
// Set RTP encodings by parsing the SDP offer if no encodings are given.
|
|
310
|
+
if (!encodings) {
|
|
311
|
+
sendingRtpParameters.encodings = sdpUnifiedPlanUtils.getRtpEncodings({
|
|
312
|
+
offerMediaObject,
|
|
313
|
+
codecs: sendingRtpParameters.codecs,
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
// Set RTP encodings by parsing the SDP offer and complete them with given
|
|
317
|
+
// one if just a single encoding has been given.
|
|
318
|
+
else if (encodings.length === 1) {
|
|
319
|
+
const newEncodings = sdpUnifiedPlanUtils.getRtpEncodings({
|
|
320
|
+
offerMediaObject,
|
|
321
|
+
codecs: sendingRtpParameters.codecs,
|
|
322
|
+
});
|
|
323
|
+
Object.assign(newEncodings[0], encodings[0]);
|
|
324
|
+
sendingRtpParameters.encodings = newEncodings;
|
|
325
|
+
}
|
|
326
|
+
// Otherwise if more than 1 encoding are given use them verbatim.
|
|
327
|
+
else {
|
|
328
|
+
sendingRtpParameters.encodings = encodings;
|
|
329
|
+
}
|
|
330
|
+
this._remoteSdp.send({
|
|
281
331
|
offerMediaObject,
|
|
282
|
-
|
|
332
|
+
reuseMid: mediaSectionIdx.reuseMid,
|
|
333
|
+
offerRtpParameters: sendingRtpParameters,
|
|
334
|
+
answerRtpParameters: sendingRemoteRtpParameters,
|
|
335
|
+
codecOptions,
|
|
283
336
|
});
|
|
284
|
-
|
|
285
|
-
type: '
|
|
286
|
-
sdp:
|
|
337
|
+
const answer = {
|
|
338
|
+
type: 'answer',
|
|
339
|
+
sdp: this._remoteSdp.getSdp(),
|
|
340
|
+
};
|
|
341
|
+
logger.debug('send() | calling pc.setRemoteDescription() [answer:%o]', answer);
|
|
342
|
+
await this._pc.setRemoteDescription(answer);
|
|
343
|
+
// Store in the map.
|
|
344
|
+
this._mapMidTransceiver.set(localId, transceiver);
|
|
345
|
+
return {
|
|
346
|
+
localId,
|
|
347
|
+
rtpParameters: sendingRtpParameters,
|
|
348
|
+
rtpSender: transceiver.sender,
|
|
287
349
|
};
|
|
288
350
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
sendingRtpParameters.rtcp.cname = sdpCommonUtils.getCname({
|
|
299
|
-
offerMediaObject,
|
|
300
|
-
});
|
|
301
|
-
// Set msid.
|
|
302
|
-
sendingRtpParameters.msid = `${streamId ?? this._sendStream.id} ${track.id}`;
|
|
303
|
-
// Set RTP encodings.
|
|
304
|
-
sendingRtpParameters.encodings = sdpUnifiedPlanUtils.getRtpEncodings({
|
|
305
|
-
offerMediaObject,
|
|
306
|
-
codecs: sendingRtpParameters.codecs,
|
|
307
|
-
});
|
|
308
|
-
// Complete encodings with given values.
|
|
309
|
-
if (encodings) {
|
|
310
|
-
for (let idx = 0; idx < sendingRtpParameters.encodings.length; ++idx) {
|
|
311
|
-
if (encodings[idx]) {
|
|
312
|
-
Object.assign(sendingRtpParameters.encodings[idx], encodings[idx]);
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
// If VP8 or H264 and there is effective simulcast, add scalabilityMode to
|
|
317
|
-
// each encoding.
|
|
318
|
-
if (sendingRtpParameters.encodings.length > 1 &&
|
|
319
|
-
(sendingRtpParameters.codecs[0].mimeType.toLowerCase() === 'video/vp8' ||
|
|
320
|
-
sendingRtpParameters.codecs[0].mimeType.toLowerCase() === 'video/h264')) {
|
|
321
|
-
for (const encoding of sendingRtpParameters.encodings) {
|
|
322
|
-
if (encoding.scalabilityMode) {
|
|
323
|
-
encoding.scalabilityMode = `L1T${layers.temporalLayers}`;
|
|
324
|
-
}
|
|
325
|
-
else {
|
|
326
|
-
encoding.scalabilityMode = 'L1T3';
|
|
351
|
+
catch (error) {
|
|
352
|
+
// Undo the changes done in the PeerConnection, otherwise it gets out of
|
|
353
|
+
// sync with the remote SDP and later calls to send() fail.
|
|
354
|
+
try {
|
|
355
|
+
if (this._pc.signalingState === 'have-local-offer') {
|
|
356
|
+
try {
|
|
357
|
+
await this._pc.setLocalDescription({ type: 'rollback' });
|
|
358
|
+
}
|
|
359
|
+
catch (error2) { }
|
|
327
360
|
}
|
|
361
|
+
transceiver.stop();
|
|
328
362
|
}
|
|
363
|
+
catch (error3) { }
|
|
364
|
+
throw error;
|
|
329
365
|
}
|
|
330
|
-
this._remoteSdp.send({
|
|
331
|
-
offerMediaObject,
|
|
332
|
-
reuseMid: mediaSectionIdx.reuseMid,
|
|
333
|
-
offerRtpParameters: sendingRtpParameters,
|
|
334
|
-
answerRtpParameters: sendingRemoteRtpParameters,
|
|
335
|
-
codecOptions,
|
|
336
|
-
});
|
|
337
|
-
const answer = {
|
|
338
|
-
type: 'answer',
|
|
339
|
-
sdp: this._remoteSdp.getSdp(),
|
|
340
|
-
};
|
|
341
|
-
logger.debug('send() | calling pc.setRemoteDescription() [answer:%o]', answer);
|
|
342
|
-
await this._pc.setRemoteDescription(answer);
|
|
343
|
-
// Store in the map.
|
|
344
|
-
this._mapMidTransceiver.set(localId, transceiver);
|
|
345
|
-
return {
|
|
346
|
-
localId,
|
|
347
|
-
rtpParameters: sendingRtpParameters,
|
|
348
|
-
rtpSender: transceiver.sender,
|
|
349
|
-
};
|
|
350
366
|
}
|
|
351
367
|
async stopSending(localId) {
|
|
352
368
|
this.assertSendDirection();
|
|
@@ -514,25 +530,43 @@ class Safari12 extends enhancedEvents_1.EnhancedEventEmitter {
|
|
|
514
530
|
// If this is the first DataChannel we need to create the SDP answer with
|
|
515
531
|
// m=application section.
|
|
516
532
|
if (!this._hasDataChannelMediaSection) {
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
533
|
+
try {
|
|
534
|
+
const offer = await this._pc.createOffer();
|
|
535
|
+
const localSdpObject = sdpTransform.parse(offer.sdp);
|
|
536
|
+
const offerMediaObject = localSdpObject.media.find(m => m.type === 'application');
|
|
537
|
+
if (!this._transportReady) {
|
|
538
|
+
await this.setupTransport({
|
|
539
|
+
localDtlsRole: this._forcedLocalDtlsRole ?? 'client',
|
|
540
|
+
localSdpObject,
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
logger.debug('sendDataChannel() | calling pc.setLocalDescription() [offer:%o]', offer);
|
|
544
|
+
await this._pc.setLocalDescription(offer);
|
|
545
|
+
this._remoteSdp.sendSctpAssociation({ offerMediaObject });
|
|
546
|
+
const answer = {
|
|
547
|
+
type: 'answer',
|
|
548
|
+
sdp: this._remoteSdp.getSdp(),
|
|
549
|
+
};
|
|
550
|
+
logger.debug('sendDataChannel() | calling pc.setRemoteDescription() [answer:%o]', answer);
|
|
551
|
+
await this._pc.setRemoteDescription(answer);
|
|
552
|
+
this._hasDataChannelMediaSection = true;
|
|
553
|
+
}
|
|
554
|
+
catch (error) {
|
|
555
|
+
// Undo the changes done in the PeerConnection, otherwise it gets out of
|
|
556
|
+
// sync with the remote SDP and later calls to send() and
|
|
557
|
+
// sendDataChannel() fail.
|
|
558
|
+
try {
|
|
559
|
+
if (this._pc.signalingState === 'have-local-offer') {
|
|
560
|
+
try {
|
|
561
|
+
await this._pc.setLocalDescription({ type: 'rollback' });
|
|
562
|
+
}
|
|
563
|
+
catch (error2) { }
|
|
564
|
+
}
|
|
565
|
+
dataChannel.close();
|
|
566
|
+
}
|
|
567
|
+
catch (error3) { }
|
|
568
|
+
throw error;
|
|
525
569
|
}
|
|
526
|
-
logger.debug('sendDataChannel() | calling pc.setLocalDescription() [offer:%o]', offer);
|
|
527
|
-
await this._pc.setLocalDescription(offer);
|
|
528
|
-
this._remoteSdp.sendSctpAssociation({ offerMediaObject });
|
|
529
|
-
const answer = {
|
|
530
|
-
type: 'answer',
|
|
531
|
-
sdp: this._remoteSdp.getSdp(),
|
|
532
|
-
};
|
|
533
|
-
logger.debug('sendDataChannel() | calling pc.setRemoteDescription() [answer:%o]', answer);
|
|
534
|
-
await this._pc.setRemoteDescription(answer);
|
|
535
|
-
this._hasDataChannelMediaSection = true;
|
|
536
570
|
}
|
|
537
571
|
const newSctpStreamParameters = {
|
|
538
572
|
streamId: options.id,
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
package/lib/ortc.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ortc.d.ts","sourceRoot":"","sources":["../src/ortc.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,eAAe,EACf,SAAS,EACT,kBAAkB,EAElB,aAAa,EACb,kBAAkB,EAKlB,uBAAuB,EAGvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAO7D;;;;GAIG;AACH,wBAAgB,mCAAmC,CAClD,IAAI,EAAE,eAAe,GACnB,IAAI,CA0BN;AAED;;;;GAIG;AACH,wBAAgB,iCAAiC,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAiD7E;AAED;;;;GAIG;AACH,wBAAgB,wCAAwC,CACvD,MAAM,EAAE,oBAAoB,GAC1B,IAAI,
|
|
1
|
+
{"version":3,"file":"ortc.d.ts","sourceRoot":"","sources":["../src/ortc.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,eAAe,EACf,SAAS,EACT,kBAAkB,EAElB,aAAa,EACb,kBAAkB,EAKlB,uBAAuB,EAGvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAO7D;;;;GAIG;AACH,wBAAgB,mCAAmC,CAClD,IAAI,EAAE,eAAe,GACnB,IAAI,CA0BN;AAED;;;;GAIG;AACH,wBAAgB,iCAAiC,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAiD7E;AAED;;;;GAIG;AACH,wBAAgB,wCAAwC,CACvD,MAAM,EAAE,oBAAoB,GAC1B,IAAI,CAsEN;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CACzC,SAAS,EAAE,eAAe,EAC1B,UAAU,EAAE,eAAe,EAC3B,sBAAsB,EAAE,OAAO,GAC7B,uBAAuB,CAiJzB;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACrC,uBAAuB,EAAE,uBAAuB,GAC9C,eAAe,CAEjB;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACrC,uBAAuB,EAAE,uBAAuB,GAC9C,eAAe,CAEjB;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACtC,IAAI,EAAE,SAAS,EACf,uBAAuB,EAAE,uBAAuB,GAC9C,aAAa,CA8Df;AAED;;GAEG;AACH,wBAAgB,6BAA6B,CAC5C,IAAI,EAAE,SAAS,EACf,uBAAuB,EAAE,uBAAuB,GAC9C,aAAa,CA+Ff;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAC3B,MAAM,EAAE,kBAAkB,EAAE,EAC5B,QAAQ,CAAC,EAAE,kBAAkB,GAC3B,kBAAkB,EAAE,CA+BtB;AAED;;GAEG;AACH,wBAAgB,6BAA6B,CAC5C,kBAAkB,EAAE,aAAa,GAC/B,aAAa,CAoBf;AAED;;GAEG;AACH,wBAAgB,OAAO,CACtB,IAAI,EAAE,SAAS,EACf,eAAe,EAAE,eAAe,GAC9B,OAAO,CAET;AAED;;;GAGG;AACH,wBAAgB,UAAU,CACzB,aAAa,EAAE,aAAa,EAC5B,eAAe,EAAE,eAAe,GAC9B,OAAO,CAaT"}
|
package/lib/ortc.js
CHANGED
|
@@ -151,24 +151,28 @@ function validateAndNormalizeSctpStreamParameters(params) {
|
|
|
151
151
|
params.ordered = true;
|
|
152
152
|
}
|
|
153
153
|
// maxPacketLifeTime is optional.
|
|
154
|
-
if (params.maxPacketLifeTime &&
|
|
154
|
+
if (params.maxPacketLifeTime !== undefined &&
|
|
155
155
|
typeof params.maxPacketLifeTime !== 'number') {
|
|
156
156
|
throw new TypeError('invalid params.maxPacketLifeTime');
|
|
157
157
|
}
|
|
158
158
|
// maxRetransmits is optional.
|
|
159
|
-
if (params.maxRetransmits
|
|
159
|
+
if (params.maxRetransmits !== undefined &&
|
|
160
|
+
typeof params.maxRetransmits !== 'number') {
|
|
160
161
|
throw new TypeError('invalid params.maxRetransmits');
|
|
161
162
|
}
|
|
162
|
-
if (params.maxPacketLifeTime
|
|
163
|
+
if (params.maxPacketLifeTime !== undefined &&
|
|
164
|
+
params.maxRetransmits !== undefined) {
|
|
163
165
|
throw new TypeError('cannot provide both maxPacketLifeTime and maxRetransmits');
|
|
164
166
|
}
|
|
165
167
|
if (orderedGiven &&
|
|
166
168
|
params.ordered &&
|
|
167
|
-
(params.maxPacketLifeTime
|
|
169
|
+
(params.maxPacketLifeTime !== undefined ||
|
|
170
|
+
params.maxRetransmits !== undefined)) {
|
|
168
171
|
throw new TypeError('cannot be ordered with maxPacketLifeTime or maxRetransmits');
|
|
169
172
|
}
|
|
170
173
|
else if (!orderedGiven &&
|
|
171
|
-
(params.maxPacketLifeTime
|
|
174
|
+
(params.maxPacketLifeTime !== undefined ||
|
|
175
|
+
params.maxRetransmits !== undefined)) {
|
|
172
176
|
params.ordered = false;
|
|
173
177
|
}
|
|
174
178
|
// label is optional.
|
package/lib/test/test.js
CHANGED
|
@@ -761,6 +761,31 @@ test('transport.produceData() succeeds', async () => {
|
|
|
761
761
|
expect(dataProducer.label).toBe('FOO');
|
|
762
762
|
expect(dataProducer.protocol).toBe('BAR');
|
|
763
763
|
}, 500);
|
|
764
|
+
test('transport.produceData() with maxRetransmits 0 or maxPacketLifeTime 0 creates an unordered DataProducer', async () => {
|
|
765
|
+
const dataProducer1 = await ctx.connectedSendTransport.produceData({
|
|
766
|
+
maxRetransmits: 0,
|
|
767
|
+
});
|
|
768
|
+
expect(dataProducer1.sctpStreamParameters.ordered).toBe(false);
|
|
769
|
+
expect(dataProducer1.sctpStreamParameters.maxRetransmits).toBe(0);
|
|
770
|
+
const dataProducer2 = await ctx.connectedSendTransport.produceData({
|
|
771
|
+
maxPacketLifeTime: 0,
|
|
772
|
+
});
|
|
773
|
+
expect(dataProducer2.sctpStreamParameters.ordered).toBe(false);
|
|
774
|
+
expect(dataProducer2.sctpStreamParameters.maxPacketLifeTime).toBe(0);
|
|
775
|
+
}, 500);
|
|
776
|
+
test('transport.produceData() closes the DataChannel if the "producedata" listener rejects', async () => {
|
|
777
|
+
const handlerSpy = jest.spyOn(ctx.connectedSendTransport.handler, 'sendDataChannel');
|
|
778
|
+
const error = new Error('produceData() failed');
|
|
779
|
+
const listener = (parameters, callback, errback) => {
|
|
780
|
+
errback(error);
|
|
781
|
+
};
|
|
782
|
+
ctx.connectedSendTransport.prependListener('producedata', listener);
|
|
783
|
+
await expect(ctx.connectedSendTransport.produceData()).rejects.toThrow(error);
|
|
784
|
+
const { dataChannel } = await handlerSpy.mock.results[0].value;
|
|
785
|
+
expect(dataChannel.readyState).toBe('closed');
|
|
786
|
+
ctx.connectedSendTransport.off('producedata', listener);
|
|
787
|
+
handlerSpy.mockRestore();
|
|
788
|
+
}, 500);
|
|
764
789
|
test('transport.produceData() in a receiving Transport rejects with UnsupportedError', async () => {
|
|
765
790
|
await expect(ctx.recvTransport.produceData({})).rejects.toThrow(errors_1.UnsupportedError);
|
|
766
791
|
}, 500);
|
|
@@ -904,7 +929,7 @@ test('producer.replaceTrack() with a new track succeeds', async () => {
|
|
|
904
929
|
const videoProducerPreviousTrack = ctx.videoProducer.track;
|
|
905
930
|
const newVideoTrack = new fake_mediastreamtrack_1.FakeMediaStreamTrack({ kind: 'video' });
|
|
906
931
|
await expect(ctx.videoProducer.replaceTrack({ track: newVideoTrack })).resolves.toBe(undefined);
|
|
907
|
-
// Previous track must be 'ended' due to stopTracks: true.
|
|
932
|
+
// Previous track must be 'ended' due to stopTracks: true (default value).
|
|
908
933
|
expect(videoProducerPreviousTrack?.readyState).toBe('ended');
|
|
909
934
|
expect(ctx.videoProducer.track).not.toBe(videoProducerPreviousTrack);
|
|
910
935
|
expect(ctx.videoProducer.track).toBe(newVideoTrack);
|
|
@@ -949,6 +974,34 @@ test('producer.setMaxSpatialLayer() succeeds', async () => {
|
|
|
949
974
|
await expect(ctx.videoProducer.setMaxSpatialLayer(0)).resolves.toBe(undefined);
|
|
950
975
|
expect(ctx.videoProducer.maxSpatialLayer).toBe(0);
|
|
951
976
|
}, 500);
|
|
977
|
+
test('producer.replaceTrack() rejects with InvalidStateError and stops the new track if the Producer is closed while replacing', async () => {
|
|
978
|
+
const previousTrack = ctx.videoProducer.track;
|
|
979
|
+
const newTrack = new fake_mediastreamtrack_1.FakeMediaStreamTrack({ kind: 'video' });
|
|
980
|
+
const replacePromise = ctx.videoProducer.replaceTrack({ track: newTrack });
|
|
981
|
+
ctx.videoProducer.close();
|
|
982
|
+
await expect(replacePromise).rejects.toThrow(errors_1.InvalidStateError);
|
|
983
|
+
expect(previousTrack?.readyState).toBe('ended');
|
|
984
|
+
// The new track must be 'ended' due to stopTracks: true (default value).
|
|
985
|
+
expect(newTrack.readyState).toBe('ended');
|
|
986
|
+
expect(ctx.videoProducer.track).toBe(previousTrack);
|
|
987
|
+
}, 500);
|
|
988
|
+
test('producer.replaceTrack() stops the new track if the Transport is closed while replacing', async () => {
|
|
989
|
+
const newTrack = new fake_mediastreamtrack_1.FakeMediaStreamTrack({ kind: 'video' });
|
|
990
|
+
const replacePromise = ctx.videoProducer.replaceTrack({ track: newTrack });
|
|
991
|
+
ctx.connectedSendTransport.close();
|
|
992
|
+
await expect(replacePromise).rejects.toThrow();
|
|
993
|
+
// The new track must be 'ended' due to stopTracks: true (default value).
|
|
994
|
+
expect(newTrack.readyState).toBe('ended');
|
|
995
|
+
}, 500);
|
|
996
|
+
test('producer.setMaxSpatialLayer() rejects and keeps the previous value if the handler fails', async () => {
|
|
997
|
+
const previousMaxSpatialLayer = ctx.videoProducer.maxSpatialLayer;
|
|
998
|
+
const error = new Error('setParameters() failed');
|
|
999
|
+
const handlerSpy = jest.spyOn(ctx.connectedSendTransport.handler, 'setMaxSpatialLayer');
|
|
1000
|
+
handlerSpy.mockRejectedValueOnce(error);
|
|
1001
|
+
await expect(ctx.videoProducer.setMaxSpatialLayer(1)).rejects.toThrow(error);
|
|
1002
|
+
expect(ctx.videoProducer.maxSpatialLayer).toBe(previousMaxSpatialLayer);
|
|
1003
|
+
handlerSpy.mockRestore();
|
|
1004
|
+
}, 500);
|
|
952
1005
|
test('producer.setMaxSpatialLayer() in an audio Producer rejects with UnsupportedError', async () => {
|
|
953
1006
|
await expect(ctx.audioProducer.setMaxSpatialLayer(1)).rejects.toThrow(errors_1.UnsupportedError);
|
|
954
1007
|
expect(ctx.audioProducer.maxSpatialLayer).toBe(undefined);
|
|
@@ -1083,6 +1136,12 @@ test('transport.produce() rejects with InvalidStateError if closed', async () =>
|
|
|
1083
1136
|
// The track must be 'live' due to stopTracks: false.
|
|
1084
1137
|
expect(track.readyState).toBe('live');
|
|
1085
1138
|
}, 500);
|
|
1139
|
+
test('transport.produce() stops the track if the Transport is closed', async () => {
|
|
1140
|
+
const track = new fake_mediastreamtrack_1.FakeMediaStreamTrack({ kind: 'audio' });
|
|
1141
|
+
ctx.connectedSendTransport.close();
|
|
1142
|
+
await expect(ctx.connectedSendTransport.produce({ track })).rejects.toThrow(errors_1.InvalidStateError);
|
|
1143
|
+
expect(track.readyState).toBe('ended');
|
|
1144
|
+
}, 500);
|
|
1086
1145
|
test('transport.consume() rejects with InvalidStateError if closed', async () => {
|
|
1087
1146
|
ctx.connectedRecvTransport.close();
|
|
1088
1147
|
// @ts-expect-error --- On purpose.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mediasoup-client",
|
|
3
|
-
"version": "3.24.
|
|
3
|
+
"version": "3.24.4",
|
|
4
4
|
"description": "mediasoup client side TypeScript library",
|
|
5
5
|
"contributors": [
|
|
6
6
|
"Iñaki Baz Castillo <ibc@aliax.net> (https://inakibaz.me)",
|
|
@@ -91,13 +91,13 @@
|
|
|
91
91
|
"eslint-config-prettier": "^10.1.8",
|
|
92
92
|
"eslint-plugin-jest": "^29.16.6",
|
|
93
93
|
"eslint-plugin-prettier": "^5.5.6",
|
|
94
|
-
"globals": "^17.
|
|
94
|
+
"globals": "^17.13.0",
|
|
95
95
|
"jest": "^30.5.2",
|
|
96
|
-
"knip": "^6.
|
|
96
|
+
"knip": "^6.39.0",
|
|
97
97
|
"open-cli": "^9.0.0",
|
|
98
98
|
"prettier": "^3.9.9",
|
|
99
|
-
"ts-jest": "^29.4.
|
|
99
|
+
"ts-jest": "^29.4.14",
|
|
100
100
|
"typescript": "^6.0.3",
|
|
101
|
-
"typescript-eslint": "^8.
|
|
101
|
+
"typescript-eslint": "^8.71.0"
|
|
102
102
|
}
|
|
103
103
|
}
|