livekit-client 1.14.1 → 1.14.3
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/livekit-client.e2ee.worker.js +1 -1
- package/dist/livekit-client.e2ee.worker.js.map +1 -1
- package/dist/livekit-client.e2ee.worker.mjs +25 -44
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +555 -306
- package/dist/livekit-client.esm.mjs.map +1 -1
- package/dist/livekit-client.umd.js +1 -1
- package/dist/livekit-client.umd.js.map +1 -1
- package/dist/src/e2ee/E2eeManager.d.ts.map +1 -1
- package/dist/src/e2ee/utils.d.ts +0 -1
- package/dist/src/e2ee/utils.d.ts.map +1 -1
- package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
- package/dist/src/e2ee/worker/ParticipantKeyHandler.d.ts.map +1 -1
- package/dist/src/proto/livekit_models_pb.d.ts +87 -11
- package/dist/src/proto/livekit_models_pb.d.ts.map +1 -1
- package/dist/src/proto/livekit_rtc_pb.d.ts +0 -4
- package/dist/src/proto/livekit_rtc_pb.d.ts.map +1 -1
- package/dist/src/room/PCTransport.d.ts +20 -1
- package/dist/src/room/PCTransport.d.ts.map +1 -1
- package/dist/src/room/RTCEngine.d.ts +1 -1
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts +1 -1
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/defaults.d.ts +1 -0
- package/dist/src/room/defaults.d.ts.map +1 -1
- package/dist/src/room/events.d.ts +3 -1
- package/dist/src/room/events.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/participant/Participant.d.ts +1 -0
- package/dist/src/room/participant/Participant.d.ts.map +1 -1
- package/dist/src/room/timers.d.ts +1 -1
- package/dist/src/room/timers.d.ts.map +1 -1
- package/dist/src/room/track/LocalAudioTrack.d.ts +1 -1
- package/dist/src/room/track/LocalAudioTrack.d.ts.map +1 -1
- package/dist/src/room/track/LocalTrack.d.ts +3 -3
- package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
- package/dist/src/room/track/LocalVideoTrack.d.ts +2 -1
- package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -1
- package/dist/src/room/track/Track.d.ts.map +1 -1
- package/dist/src/room/track/options.d.ts +0 -1
- package/dist/src/room/track/options.d.ts.map +1 -1
- package/dist/src/room/track/utils.d.ts +2 -1
- package/dist/src/room/track/utils.d.ts.map +1 -1
- package/dist/src/utils/cloneDeep.d.ts +2 -0
- package/dist/src/utils/cloneDeep.d.ts.map +1 -0
- package/dist/ts4.2/src/e2ee/utils.d.ts +0 -1
- package/dist/ts4.2/src/proto/livekit_models_pb.d.ts +87 -11
- package/dist/ts4.2/src/proto/livekit_rtc_pb.d.ts +0 -4
- package/dist/ts4.2/src/room/PCTransport.d.ts +20 -1
- package/dist/ts4.2/src/room/RTCEngine.d.ts +1 -1
- package/dist/ts4.2/src/room/Room.d.ts +1 -1
- package/dist/ts4.2/src/room/defaults.d.ts +1 -0
- package/dist/ts4.2/src/room/events.d.ts +3 -1
- package/dist/ts4.2/src/room/participant/Participant.d.ts +1 -0
- package/dist/ts4.2/src/room/timers.d.ts +1 -1
- package/dist/ts4.2/src/room/track/LocalAudioTrack.d.ts +1 -1
- package/dist/ts4.2/src/room/track/LocalTrack.d.ts +3 -3
- package/dist/ts4.2/src/room/track/LocalVideoTrack.d.ts +2 -1
- package/dist/ts4.2/src/room/track/options.d.ts +0 -1
- package/dist/ts4.2/src/room/track/utils.d.ts +1 -0
- package/dist/ts4.2/src/utils/cloneDeep.d.ts +2 -0
- package/package.json +15 -15
- package/src/connectionHelper/checks/webrtc.ts +1 -1
- package/src/e2ee/E2eeManager.ts +2 -1
- package/src/e2ee/utils.ts +0 -10
- package/src/e2ee/worker/FrameCryptor.ts +13 -14
- package/src/e2ee/worker/ParticipantKeyHandler.ts +4 -5
- package/src/e2ee/worker/e2ee.worker.ts +3 -1
- package/src/proto/livekit_models_pb.ts +140 -15
- package/src/proto/livekit_rtc_pb.ts +1 -7
- package/src/room/PCTransport.ts +122 -5
- package/src/room/RTCEngine.ts +56 -92
- package/src/room/Room.ts +14 -11
- package/src/room/defaults.ts +4 -2
- package/src/room/events.ts +5 -1
- package/src/room/participant/LocalParticipant.ts +47 -68
- package/src/room/participant/Participant.ts +1 -0
- package/src/room/track/LocalAudioTrack.ts +1 -1
- package/src/room/track/LocalTrack.ts +8 -5
- package/src/room/track/LocalVideoTrack.ts +2 -1
- package/src/room/track/Track.ts +6 -1
- package/src/room/track/options.ts +0 -7
- package/src/room/track/utils.ts +17 -8
- package/src/utils/cloneDeep.test.ts +54 -0
- package/src/utils/cloneDeep.ts +11 -0
package/src/room/RTCEngine.ts
CHANGED
@@ -108,7 +108,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
108
108
|
|
109
109
|
private subscriberPrimary: boolean = false;
|
110
110
|
|
111
|
-
private
|
111
|
+
private primaryTransport?: PCTransport;
|
112
112
|
|
113
113
|
private pcState: PCState = PCState.New;
|
114
114
|
|
@@ -247,12 +247,12 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
247
247
|
}
|
248
248
|
|
249
249
|
async cleanupPeerConnections() {
|
250
|
-
if (this.publisher && this.publisher.
|
251
|
-
this.publisher.
|
250
|
+
if (this.publisher && this.publisher.getSignallingState() !== 'closed') {
|
251
|
+
this.publisher.getSenders().forEach((sender) => {
|
252
252
|
try {
|
253
253
|
// TODO: react-native-webrtc doesn't have removeTrack yet.
|
254
|
-
if (this.publisher?.
|
255
|
-
this.publisher?.
|
254
|
+
if (this.publisher?.canRemoveTrack()) {
|
255
|
+
this.publisher?.removeTrack(sender);
|
256
256
|
}
|
257
257
|
} catch (e) {
|
258
258
|
log.warn('could not removeTrack', { error: e });
|
@@ -268,7 +268,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
268
268
|
this.subscriber = undefined;
|
269
269
|
}
|
270
270
|
this.hasPublished = false;
|
271
|
-
this.
|
271
|
+
this.primaryTransport = undefined;
|
272
272
|
|
273
273
|
const dcCleanup = (dc: RTCDataChannel | undefined) => {
|
274
274
|
if (!dc) return;
|
@@ -336,7 +336,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
336
336
|
delete this.pendingTrackResolvers[sender.track.id];
|
337
337
|
}
|
338
338
|
try {
|
339
|
-
this.publisher?.
|
339
|
+
this.publisher?.removeTrack(sender);
|
340
340
|
return true;
|
341
341
|
} catch (e: unknown) {
|
342
342
|
log.warn('failed to remove track', { error: e, method: 'removeTrack' });
|
@@ -353,10 +353,10 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
353
353
|
}
|
354
354
|
|
355
355
|
async getConnectedServerAddress(): Promise<string | undefined> {
|
356
|
-
if (this.
|
356
|
+
if (this.primaryTransport === undefined) {
|
357
357
|
return undefined;
|
358
358
|
}
|
359
|
-
return getConnectedAddress(
|
359
|
+
return this.primaryTransport.getConnectedAddress();
|
360
360
|
}
|
361
361
|
|
362
362
|
/* @internal */
|
@@ -374,53 +374,44 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
374
374
|
|
375
375
|
const rtcConfig = this.makeRTCConfiguration(joinResponse);
|
376
376
|
|
377
|
-
if (this.signalOpts?.e2eeEnabled) {
|
378
|
-
log.debug('E2EE - setting up transports with insertable streams');
|
379
|
-
// this makes sure that no data is sent before the transforms are ready
|
380
|
-
// @ts-ignore
|
381
|
-
rtcConfig.encodedInsertableStreams = true;
|
382
|
-
}
|
383
|
-
|
384
377
|
const googConstraints = { optional: [{ googDscp: true }] };
|
385
378
|
this.publisher = new PCTransport(rtcConfig, googConstraints);
|
386
379
|
this.subscriber = new PCTransport(rtcConfig);
|
387
380
|
|
388
381
|
this.emit(EngineEvent.TransportsCreated, this.publisher, this.subscriber);
|
389
382
|
|
390
|
-
this.publisher.
|
391
|
-
|
392
|
-
|
393
|
-
this.client.sendIceCandidate(ev.candidate, SignalTarget.PUBLISHER);
|
383
|
+
this.publisher.onIceCandidate = (candidate) => {
|
384
|
+
log.trace('adding ICE candidate for peer', candidate);
|
385
|
+
this.client.sendIceCandidate(candidate, SignalTarget.PUBLISHER);
|
394
386
|
};
|
395
387
|
|
396
|
-
this.subscriber.
|
397
|
-
|
398
|
-
this.client.sendIceCandidate(ev.candidate, SignalTarget.SUBSCRIBER);
|
388
|
+
this.subscriber.onIceCandidate = (candidate) => {
|
389
|
+
this.client.sendIceCandidate(candidate, SignalTarget.SUBSCRIBER);
|
399
390
|
};
|
400
391
|
|
401
392
|
this.publisher.onOffer = (offer) => {
|
402
393
|
this.client.sendOffer(offer);
|
403
394
|
};
|
404
395
|
|
405
|
-
let
|
406
|
-
let
|
396
|
+
let primaryTransport = this.publisher;
|
397
|
+
let secondaryTransport = this.subscriber;
|
407
398
|
let subscriberPrimary = joinResponse.subscriberPrimary;
|
408
399
|
if (subscriberPrimary) {
|
409
|
-
|
410
|
-
|
400
|
+
primaryTransport = this.subscriber;
|
401
|
+
secondaryTransport = this.publisher;
|
411
402
|
// in subscriber primary mode, server side opens sub data channels.
|
412
|
-
this.subscriber.
|
403
|
+
this.subscriber.onDataChannel = this.handleDataChannel;
|
413
404
|
}
|
414
|
-
this.
|
415
|
-
|
416
|
-
log.debug(`primary PC state changed ${
|
417
|
-
if (
|
405
|
+
this.primaryTransport = primaryTransport;
|
406
|
+
primaryTransport.onConnectionStateChange = async (connectionState) => {
|
407
|
+
log.debug(`primary PC state changed ${connectionState}`);
|
408
|
+
if (connectionState === 'connected') {
|
418
409
|
const shouldEmit = this.pcState === PCState.New;
|
419
410
|
this.pcState = PCState.Connected;
|
420
411
|
if (shouldEmit) {
|
421
412
|
this.emit(EngineEvent.Connected, joinResponse);
|
422
413
|
}
|
423
|
-
} else if (
|
414
|
+
} else if (connectionState === 'failed') {
|
424
415
|
// on Safari, PeerConnection will switch to 'disconnected' during renegotiation
|
425
416
|
if (this.pcState === PCState.Connected) {
|
426
417
|
this.pcState = PCState.Disconnected;
|
@@ -434,10 +425,10 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
434
425
|
}
|
435
426
|
}
|
436
427
|
};
|
437
|
-
|
438
|
-
log.debug(`secondary PC state changed ${
|
428
|
+
secondaryTransport.onConnectionStateChange = async (connectionState) => {
|
429
|
+
log.debug(`secondary PC state changed ${connectionState}`);
|
439
430
|
// also reconnect if secondary peerconnection fails
|
440
|
-
if (
|
431
|
+
if (connectionState === 'failed') {
|
441
432
|
this.handleDisconnect(
|
442
433
|
'secondary peerconnection',
|
443
434
|
subscriberPrimary
|
@@ -447,7 +438,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
447
438
|
}
|
448
439
|
};
|
449
440
|
|
450
|
-
this.subscriber.
|
441
|
+
this.subscriber.onTrack = (ev: RTCTrackEvent) => {
|
451
442
|
this.emit(EngineEvent.MediaTrackAdded, ev.track, ev.streams[0], ev.receiver);
|
452
443
|
};
|
453
444
|
|
@@ -462,7 +453,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
462
453
|
}
|
463
454
|
log.debug('received server answer', {
|
464
455
|
RTCSdpType: sd.type,
|
465
|
-
signalingState: this.publisher.
|
456
|
+
signalingState: this.publisher.getSignallingState().toString(),
|
466
457
|
});
|
467
458
|
await this.publisher.setRemoteDescription(sd);
|
468
459
|
};
|
@@ -487,7 +478,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
487
478
|
}
|
488
479
|
log.debug('received server offer', {
|
489
480
|
RTCSdpType: sd.type,
|
490
|
-
signalingState: this.subscriber.
|
481
|
+
signalingState: this.subscriber.getSignallingState().toString(),
|
491
482
|
});
|
492
483
|
await this.subscriber.setRemoteDescription(sd);
|
493
484
|
|
@@ -518,7 +509,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
518
509
|
this.client.onLeave = (leave?: LeaveRequest) => {
|
519
510
|
if (leave?.canReconnect) {
|
520
511
|
this.fullReconnectOnNext = true;
|
521
|
-
this.
|
512
|
+
this.primaryTransport = undefined;
|
522
513
|
// reconnect immediately instead of waiting for next attempt
|
523
514
|
this.handleDisconnect(leaveReconnect);
|
524
515
|
} else {
|
@@ -531,6 +522,12 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
531
522
|
|
532
523
|
private makeRTCConfiguration(serverResponse: JoinResponse | ReconnectResponse): RTCConfiguration {
|
533
524
|
const rtcConfig = { ...this.rtcConfig };
|
525
|
+
if (this.signalOpts?.e2eeEnabled) {
|
526
|
+
log.debug('E2EE - setting up transports with insertable streams');
|
527
|
+
// this makes sure that no data is sent before the transforms are ready
|
528
|
+
// @ts-ignore
|
529
|
+
rtcConfig.encodedInsertableStreams = true;
|
530
|
+
}
|
534
531
|
|
535
532
|
// update ICE servers before creating PeerConnection
|
536
533
|
if (serverResponse.iceServers && !rtcConfig.iceServers) {
|
@@ -579,12 +576,12 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
579
576
|
}
|
580
577
|
|
581
578
|
// create data channels
|
582
|
-
this.lossyDC = this.publisher.
|
579
|
+
this.lossyDC = this.publisher.createDataChannel(lossyDataChannel, {
|
583
580
|
// will drop older packets that arrive
|
584
581
|
ordered: true,
|
585
582
|
maxRetransmits: 0,
|
586
583
|
});
|
587
|
-
this.reliableDC = this.publisher.
|
584
|
+
this.reliableDC = this.publisher.createDataChannel(reliableDataChannel, {
|
588
585
|
ordered: true,
|
589
586
|
});
|
590
587
|
|
@@ -765,7 +762,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
765
762
|
transceiverInit.sendEncodings = encodings;
|
766
763
|
}
|
767
764
|
// addTransceiver for react-native is async. web is synchronous, but await won't effect it.
|
768
|
-
const transceiver = await this.publisher.
|
765
|
+
const transceiver = await this.publisher.addTransceiver(
|
769
766
|
track.mediaStreamTrack,
|
770
767
|
transceiverInit,
|
771
768
|
);
|
@@ -791,7 +788,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
791
788
|
transceiverInit.sendEncodings = encodings;
|
792
789
|
}
|
793
790
|
// addTransceiver for react-native is async. web is synchronous, but await won't effect it.
|
794
|
-
const transceiver = await this.publisher.
|
791
|
+
const transceiver = await this.publisher.addTransceiver(
|
795
792
|
simulcastTrack.mediaStreamTrack,
|
796
793
|
transceiverInit,
|
797
794
|
);
|
@@ -807,7 +804,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
807
804
|
if (!this.publisher) {
|
808
805
|
throw new UnexpectedConnectionState('publisher is closed');
|
809
806
|
}
|
810
|
-
return this.publisher.
|
807
|
+
return this.publisher.addTrack(track);
|
811
808
|
}
|
812
809
|
|
813
810
|
// websocket reconnect behavior. if websocket is interrupted, and the PeerConnection
|
@@ -872,7 +869,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
872
869
|
this.clientConfiguration?.resumeConnection === ClientConfigSetting.DISABLED ||
|
873
870
|
// signaling state could change to closed due to hardware sleep
|
874
871
|
// those connections cannot be resumed
|
875
|
-
(this.
|
872
|
+
(this.primaryTransport?.getSignallingState() ?? 'closed') === 'closed'
|
876
873
|
) {
|
877
874
|
this.fullReconnectOnNext = true;
|
878
875
|
}
|
@@ -999,13 +996,14 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
999
996
|
const res = await this.client.reconnect(this.url, this.token, this.participantSid, reason);
|
1000
997
|
if (res) {
|
1001
998
|
const rtcConfig = this.makeRTCConfiguration(res);
|
1002
|
-
this.publisher.
|
1003
|
-
this.subscriber.
|
999
|
+
this.publisher.setConfiguration(rtcConfig);
|
1000
|
+
this.subscriber.setConfiguration(rtcConfig);
|
1004
1001
|
}
|
1005
1002
|
} catch (e) {
|
1006
1003
|
let message = '';
|
1007
1004
|
if (e instanceof Error) {
|
1008
1005
|
message = e.message;
|
1006
|
+
log.error(e.message);
|
1009
1007
|
}
|
1010
1008
|
if (e instanceof ConnectionError && e.reason === ConnectionErrorReason.NotAllowed) {
|
1011
1009
|
throw new UnexpectedConnectionState('could not reconnect, token might be expired');
|
@@ -1084,7 +1082,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
1084
1082
|
|
1085
1083
|
log.debug('waiting for peer connection to reconnect');
|
1086
1084
|
while (now - startTime < this.peerConnectionTimeout) {
|
1087
|
-
if (this.
|
1085
|
+
if (this.primaryTransport === undefined) {
|
1088
1086
|
// we can abort early, connection is hosed
|
1089
1087
|
break;
|
1090
1088
|
} else if (
|
@@ -1092,8 +1090,8 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
1092
1090
|
// this means we'd have to check its status manually and update address
|
1093
1091
|
// manually
|
1094
1092
|
now - startTime > minReconnectWait &&
|
1095
|
-
this.
|
1096
|
-
(!this.hasPublished || this.publisher?.
|
1093
|
+
this.primaryTransport?.getConnectionState() === 'connected' &&
|
1094
|
+
(!this.hasPublished || this.publisher?.getConnectionState() === 'connected')
|
1097
1095
|
) {
|
1098
1096
|
this.pcState = PCState.Connected;
|
1099
1097
|
}
|
@@ -1172,7 +1170,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
1172
1170
|
if (
|
1173
1171
|
!subscriber &&
|
1174
1172
|
!this.publisher?.isICEConnected &&
|
1175
|
-
this.publisher?.
|
1173
|
+
this.publisher?.getICEConnectionState() !== 'checking'
|
1176
1174
|
) {
|
1177
1175
|
// start negotiation
|
1178
1176
|
this.negotiate();
|
@@ -1196,7 +1194,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
1196
1194
|
}
|
1197
1195
|
|
1198
1196
|
throw new ConnectionError(
|
1199
|
-
`could not establish ${transportName} connection, state: ${transport.
|
1197
|
+
`could not establish ${transportName} connection, state: ${transport.getICEConnectionState()}`,
|
1200
1198
|
);
|
1201
1199
|
}
|
1202
1200
|
|
@@ -1207,12 +1205,12 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
1207
1205
|
/* @internal */
|
1208
1206
|
verifyTransport(): boolean {
|
1209
1207
|
// primary connection
|
1210
|
-
if (!this.
|
1208
|
+
if (!this.primaryTransport) {
|
1211
1209
|
return false;
|
1212
1210
|
}
|
1213
1211
|
if (
|
1214
|
-
this.
|
1215
|
-
this.
|
1212
|
+
this.primaryTransport.getConnectionState() === 'closed' ||
|
1213
|
+
this.primaryTransport.getConnectionState() === 'failed'
|
1216
1214
|
) {
|
1217
1215
|
return false;
|
1218
1216
|
}
|
@@ -1223,8 +1221,8 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
1223
1221
|
return false;
|
1224
1222
|
}
|
1225
1223
|
if (
|
1226
|
-
this.publisher.
|
1227
|
-
this.publisher.
|
1224
|
+
this.publisher.getConnectionState() === 'closed' ||
|
1225
|
+
this.publisher.getConnectionState() === 'failed'
|
1228
1226
|
) {
|
1229
1227
|
return false;
|
1230
1228
|
}
|
@@ -1355,40 +1353,6 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
1355
1353
|
}
|
1356
1354
|
}
|
1357
1355
|
|
1358
|
-
async function getConnectedAddress(pc: RTCPeerConnection): Promise<string | undefined> {
|
1359
|
-
let selectedCandidatePairId = '';
|
1360
|
-
const candidatePairs = new Map<string, RTCIceCandidatePairStats>();
|
1361
|
-
// id -> candidate ip
|
1362
|
-
const candidates = new Map<string, string>();
|
1363
|
-
const stats: RTCStatsReport = await pc.getStats();
|
1364
|
-
stats.forEach((v) => {
|
1365
|
-
switch (v.type) {
|
1366
|
-
case 'transport':
|
1367
|
-
selectedCandidatePairId = v.selectedCandidatePairId;
|
1368
|
-
break;
|
1369
|
-
case 'candidate-pair':
|
1370
|
-
if (selectedCandidatePairId === '' && v.selected) {
|
1371
|
-
selectedCandidatePairId = v.id;
|
1372
|
-
}
|
1373
|
-
candidatePairs.set(v.id, v);
|
1374
|
-
break;
|
1375
|
-
case 'remote-candidate':
|
1376
|
-
candidates.set(v.id, `${v.address}:${v.port}`);
|
1377
|
-
break;
|
1378
|
-
default:
|
1379
|
-
}
|
1380
|
-
});
|
1381
|
-
|
1382
|
-
if (selectedCandidatePairId === '') {
|
1383
|
-
return undefined;
|
1384
|
-
}
|
1385
|
-
const selectedID = candidatePairs.get(selectedCandidatePairId)?.remoteCandidateId;
|
1386
|
-
if (selectedID === undefined) {
|
1387
|
-
return undefined;
|
1388
|
-
}
|
1389
|
-
return candidates.get(selectedID);
|
1390
|
-
}
|
1391
|
-
|
1392
1356
|
class SignalReconnectError extends Error {}
|
1393
1357
|
|
1394
1358
|
export type EngineEventCallbacks = {
|
package/src/room/Room.ts
CHANGED
@@ -452,6 +452,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
452
452
|
error instanceof ConnectionError &&
|
453
453
|
(error.status === 401 || error.reason === ConnectionErrorReason.Cancelled)
|
454
454
|
) {
|
455
|
+
this.handleDisconnect(this.options.stopLocalTrackOnUnpublish);
|
455
456
|
reject(error);
|
456
457
|
return;
|
457
458
|
}
|
@@ -462,9 +463,11 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
462
463
|
);
|
463
464
|
await connectFn(resolve, reject, nextUrl);
|
464
465
|
} else {
|
466
|
+
this.handleDisconnect(this.options.stopLocalTrackOnUnpublish);
|
465
467
|
reject(e);
|
466
468
|
}
|
467
469
|
} else {
|
470
|
+
this.handleDisconnect(this.options.stopLocalTrackOnUnpublish);
|
468
471
|
reject(e);
|
469
472
|
}
|
470
473
|
}
|
@@ -593,8 +596,8 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
593
596
|
this.setupLocalParticipantEvents();
|
594
597
|
this.emit(RoomEvent.SignalConnected);
|
595
598
|
} catch (err) {
|
599
|
+
await this.engine.close();
|
596
600
|
this.recreateEngine();
|
597
|
-
this.handleDisconnect(this.options.stopLocalTrackOnUnpublish);
|
598
601
|
const resultingError = new ConnectionError(`could not establish signal connection`);
|
599
602
|
if (err instanceof Error) {
|
600
603
|
resultingError.message = `${resultingError.message}: ${err.message}`;
|
@@ -608,8 +611,8 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
608
611
|
}
|
609
612
|
|
610
613
|
if (abortController.signal.aborted) {
|
614
|
+
await this.engine.close();
|
611
615
|
this.recreateEngine();
|
612
|
-
this.handleDisconnect(this.options.stopLocalTrackOnUnpublish);
|
613
616
|
throw new ConnectionError(`Connection attempt aborted`);
|
614
617
|
}
|
615
618
|
|
@@ -619,8 +622,8 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
619
622
|
abortController,
|
620
623
|
);
|
621
624
|
} catch (e) {
|
625
|
+
await this.engine.close();
|
622
626
|
this.recreateEngine();
|
623
|
-
this.handleDisconnect(this.options.stopLocalTrackOnUnpublish);
|
624
627
|
throw e;
|
625
628
|
}
|
626
629
|
|
@@ -799,7 +802,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
799
802
|
* - `startAudio`
|
800
803
|
* - `getUserMedia`
|
801
804
|
*/
|
802
|
-
async
|
805
|
+
startAudio = async () => {
|
803
806
|
const elements: Array<HTMLMediaElement> = [];
|
804
807
|
const browser = getBrowser();
|
805
808
|
if (browser && browser.os === 'iOS') {
|
@@ -860,7 +863,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
860
863
|
this.handleAudioPlaybackFailed(err);
|
861
864
|
throw err;
|
862
865
|
}
|
863
|
-
}
|
866
|
+
};
|
864
867
|
|
865
868
|
/**
|
866
869
|
* Returns true if audio playback is enabled
|
@@ -970,6 +973,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
970
973
|
.on(ParticipantEvent.LocalTrackUnpublished, this.onLocalTrackUnpublished)
|
971
974
|
.on(ParticipantEvent.ConnectionQualityChanged, this.onLocalConnectionQualityChanged)
|
972
975
|
.on(ParticipantEvent.MediaDevicesError, this.onMediaDevicesError)
|
976
|
+
.on(ParticipantEvent.AudioStreamAcquired, this.startAudio)
|
973
977
|
.on(
|
974
978
|
ParticipantEvent.ParticipantPermissionsChanged,
|
975
979
|
this.onLocalParticipantPermissionsChanged,
|
@@ -1166,6 +1170,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
1166
1170
|
.off(ParticipantEvent.LocalTrackUnpublished, this.onLocalTrackUnpublished)
|
1167
1171
|
.off(ParticipantEvent.ConnectionQualityChanged, this.onLocalConnectionQualityChanged)
|
1168
1172
|
.off(ParticipantEvent.MediaDevicesError, this.onMediaDevicesError)
|
1173
|
+
.off(ParticipantEvent.AudioStreamAcquired, this.startAudio)
|
1169
1174
|
.off(
|
1170
1175
|
ParticipantEvent.ParticipantPermissionsChanged,
|
1171
1176
|
this.onLocalParticipantPermissionsChanged,
|
@@ -1546,14 +1551,12 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
1546
1551
|
}
|
1547
1552
|
|
1548
1553
|
private sendSyncState() {
|
1549
|
-
|
1550
|
-
|
1551
|
-
|
1552
|
-
) {
|
1554
|
+
const previousAnswer = this.engine.subscriber?.getLocalDescription();
|
1555
|
+
const previousOffer = this.engine.subscriber?.getRemoteDescription();
|
1556
|
+
|
1557
|
+
if (!previousAnswer) {
|
1553
1558
|
return;
|
1554
1559
|
}
|
1555
|
-
const previousAnswer = this.engine.subscriber.pc.localDescription;
|
1556
|
-
const previousOffer = this.engine.subscriber.pc.remoteDescription;
|
1557
1560
|
|
1558
1561
|
/* 1. autosubscribe on, so subscribed tracks = all tracks - unsub tracks,
|
1559
1562
|
in this case, we send unsub tracks, so server add all tracks to this
|
package/src/room/defaults.ts
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
import type { InternalRoomConnectOptions, InternalRoomOptions } from '../options';
|
2
2
|
import DefaultReconnectPolicy from './DefaultReconnectPolicy';
|
3
|
-
import { AudioPresets, ScreenSharePresets, VideoPresets } from './track/options';
|
4
3
|
import type {
|
5
4
|
AudioCaptureOptions,
|
6
5
|
TrackPublishDefaults,
|
7
6
|
VideoCaptureOptions,
|
8
7
|
} from './track/options';
|
8
|
+
import { AudioPresets, ScreenSharePresets, VideoPresets } from './track/options';
|
9
|
+
|
10
|
+
export const defaultVideoCodec = 'vp8';
|
9
11
|
|
10
12
|
export const publishDefaults: TrackPublishDefaults = {
|
11
13
|
/**
|
@@ -19,7 +21,7 @@ export const publishDefaults: TrackPublishDefaults = {
|
|
19
21
|
simulcast: true,
|
20
22
|
screenShareEncoding: ScreenSharePresets.h1080fps15.encoding,
|
21
23
|
stopMicTrackOnMute: false,
|
22
|
-
videoCodec:
|
24
|
+
videoCodec: defaultVideoCodec,
|
23
25
|
backupCodec: false,
|
24
26
|
} as const;
|
25
27
|
|
package/src/room/events.ts
CHANGED
@@ -223,7 +223,7 @@ export enum RoomEvent {
|
|
223
223
|
* be emitted.
|
224
224
|
*
|
225
225
|
* args: (pub: [[RemoteTrackPublication]],
|
226
|
-
* status: [[TrackPublication.
|
226
|
+
* status: [[TrackPublication.PermissionStatus]],
|
227
227
|
* participant: [[RemoteParticipant]])
|
228
228
|
*/
|
229
229
|
TrackSubscriptionPermissionChanged = 'trackSubscriptionPermissionChanged',
|
@@ -441,6 +441,10 @@ export enum ParticipantEvent {
|
|
441
441
|
/** @internal */
|
442
442
|
MediaDevicesError = 'mediaDevicesError',
|
443
443
|
|
444
|
+
// fired only on LocalParticipant
|
445
|
+
/** @internal */
|
446
|
+
AudioStreamAcquired = 'audioStreamAcquired',
|
447
|
+
|
444
448
|
/**
|
445
449
|
* A participant's permission has changed. Currently only fired on LocalParticipant.
|
446
450
|
* args: (prevPermissions: [[ParticipantPermission]])
|