mediasoup-client 3.24.1 → 3.24.3
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 +149 -112
- 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 +3 -3
package/lib/handlers/Safari12.js
CHANGED
|
@@ -244,109 +244,128 @@ class Safari12 extends enhancedEvents_1.EnhancedEventEmitter {
|
|
|
244
244
|
streams: [this._sendStream],
|
|
245
245
|
sendEncodings: encodings,
|
|
246
246
|
});
|
|
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
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
247
|
+
try {
|
|
248
|
+
if (this._forcedRtpExtensions) {
|
|
249
|
+
ortcUtils.applyForcedRtpExtensions(transceiver, this._forcedRtpExtensions);
|
|
250
|
+
}
|
|
251
|
+
if (onRtpSender) {
|
|
252
|
+
onRtpSender(transceiver.sender);
|
|
253
|
+
}
|
|
254
|
+
let offer = await this._pc.createOffer();
|
|
255
|
+
let localSdpObject = sdpTransform.parse(offer.sdp);
|
|
256
|
+
if (localSdpObject.extmapAllowMixed) {
|
|
257
|
+
this._remoteSdp.setSessionExtmapAllowMixed();
|
|
258
|
+
}
|
|
259
|
+
const nativeRtpCapabilities = Safari12.getLocalRtpCapabilities(localSdpObject);
|
|
260
|
+
const sendExtendedRtpCapabilities = this._getSendExtendedRtpCapabilities(nativeRtpCapabilities);
|
|
261
|
+
// Generic sending RTP parameters.
|
|
262
|
+
const sendingRtpParameters = ortc.getSendingRtpParameters(track.kind, sendExtendedRtpCapabilities);
|
|
263
|
+
// This may throw.
|
|
264
|
+
sendingRtpParameters.codecs = ortc.reduceCodecs(sendingRtpParameters.codecs, codec);
|
|
265
|
+
// Generic sending RTP parameters suitable for the SDP remote answer.
|
|
266
|
+
const sendingRemoteRtpParameters = ortc.getSendingRemoteRtpParameters(track.kind, sendExtendedRtpCapabilities);
|
|
267
|
+
// This may throw.
|
|
268
|
+
sendingRemoteRtpParameters.codecs = ortc.reduceCodecs(sendingRemoteRtpParameters.codecs, codec);
|
|
269
|
+
let offerMediaObject;
|
|
270
|
+
if (!this._transportReady) {
|
|
271
|
+
await this.setupTransport({
|
|
272
|
+
localDtlsRole: this._forcedLocalDtlsRole ?? 'client',
|
|
273
|
+
localSdpObject,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
const layers = (0, scalabilityModes_1.parse)((encodings ?? [{}])[0].scalabilityMode);
|
|
277
|
+
if (encodings && encodings.length > 1) {
|
|
278
|
+
logger.debug('send() | enabling legacy simulcast');
|
|
279
|
+
localSdpObject = sdpTransform.parse(offer.sdp);
|
|
280
|
+
offerMediaObject = localSdpObject.media[mediaSectionIdx.idx];
|
|
281
|
+
sdpUnifiedPlanUtils.addLegacySimulcast({
|
|
282
|
+
offerMediaObject,
|
|
283
|
+
numStreams: encodings.length,
|
|
284
|
+
});
|
|
285
|
+
offer = {
|
|
286
|
+
type: 'offer',
|
|
287
|
+
sdp: sdpTransform.write(localSdpObject),
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
logger.debug('send() | calling pc.setLocalDescription() [offer:%o]', offer);
|
|
291
|
+
await this._pc.setLocalDescription(offer);
|
|
292
|
+
// We can now get the transceiver.mid.
|
|
293
|
+
const localId = transceiver.mid;
|
|
294
|
+
// Set MID.
|
|
295
|
+
sendingRtpParameters.mid = localId;
|
|
296
|
+
localSdpObject = sdpTransform.parse(this._pc.localDescription.sdp);
|
|
279
297
|
offerMediaObject = localSdpObject.media[mediaSectionIdx.idx];
|
|
280
|
-
|
|
298
|
+
// Set RTCP CNAME.
|
|
299
|
+
sendingRtpParameters.rtcp.cname = sdpCommonUtils.getCname({
|
|
281
300
|
offerMediaObject,
|
|
282
|
-
numStreams: encodings.length,
|
|
283
301
|
});
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
// Set RTCP CNAME.
|
|
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]);
|
|
302
|
+
// Set msid.
|
|
303
|
+
sendingRtpParameters.msid = `${streamId ?? this._sendStream.id} ${track.id}`;
|
|
304
|
+
// Set RTP encodings.
|
|
305
|
+
sendingRtpParameters.encodings = sdpUnifiedPlanUtils.getRtpEncodings({
|
|
306
|
+
offerMediaObject,
|
|
307
|
+
codecs: sendingRtpParameters.codecs,
|
|
308
|
+
});
|
|
309
|
+
// Complete encodings with given values.
|
|
310
|
+
if (encodings) {
|
|
311
|
+
for (let idx = 0; idx < sendingRtpParameters.encodings.length; ++idx) {
|
|
312
|
+
if (encodings[idx]) {
|
|
313
|
+
Object.assign(sendingRtpParameters.encodings[idx], encodings[idx]);
|
|
314
|
+
}
|
|
313
315
|
}
|
|
314
316
|
}
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
encoding.scalabilityMode
|
|
317
|
+
// If VP8 or H264 and there is effective simulcast, add scalabilityMode to
|
|
318
|
+
// each encoding.
|
|
319
|
+
if (sendingRtpParameters.encodings.length > 1 &&
|
|
320
|
+
(sendingRtpParameters.codecs[0].mimeType.toLowerCase() ===
|
|
321
|
+
'video/vp8' ||
|
|
322
|
+
sendingRtpParameters.codecs[0].mimeType.toLowerCase() ===
|
|
323
|
+
'video/h264')) {
|
|
324
|
+
for (const encoding of sendingRtpParameters.encodings) {
|
|
325
|
+
if (encoding.scalabilityMode) {
|
|
326
|
+
encoding.scalabilityMode = `L1T${layers.temporalLayers}`;
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
encoding.scalabilityMode = 'L1T3';
|
|
330
|
+
}
|
|
324
331
|
}
|
|
325
|
-
|
|
326
|
-
|
|
332
|
+
}
|
|
333
|
+
this._remoteSdp.send({
|
|
334
|
+
offerMediaObject,
|
|
335
|
+
reuseMid: mediaSectionIdx.reuseMid,
|
|
336
|
+
offerRtpParameters: sendingRtpParameters,
|
|
337
|
+
answerRtpParameters: sendingRemoteRtpParameters,
|
|
338
|
+
codecOptions,
|
|
339
|
+
});
|
|
340
|
+
const answer = {
|
|
341
|
+
type: 'answer',
|
|
342
|
+
sdp: this._remoteSdp.getSdp(),
|
|
343
|
+
};
|
|
344
|
+
logger.debug('send() | calling pc.setRemoteDescription() [answer:%o]', answer);
|
|
345
|
+
await this._pc.setRemoteDescription(answer);
|
|
346
|
+
// Store in the map.
|
|
347
|
+
this._mapMidTransceiver.set(localId, transceiver);
|
|
348
|
+
return {
|
|
349
|
+
localId,
|
|
350
|
+
rtpParameters: sendingRtpParameters,
|
|
351
|
+
rtpSender: transceiver.sender,
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
catch (error) {
|
|
355
|
+
// Undo the changes done in the PeerConnection, otherwise it gets out of
|
|
356
|
+
// sync with the remote SDP and later calls to send() fail.
|
|
357
|
+
try {
|
|
358
|
+
if (this._pc.signalingState === 'have-local-offer') {
|
|
359
|
+
try {
|
|
360
|
+
await this._pc.setLocalDescription({ type: 'rollback' });
|
|
361
|
+
}
|
|
362
|
+
catch (error2) { }
|
|
327
363
|
}
|
|
364
|
+
transceiver.stop();
|
|
328
365
|
}
|
|
366
|
+
catch (error3) { }
|
|
367
|
+
throw error;
|
|
329
368
|
}
|
|
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
369
|
}
|
|
351
370
|
async stopSending(localId) {
|
|
352
371
|
this.assertSendDirection();
|
|
@@ -514,25 +533,43 @@ class Safari12 extends enhancedEvents_1.EnhancedEventEmitter {
|
|
|
514
533
|
// If this is the first DataChannel we need to create the SDP answer with
|
|
515
534
|
// m=application section.
|
|
516
535
|
if (!this._hasDataChannelMediaSection) {
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
536
|
+
try {
|
|
537
|
+
const offer = await this._pc.createOffer();
|
|
538
|
+
const localSdpObject = sdpTransform.parse(offer.sdp);
|
|
539
|
+
const offerMediaObject = localSdpObject.media.find(m => m.type === 'application');
|
|
540
|
+
if (!this._transportReady) {
|
|
541
|
+
await this.setupTransport({
|
|
542
|
+
localDtlsRole: this._forcedLocalDtlsRole ?? 'client',
|
|
543
|
+
localSdpObject,
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
logger.debug('sendDataChannel() | calling pc.setLocalDescription() [offer:%o]', offer);
|
|
547
|
+
await this._pc.setLocalDescription(offer);
|
|
548
|
+
this._remoteSdp.sendSctpAssociation({ offerMediaObject });
|
|
549
|
+
const answer = {
|
|
550
|
+
type: 'answer',
|
|
551
|
+
sdp: this._remoteSdp.getSdp(),
|
|
552
|
+
};
|
|
553
|
+
logger.debug('sendDataChannel() | calling pc.setRemoteDescription() [answer:%o]', answer);
|
|
554
|
+
await this._pc.setRemoteDescription(answer);
|
|
555
|
+
this._hasDataChannelMediaSection = true;
|
|
556
|
+
}
|
|
557
|
+
catch (error) {
|
|
558
|
+
// Undo the changes done in the PeerConnection, otherwise it gets out of
|
|
559
|
+
// sync with the remote SDP and later calls to send() and
|
|
560
|
+
// sendDataChannel() fail.
|
|
561
|
+
try {
|
|
562
|
+
if (this._pc.signalingState === 'have-local-offer') {
|
|
563
|
+
try {
|
|
564
|
+
await this._pc.setLocalDescription({ type: 'rollback' });
|
|
565
|
+
}
|
|
566
|
+
catch (error2) { }
|
|
567
|
+
}
|
|
568
|
+
dataChannel.close();
|
|
569
|
+
}
|
|
570
|
+
catch (error3) { }
|
|
571
|
+
throw error;
|
|
525
572
|
}
|
|
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
573
|
}
|
|
537
574
|
const newSctpStreamParameters = {
|
|
538
575
|
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.3",
|
|
4
4
|
"description": "mediasoup client side TypeScript library",
|
|
5
5
|
"contributors": [
|
|
6
6
|
"Iñaki Baz Castillo <ibc@aliax.net> (https://inakibaz.me)",
|
|
@@ -96,8 +96,8 @@
|
|
|
96
96
|
"knip": "^6.38.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
|
}
|