livekit-client 1.15.6 → 1.15.7
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 +14 -1
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +558 -327
- 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/api/SignalClient.d.ts +5 -1
- package/dist/src/api/SignalClient.d.ts.map +1 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/logger.d.ts +19 -3
- package/dist/src/logger.d.ts.map +1 -1
- package/dist/src/options.d.ts +1 -0
- package/dist/src/options.d.ts.map +1 -1
- package/dist/src/room/PCTransport.d.ts +5 -1
- package/dist/src/room/PCTransport.d.ts.map +1 -1
- package/dist/src/room/PCTransportManager.d.ts +5 -1
- package/dist/src/room/PCTransportManager.d.ts.map +1 -1
- package/dist/src/room/RTCEngine.d.ts +8 -0
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts +2 -0
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/participant/Participant.d.ts +9 -1
- package/dist/src/room/participant/Participant.d.ts.map +1 -1
- package/dist/src/room/participant/RemoteParticipant.d.ts +2 -1
- package/dist/src/room/participant/RemoteParticipant.d.ts.map +1 -1
- package/dist/src/room/participant/publishUtils.d.ts +2 -1
- package/dist/src/room/participant/publishUtils.d.ts.map +1 -1
- package/dist/src/room/track/LocalAudioTrack.d.ts +2 -1
- package/dist/src/room/track/LocalAudioTrack.d.ts.map +1 -1
- package/dist/src/room/track/LocalTrack.d.ts +2 -1
- package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
- package/dist/src/room/track/LocalTrackPublication.d.ts +2 -1
- package/dist/src/room/track/LocalTrackPublication.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/RemoteAudioTrack.d.ts +2 -1
- package/dist/src/room/track/RemoteAudioTrack.d.ts.map +1 -1
- package/dist/src/room/track/RemoteTrack.d.ts +2 -1
- package/dist/src/room/track/RemoteTrack.d.ts.map +1 -1
- package/dist/src/room/track/RemoteTrackPublication.d.ts +2 -1
- package/dist/src/room/track/RemoteTrackPublication.d.ts.map +1 -1
- package/dist/src/room/track/RemoteVideoTrack.d.ts +2 -1
- package/dist/src/room/track/RemoteVideoTrack.d.ts.map +1 -1
- package/dist/src/room/track/Track.d.ts +10 -1
- package/dist/src/room/track/Track.d.ts.map +1 -1
- package/dist/src/room/track/TrackPublication.d.ts +7 -1
- package/dist/src/room/track/TrackPublication.d.ts.map +1 -1
- package/dist/src/room/track/create.d.ts.map +1 -1
- package/dist/src/room/track/options.d.ts +8 -3
- package/dist/src/room/track/options.d.ts.map +1 -1
- package/dist/src/room/track/utils.d.ts +1 -0
- package/dist/src/room/track/utils.d.ts.map +1 -1
- package/dist/src/room/types.d.ts +4 -0
- package/dist/src/room/types.d.ts.map +1 -1
- package/dist/src/room/utils.d.ts +1 -0
- package/dist/src/room/utils.d.ts.map +1 -1
- package/dist/ts4.2/src/api/SignalClient.d.ts +5 -1
- package/dist/ts4.2/src/index.d.ts +2 -2
- package/dist/ts4.2/src/logger.d.ts +19 -3
- package/dist/ts4.2/src/options.d.ts +1 -0
- package/dist/ts4.2/src/room/PCTransport.d.ts +5 -1
- package/dist/ts4.2/src/room/PCTransportManager.d.ts +5 -1
- package/dist/ts4.2/src/room/RTCEngine.d.ts +8 -0
- package/dist/ts4.2/src/room/Room.d.ts +2 -0
- package/dist/ts4.2/src/room/participant/Participant.d.ts +9 -1
- package/dist/ts4.2/src/room/participant/RemoteParticipant.d.ts +2 -1
- package/dist/ts4.2/src/room/participant/publishUtils.d.ts +2 -1
- package/dist/ts4.2/src/room/track/LocalAudioTrack.d.ts +2 -1
- package/dist/ts4.2/src/room/track/LocalTrack.d.ts +2 -1
- package/dist/ts4.2/src/room/track/LocalTrackPublication.d.ts +2 -1
- package/dist/ts4.2/src/room/track/LocalVideoTrack.d.ts +2 -1
- package/dist/ts4.2/src/room/track/RemoteAudioTrack.d.ts +2 -1
- package/dist/ts4.2/src/room/track/RemoteTrack.d.ts +2 -1
- package/dist/ts4.2/src/room/track/RemoteTrackPublication.d.ts +2 -1
- package/dist/ts4.2/src/room/track/RemoteVideoTrack.d.ts +2 -1
- package/dist/ts4.2/src/room/track/Track.d.ts +10 -1
- package/dist/ts4.2/src/room/track/TrackPublication.d.ts +7 -1
- package/dist/ts4.2/src/room/track/options.d.ts +8 -3
- package/dist/ts4.2/src/room/track/utils.d.ts +1 -0
- package/dist/ts4.2/src/room/types.d.ts +4 -0
- package/dist/ts4.2/src/room/utils.d.ts +1 -0
- package/package.json +2 -2
- package/src/api/SignalClient.ts +43 -21
- package/src/index.ts +2 -1
- package/src/logger.ts +32 -8
- package/src/options.ts +2 -0
- package/src/room/PCTransport.ts +29 -8
- package/src/room/PCTransportManager.ts +29 -9
- package/src/room/RTCEngine.ts +71 -34
- package/src/room/Room.ts +94 -30
- package/src/room/participant/LocalParticipant.ts +163 -47
- package/src/room/participant/Participant.ts +26 -3
- package/src/room/participant/RemoteParticipant.ts +23 -15
- package/src/room/participant/publishUtils.test.ts +2 -2
- package/src/room/participant/publishUtils.ts +7 -4
- package/src/room/track/LocalAudioTrack.ts +8 -7
- package/src/room/track/LocalTrack.ts +23 -19
- package/src/room/track/LocalTrackPublication.ts +3 -2
- package/src/room/track/LocalVideoTrack.ts +31 -13
- package/src/room/track/RemoteAudioTrack.ts +4 -3
- package/src/room/track/RemoteTrack.ts +4 -1
- package/src/room/track/RemoteTrackPublication.ts +21 -13
- package/src/room/track/RemoteVideoTrack.ts +5 -4
- package/src/room/track/Track.ts +32 -2
- package/src/room/track/TrackPublication.ts +18 -3
- package/src/room/track/create.ts +4 -3
- package/src/room/track/options.ts +12 -5
- package/src/room/track/utils.ts +23 -1
- package/src/room/types.ts +5 -0
- package/src/room/utils.ts +5 -0
package/src/room/RTCEngine.ts
CHANGED
@@ -7,7 +7,7 @@ import {
|
|
7
7
|
SignalConnectionState,
|
8
8
|
toProtoSessionDescription,
|
9
9
|
} from '../api/SignalClient';
|
10
|
-
import log from '../logger';
|
10
|
+
import log, { LoggerNames, getLogger } from '../logger';
|
11
11
|
import type { InternalRoomOptions } from '../options';
|
12
12
|
import {
|
13
13
|
ClientConfigSetting,
|
@@ -61,6 +61,7 @@ import type RemoteTrackPublication from './track/RemoteTrackPublication';
|
|
61
61
|
import { Track } from './track/Track';
|
62
62
|
import type { TrackPublishOptions, VideoCodec } from './track/options';
|
63
63
|
import { getTrackPublicationInfo } from './track/utils';
|
64
|
+
import type { LoggerOptions } from './types';
|
64
65
|
import {
|
65
66
|
Mutex,
|
66
67
|
isVideoCodec,
|
@@ -162,9 +163,18 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
162
163
|
|
163
164
|
private regionUrlProvider?: RegionUrlProvider;
|
164
165
|
|
166
|
+
private log = log;
|
167
|
+
|
168
|
+
private loggerOptions: LoggerOptions;
|
169
|
+
|
165
170
|
constructor(private options: InternalRoomOptions) {
|
166
171
|
super();
|
167
|
-
this.
|
172
|
+
this.log = getLogger(options.loggerName ?? LoggerNames.Engine);
|
173
|
+
this.loggerOptions = {
|
174
|
+
loggerName: options.loggerName,
|
175
|
+
loggerContextCb: () => this.logContext,
|
176
|
+
};
|
177
|
+
this.client = new SignalClient(undefined, this.loggerOptions);
|
168
178
|
this.client.signalLatency = this.options.expSignalLatency;
|
169
179
|
this.reconnectPolicy = this.options.reconnectPolicy;
|
170
180
|
this.registerOnLineListener();
|
@@ -187,6 +197,15 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
187
197
|
this.client.onStreamStateUpdate = (update) => this.emit(EngineEvent.StreamStateChanged, update);
|
188
198
|
}
|
189
199
|
|
200
|
+
/** @internal */
|
201
|
+
get logContext() {
|
202
|
+
return {
|
203
|
+
room: this.latestJoinResponse?.room?.name,
|
204
|
+
roomSid: this.latestJoinResponse?.room?.sid,
|
205
|
+
identity: this.latestJoinResponse?.participant?.identity,
|
206
|
+
};
|
207
|
+
}
|
208
|
+
|
190
209
|
async join(
|
191
210
|
url: string,
|
192
211
|
token: string,
|
@@ -220,8 +239,9 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
220
239
|
} catch (e) {
|
221
240
|
if (e instanceof ConnectionError) {
|
222
241
|
if (e.reason === ConnectionErrorReason.ServerUnreachable) {
|
223
|
-
log.warn(
|
242
|
+
this.log.warn(
|
224
243
|
`Couldn't connect to server, attempt ${this.joinAttempts} of ${this.maxJoinAttempts}`,
|
244
|
+
this.logContext,
|
225
245
|
);
|
226
246
|
if (this.joinAttempts < this.maxJoinAttempts) {
|
227
247
|
return this.join(url, token, opts, abortSignal);
|
@@ -324,7 +344,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
324
344
|
this.pcManager!.removeTrack(sender);
|
325
345
|
return true;
|
326
346
|
} catch (e: unknown) {
|
327
|
-
log.warn('failed to remove track', { error: e
|
347
|
+
this.log.warn('failed to remove track', { ...this.logContext, error: e });
|
328
348
|
}
|
329
349
|
return false;
|
330
350
|
}
|
@@ -356,7 +376,11 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
356
376
|
|
357
377
|
const rtcConfig = this.makeRTCConfiguration(joinResponse);
|
358
378
|
|
359
|
-
this.pcManager = new PCTransportManager(
|
379
|
+
this.pcManager = new PCTransportManager(
|
380
|
+
rtcConfig,
|
381
|
+
joinResponse.subscriberPrimary,
|
382
|
+
this.loggerOptions,
|
383
|
+
);
|
360
384
|
|
361
385
|
this.emit(EngineEvent.TransportsCreated, this.pcManager.publisher, this.pcManager.subscriber);
|
362
386
|
|
@@ -370,7 +394,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
370
394
|
|
371
395
|
this.pcManager.onDataChannel = this.handleDataChannel;
|
372
396
|
this.pcManager.onStateChange = async (connectionState, publisherState, subscriberState) => {
|
373
|
-
log.debug(`primary PC state changed ${connectionState}
|
397
|
+
this.log.debug(`primary PC state changed ${connectionState}`, this.logContext);
|
374
398
|
if (connectionState === PCTransportState.CONNECTED) {
|
375
399
|
const shouldEmit = this.pcState === PCState.New;
|
376
400
|
this.pcState = PCState.Connected;
|
@@ -404,9 +428,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
404
428
|
if (!this.pcManager) {
|
405
429
|
return;
|
406
430
|
}
|
407
|
-
log.debug('received server answer', {
|
408
|
-
RTCSdpType: sd.type,
|
409
|
-
});
|
431
|
+
this.log.debug('received server answer', { ...this.logContext, RTCSdpType: sd.type });
|
410
432
|
await this.pcManager.setPublisherAnswer(sd);
|
411
433
|
};
|
412
434
|
|
@@ -415,7 +437,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
415
437
|
if (!this.pcManager) {
|
416
438
|
return;
|
417
439
|
}
|
418
|
-
log.trace('got ICE candidate from peer', { candidate, target });
|
440
|
+
this.log.trace('got ICE candidate from peer', { ...this.logContext, candidate, target });
|
419
441
|
this.pcManager.addIceCandidate(candidate, target);
|
420
442
|
};
|
421
443
|
|
@@ -429,9 +451,16 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
429
451
|
};
|
430
452
|
|
431
453
|
this.client.onLocalTrackPublished = (res: TrackPublishedResponse) => {
|
432
|
-
log.debug('received trackPublishedResponse',
|
454
|
+
this.log.debug('received trackPublishedResponse', {
|
455
|
+
...this.logContext,
|
456
|
+
cid: res.cid,
|
457
|
+
track: res.track?.sid,
|
458
|
+
});
|
433
459
|
if (!this.pendingTrackResolvers[res.cid]) {
|
434
|
-
log.error(`missing track resolver for ${res.cid}
|
460
|
+
this.log.error(`missing track resolver for ${res.cid}`, {
|
461
|
+
...this.logContext,
|
462
|
+
cid: res.cid,
|
463
|
+
});
|
435
464
|
return;
|
436
465
|
}
|
437
466
|
const { resolve } = this.pendingTrackResolvers[res.cid];
|
@@ -464,7 +493,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
464
493
|
this.emit(EngineEvent.Disconnected, leave?.reason);
|
465
494
|
this.close();
|
466
495
|
}
|
467
|
-
log.
|
496
|
+
this.log.debug('client leave request', { ...this.logContext, reason: leave?.reason });
|
468
497
|
};
|
469
498
|
}
|
470
499
|
|
@@ -472,7 +501,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
472
501
|
const rtcConfig = { ...this.rtcConfig };
|
473
502
|
|
474
503
|
if (this.signalOpts?.e2eeEnabled) {
|
475
|
-
log.debug('E2EE - setting up transports with insertable streams');
|
504
|
+
this.log.debug('E2EE - setting up transports with insertable streams', this.logContext);
|
476
505
|
// this makes sure that no data is sent before the transforms are ready
|
477
506
|
// @ts-ignore
|
478
507
|
rtcConfig.encodedInsertableStreams = true;
|
@@ -562,7 +591,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
562
591
|
} else {
|
563
592
|
return;
|
564
593
|
}
|
565
|
-
log.debug(`on data channel ${channel.id}, ${channel.label}
|
594
|
+
this.log.debug(`on data channel ${channel.id}, ${channel.label}`, this.logContext);
|
566
595
|
channel.onmessage = this.handleDataMessage;
|
567
596
|
};
|
568
597
|
|
@@ -577,7 +606,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
577
606
|
} else if (message.data instanceof Blob) {
|
578
607
|
buffer = await message.data.arrayBuffer();
|
579
608
|
} else {
|
580
|
-
log.error('unsupported data type', message.data);
|
609
|
+
this.log.error('unsupported data type', { ...this.logContext, data: message.data });
|
581
610
|
return;
|
582
611
|
}
|
583
612
|
const dp = DataPacket.fromBinary(new Uint8Array(buffer));
|
@@ -598,9 +627,12 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
598
627
|
|
599
628
|
if (event instanceof ErrorEvent && event.error) {
|
600
629
|
const { error } = event.error;
|
601
|
-
log.error(`DataChannel error on ${channelKind}: ${event.message}`,
|
630
|
+
this.log.error(`DataChannel error on ${channelKind}: ${event.message}`, {
|
631
|
+
...this.logContext,
|
632
|
+
error,
|
633
|
+
});
|
602
634
|
} else {
|
603
|
-
log.error(`Unknown DataChannel error on ${channelKind}`, event);
|
635
|
+
this.log.error(`Unknown DataChannel error on ${channelKind}`, { ...this.logContext, event });
|
604
636
|
}
|
605
637
|
};
|
606
638
|
|
@@ -622,7 +654,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
622
654
|
}
|
623
655
|
const cap = RTCRtpSender.getCapabilities(kind);
|
624
656
|
if (!cap) return;
|
625
|
-
log.debug('get capabilities', cap);
|
657
|
+
this.log.debug('get sender capabilities', { ...this.logContext, cap });
|
626
658
|
const matched: RTCRtpCodecCapability[] = [];
|
627
659
|
const partialMatched: RTCRtpCodecCapability[] = [];
|
628
660
|
const unmatched: RTCRtpCodecCapability[] = [];
|
@@ -666,7 +698,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
666
698
|
return sender;
|
667
699
|
}
|
668
700
|
if (supportsAddTrack()) {
|
669
|
-
log.warn('using add-track fallback');
|
701
|
+
this.log.warn('using add-track fallback', this.logContext);
|
670
702
|
const sender = await this.createRTCRtpSender(track.mediaStreamTrack);
|
671
703
|
return sender;
|
672
704
|
}
|
@@ -684,7 +716,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
684
716
|
return this.createSimulcastTransceiverSender(track, simulcastTrack, opts, encodings);
|
685
717
|
}
|
686
718
|
if (supportsAddTrack()) {
|
687
|
-
log.debug('using add-track fallback');
|
719
|
+
this.log.debug('using add-track fallback', this.logContext);
|
688
720
|
return this.createRTCRtpSender(track.mediaStreamTrack);
|
689
721
|
}
|
690
722
|
|
@@ -764,15 +796,16 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
764
796
|
return;
|
765
797
|
}
|
766
798
|
|
767
|
-
log.warn(`${connection} disconnected
|
799
|
+
this.log.warn(`${connection} disconnected`, this.logContext);
|
768
800
|
if (this.reconnectAttempts === 0) {
|
769
801
|
// only reset start time on the first try
|
770
802
|
this.reconnectStart = Date.now();
|
771
803
|
}
|
772
804
|
|
773
805
|
const disconnect = (duration: number) => {
|
774
|
-
log.warn(
|
806
|
+
this.log.warn(
|
775
807
|
`could not recover connection after ${this.reconnectAttempts} attempts, ${duration}ms. giving up`,
|
808
|
+
this.logContext,
|
776
809
|
);
|
777
810
|
this.emit(EngineEvent.Disconnected);
|
778
811
|
this.close();
|
@@ -792,7 +825,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
792
825
|
delay = 0;
|
793
826
|
}
|
794
827
|
|
795
|
-
log.debug(`reconnecting in ${delay}ms
|
828
|
+
this.log.debug(`reconnecting in ${delay}ms`, this.logContext);
|
796
829
|
|
797
830
|
this.clearReconnectTimeout();
|
798
831
|
if (this.token && this.regionUrlProvider) {
|
@@ -836,7 +869,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
836
869
|
this.reconnectAttempts += 1;
|
837
870
|
let recoverable = true;
|
838
871
|
if (e instanceof UnexpectedConnectionState) {
|
839
|
-
log.debug('received unrecoverable error', { error: e });
|
872
|
+
this.log.debug('received unrecoverable error', { ...this.logContext, error: e });
|
840
873
|
// unrecoverable
|
841
874
|
recoverable = false;
|
842
875
|
} else if (!(e instanceof SignalReconnectError)) {
|
@@ -847,10 +880,11 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
847
880
|
if (recoverable) {
|
848
881
|
this.handleDisconnect('reconnect', ReconnectReason.RR_UNKNOWN);
|
849
882
|
} else {
|
850
|
-
log.info(
|
883
|
+
this.log.info(
|
851
884
|
`could not recover connection after ${this.reconnectAttempts} attempts, ${
|
852
885
|
Date.now() - this.reconnectStart
|
853
886
|
}ms. giving up`,
|
887
|
+
this.logContext,
|
854
888
|
);
|
855
889
|
this.emit(EngineEvent.Disconnected);
|
856
890
|
await this.close();
|
@@ -864,7 +898,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
864
898
|
try {
|
865
899
|
return this.reconnectPolicy.nextRetryDelayInMs(context);
|
866
900
|
} catch (e) {
|
867
|
-
log.warn('encountered error in reconnect policy', { error: e });
|
901
|
+
this.log.warn('encountered error in reconnect policy', { ...this.logContext, error: e });
|
868
902
|
}
|
869
903
|
|
870
904
|
// error in user code with provided reconnect policy, stop reconnecting
|
@@ -878,7 +912,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
878
912
|
throw new UnexpectedConnectionState('could not reconnect, url or token not saved');
|
879
913
|
}
|
880
914
|
|
881
|
-
log.info(`reconnecting, attempt: ${this.reconnectAttempts}
|
915
|
+
this.log.info(`reconnecting, attempt: ${this.reconnectAttempts}`, this.logContext);
|
882
916
|
this.emit(EngineEvent.Restarting);
|
883
917
|
|
884
918
|
if (!this.client.isDisconnected) {
|
@@ -890,7 +924,10 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
890
924
|
let joinResponse: JoinResponse;
|
891
925
|
try {
|
892
926
|
if (!this.signalOpts) {
|
893
|
-
log.warn(
|
927
|
+
this.log.warn(
|
928
|
+
'attempted connection restart, without signal options present',
|
929
|
+
this.logContext,
|
930
|
+
);
|
894
931
|
throw new SignalReconnectError();
|
895
932
|
}
|
896
933
|
// in case a regionUrl is passed, the region URL takes precedence
|
@@ -937,7 +974,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
937
974
|
throw new UnexpectedConnectionState('publisher and subscriber connections unset');
|
938
975
|
}
|
939
976
|
|
940
|
-
log.info(`resuming signal connection, attempt ${this.reconnectAttempts}
|
977
|
+
this.log.info(`resuming signal connection, attempt ${this.reconnectAttempts}`, this.logContext);
|
941
978
|
this.emit(EngineEvent.Resuming);
|
942
979
|
|
943
980
|
try {
|
@@ -951,7 +988,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
951
988
|
let message = '';
|
952
989
|
if (e instanceof Error) {
|
953
990
|
message = e.message;
|
954
|
-
log.error(e.message);
|
991
|
+
this.log.error(e.message, this.logContext);
|
955
992
|
}
|
956
993
|
if (e instanceof ConnectionError && e.reason === ConnectionErrorReason.NotAllowed) {
|
957
994
|
throw new UnexpectedConnectionState('could not reconnect, token might be expired');
|
@@ -990,7 +1027,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
990
1027
|
private async waitForPCReconnected() {
|
991
1028
|
this.pcState = PCState.Reconnecting;
|
992
1029
|
|
993
|
-
log.debug('waiting for peer connection to reconnect');
|
1030
|
+
this.log.debug('waiting for peer connection to reconnect', this.logContext);
|
994
1031
|
try {
|
995
1032
|
await sleep(minReconnectWait); // FIXME setTimeout again not ideal for a connection critical path
|
996
1033
|
if (!this.pcManager) {
|
@@ -1136,7 +1173,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
1136
1173
|
|
1137
1174
|
const handleClosed = () => {
|
1138
1175
|
abortController.abort();
|
1139
|
-
log.debug('engine disconnected while negotiation was ongoing');
|
1176
|
+
this.log.debug('engine disconnected while negotiation was ongoing', this.logContext);
|
1140
1177
|
resolve();
|
1141
1178
|
return;
|
1142
1179
|
};
|
@@ -1196,7 +1233,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
1196
1233
|
/** @internal */
|
1197
1234
|
sendSyncState(remoteTracks: RemoteTrackPublication[], localTracks: LocalTrackPublication[]) {
|
1198
1235
|
if (!this.pcManager) {
|
1199
|
-
log.warn('sync state cannot be sent without peer connection setup');
|
1236
|
+
this.log.warn('sync state cannot be sent without peer connection setup', this.logContext);
|
1200
1237
|
return;
|
1201
1238
|
}
|
1202
1239
|
const previousAnswer = this.pcManager.subscriber.getLocalDescription();
|
package/src/room/Room.ts
CHANGED
@@ -4,7 +4,7 @@ import type TypedEmitter from 'typed-emitter';
|
|
4
4
|
import 'webrtc-adapter';
|
5
5
|
import { EncryptionEvent } from '../e2ee';
|
6
6
|
import { E2EEManager } from '../e2ee/E2eeManager';
|
7
|
-
import log from '../logger';
|
7
|
+
import log, { LoggerNames, getLogger } from '../logger';
|
8
8
|
import type {
|
9
9
|
InternalRoomConnectOptions,
|
10
10
|
InternalRoomOptions,
|
@@ -151,6 +151,8 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
151
151
|
|
152
152
|
private isVideoPlaybackBlocked: boolean = false;
|
153
153
|
|
154
|
+
private log = log;
|
155
|
+
|
154
156
|
/**
|
155
157
|
* Creates a new Room, the primary construct for a LiveKit session.
|
156
158
|
* @param options
|
@@ -163,6 +165,8 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
163
165
|
this.identityToSid = new Map();
|
164
166
|
this.options = { ...roomOptionDefaults, ...options };
|
165
167
|
|
168
|
+
this.log = getLogger(this.options.loggerName ?? LoggerNames.Room);
|
169
|
+
|
166
170
|
this.options.audioCaptureDefaults = {
|
167
171
|
...audioDefaults,
|
168
172
|
...options?.audioCaptureDefaults,
|
@@ -198,7 +202,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
198
202
|
this.switchActiveDevice(
|
199
203
|
'audiooutput',
|
200
204
|
unwrapConstraint(this.options.audioOutput.deviceId),
|
201
|
-
).catch((e) => log.warn(`Could not set audio output: ${e.message}
|
205
|
+
).catch((e) => this.log.warn(`Could not set audio output: ${e.message}`, this.logContext));
|
202
206
|
}
|
203
207
|
|
204
208
|
if (this.options.e2ee) {
|
@@ -239,6 +243,14 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
239
243
|
}
|
240
244
|
}
|
241
245
|
|
246
|
+
private get logContext() {
|
247
|
+
return {
|
248
|
+
room: this.name,
|
249
|
+
roomSid: this.sid,
|
250
|
+
identity: this.localParticipant.identity,
|
251
|
+
};
|
252
|
+
}
|
253
|
+
|
242
254
|
/**
|
243
255
|
* if the current room has a participant with `recorder: true` in its JWT grant
|
244
256
|
**/
|
@@ -362,7 +374,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
362
374
|
if (this.state !== ConnectionState.Disconnected) {
|
363
375
|
return;
|
364
376
|
}
|
365
|
-
log.debug(`prepareConnection to ${url}
|
377
|
+
this.log.debug(`prepareConnection to ${url}`, this.logContext);
|
366
378
|
try {
|
367
379
|
if (isCloud(new URL(url)) && token) {
|
368
380
|
this.regionUrlProvider = new RegionUrlProvider(url, token);
|
@@ -372,13 +384,13 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
372
384
|
if (regionUrl && this.state === ConnectionState.Disconnected) {
|
373
385
|
this.regionUrl = regionUrl;
|
374
386
|
await fetch(toHttpUrl(regionUrl), { method: 'HEAD' });
|
375
|
-
log.debug(`prepared connection to ${regionUrl}
|
387
|
+
this.log.debug(`prepared connection to ${regionUrl}`, this.logContext);
|
376
388
|
}
|
377
389
|
} else {
|
378
390
|
await fetch(toHttpUrl(url), { method: 'HEAD' });
|
379
391
|
}
|
380
392
|
} catch (e) {
|
381
|
-
log.warn('could not prepare connection', { error: e });
|
393
|
+
this.log.warn('could not prepare connection', { ...this.logContext, error: e });
|
382
394
|
}
|
383
395
|
}
|
384
396
|
|
@@ -388,7 +400,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
388
400
|
|
389
401
|
if (this.state === ConnectionState.Connected) {
|
390
402
|
// when the state is reconnecting or connected, this function returns immediately
|
391
|
-
log.info(`already connected to room ${this.name}
|
403
|
+
this.log.info(`already connected to room ${this.name}`, this.logContext);
|
392
404
|
unlockDisconnect();
|
393
405
|
return Promise.resolve();
|
394
406
|
}
|
@@ -413,7 +425,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
413
425
|
// if initial connection fails, this will speed up picking regional url
|
414
426
|
// on subsequent runs
|
415
427
|
this.regionUrlProvider.fetchRegionSettings().catch((e) => {
|
416
|
-
log.warn('could not fetch region settings', { error: e });
|
428
|
+
this.log.warn('could not fetch region settings', { ...this.logContext, error: e });
|
417
429
|
});
|
418
430
|
}
|
419
431
|
|
@@ -460,8 +472,9 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
460
472
|
}
|
461
473
|
}
|
462
474
|
if (nextUrl) {
|
463
|
-
log.info(
|
475
|
+
this.log.info(
|
464
476
|
`Initial connection failed with ConnectionError: ${e.message}. Retrying with another region: ${nextUrl}`,
|
477
|
+
this.logContext,
|
465
478
|
);
|
466
479
|
await connectFn(resolve, reject, nextUrl);
|
467
480
|
} else {
|
@@ -517,10 +530,15 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
517
530
|
serverInfo = { version: joinResponse.serverVersion, region: joinResponse.serverRegion };
|
518
531
|
}
|
519
532
|
|
520
|
-
log.debug(
|
533
|
+
this.log.debug(
|
521
534
|
`connected to Livekit Server ${Object.entries(serverInfo)
|
522
535
|
.map(([key, value]) => `${key}: ${value}`)
|
523
536
|
.join(', ')}`,
|
537
|
+
{
|
538
|
+
room: joinResponse.room?.name,
|
539
|
+
roomSid: joinResponse.room?.sid,
|
540
|
+
identity: joinResponse.participant?.identity,
|
541
|
+
},
|
524
542
|
);
|
525
543
|
|
526
544
|
if (!joinResponse.serverVersion) {
|
@@ -528,7 +546,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
528
546
|
}
|
529
547
|
|
530
548
|
if (joinResponse.serverVersion === '0.15.1' && this.options.dynacast) {
|
531
|
-
log.debug('disabling dynacast due to server version');
|
549
|
+
this.log.debug('disabling dynacast due to server version', this.logContext);
|
532
550
|
// dynacast has a bug in 0.15.1, so we cannot use it then
|
533
551
|
roomOptions.dynacast = false;
|
534
552
|
}
|
@@ -561,7 +579,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
561
579
|
abortController: AbortController,
|
562
580
|
) => {
|
563
581
|
if (this.state === ConnectionState.Reconnecting) {
|
564
|
-
log.info('Reconnection attempt replaced by new connection attempt');
|
582
|
+
this.log.info('Reconnection attempt replaced by new connection attempt', this.logContext);
|
565
583
|
// make sure we close and recreate the existing engine in order to get rid of any potentially ongoing reconnection attempts
|
566
584
|
this.recreateEngine();
|
567
585
|
} else {
|
@@ -608,7 +626,10 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
608
626
|
resultingError.reason = err.reason;
|
609
627
|
resultingError.status = err.status;
|
610
628
|
}
|
611
|
-
log.debug(`error trying to establish signal connection`, {
|
629
|
+
this.log.debug(`error trying to establish signal connection`, {
|
630
|
+
...this.logContext,
|
631
|
+
error: err,
|
632
|
+
});
|
612
633
|
throw resultingError;
|
613
634
|
}
|
614
635
|
|
@@ -651,16 +672,18 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
651
672
|
const unlock = await this.disconnectLock.lock();
|
652
673
|
try {
|
653
674
|
if (this.state === ConnectionState.Disconnected) {
|
654
|
-
log.debug('already disconnected');
|
675
|
+
this.log.debug('already disconnected', this.logContext);
|
655
676
|
return;
|
656
677
|
}
|
657
|
-
log.info('disconnect from room', {
|
678
|
+
this.log.info('disconnect from room', {
|
679
|
+
...this.logContext,
|
680
|
+
});
|
658
681
|
if (
|
659
682
|
this.state === ConnectionState.Connecting ||
|
660
683
|
this.state === ConnectionState.Reconnecting
|
661
684
|
) {
|
662
685
|
// try aborting pending connection attempt
|
663
|
-
log.warn('abort connection attempt');
|
686
|
+
this.log.warn('abort connection attempt', this.logContext);
|
664
687
|
this.abortController?.abort();
|
665
688
|
// in case the abort controller didn't manage to cancel the connection attempt, reject the connect promise explicitly
|
666
689
|
this.connectFuture?.reject?.(new ConnectionError('Client initiated disconnect'));
|
@@ -886,8 +909,9 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
886
909
|
if (e.name === 'NotAllowedError') {
|
887
910
|
this.handleVideoPlaybackFailed();
|
888
911
|
} else {
|
889
|
-
log.warn(
|
912
|
+
this.log.warn(
|
890
913
|
'Resuming video playback failed, make sure you call `startVideo` directly in a user gesture handler',
|
914
|
+
this.logContext,
|
891
915
|
);
|
892
916
|
}
|
893
917
|
});
|
@@ -1052,7 +1076,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
1052
1076
|
return;
|
1053
1077
|
}
|
1054
1078
|
if (this.state === ConnectionState.Disconnected) {
|
1055
|
-
log.warn('skipping incoming track after Room disconnected');
|
1079
|
+
this.log.warn('skipping incoming track after Room disconnected', this.logContext);
|
1056
1080
|
return;
|
1057
1081
|
}
|
1058
1082
|
const parts = unpackStreamId(stream.id);
|
@@ -1064,15 +1088,16 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
1064
1088
|
if (streamId && streamId.startsWith('TR')) trackId = streamId;
|
1065
1089
|
|
1066
1090
|
if (participantId === this.localParticipant.sid) {
|
1067
|
-
log.warn('tried to create RemoteParticipant for local participant');
|
1091
|
+
this.log.warn('tried to create RemoteParticipant for local participant', this.logContext);
|
1068
1092
|
return;
|
1069
1093
|
}
|
1070
1094
|
|
1071
1095
|
const participant = this.participants.get(participantId) as RemoteParticipant | undefined;
|
1072
1096
|
|
1073
1097
|
if (!participant) {
|
1074
|
-
log.error(
|
1098
|
+
this.log.error(
|
1075
1099
|
`Tried to add a track for a participant, that's not present. Sid: ${participantId}`,
|
1100
|
+
this.logContext,
|
1076
1101
|
);
|
1077
1102
|
return;
|
1078
1103
|
}
|
@@ -1107,7 +1132,8 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
1107
1132
|
};
|
1108
1133
|
|
1109
1134
|
private handleSignalRestarted = async (joinResponse: JoinResponse) => {
|
1110
|
-
log.debug(`signal reconnected to server`, {
|
1135
|
+
this.log.debug(`signal reconnected to server, region ${joinResponse.serverRegion}`, {
|
1136
|
+
...this.logContext,
|
1111
1137
|
region: joinResponse.serverRegion,
|
1112
1138
|
});
|
1113
1139
|
|
@@ -1136,12 +1162,14 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
1136
1162
|
) {
|
1137
1163
|
// we need to restart the track before publishing, often a full reconnect
|
1138
1164
|
// is necessary because computer had gone to sleep.
|
1139
|
-
log.debug('restarting existing track', {
|
1165
|
+
this.log.debug('restarting existing track', {
|
1166
|
+
...this.logContext,
|
1140
1167
|
track: pub.trackSid,
|
1141
1168
|
});
|
1142
1169
|
await track.restartTrack();
|
1143
1170
|
}
|
1144
|
-
log.debug('publishing new track', {
|
1171
|
+
this.log.debug('publishing new track', {
|
1172
|
+
...this.logContext,
|
1145
1173
|
track: pub.trackSid,
|
1146
1174
|
});
|
1147
1175
|
await this.localParticipant.publishTrack(track, pub.options);
|
@@ -1149,12 +1177,16 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
1149
1177
|
}),
|
1150
1178
|
);
|
1151
1179
|
} catch (error) {
|
1152
|
-
log.error('error trying to re-publish tracks after reconnection', {
|
1180
|
+
this.log.error('error trying to re-publish tracks after reconnection', {
|
1181
|
+
...this.logContext,
|
1182
|
+
error,
|
1183
|
+
});
|
1153
1184
|
}
|
1154
1185
|
|
1155
1186
|
try {
|
1156
1187
|
await this.engine.waitForRestarted();
|
1157
|
-
log.debug(`fully reconnected to server`, {
|
1188
|
+
this.log.debug(`fully reconnected to server`, {
|
1189
|
+
...this.logContext,
|
1158
1190
|
region: joinResponse.serverRegion,
|
1159
1191
|
});
|
1160
1192
|
} catch {
|
@@ -1411,7 +1443,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
1411
1443
|
};
|
1412
1444
|
|
1413
1445
|
private handleAudioPlaybackFailed = (e: any) => {
|
1414
|
-
log.warn('could not playback audio', e);
|
1446
|
+
this.log.warn('could not playback audio', { ...this.logContext, error: e });
|
1415
1447
|
if (!this.canPlaybackAudio) {
|
1416
1448
|
return;
|
1417
1449
|
}
|
@@ -1480,7 +1512,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
1480
1512
|
try {
|
1481
1513
|
await this.audioContext.resume();
|
1482
1514
|
} catch (e: any) {
|
1483
|
-
log.warn(e);
|
1515
|
+
this.log.warn('Could not resume audio context', { ...this.logContext, error: e });
|
1484
1516
|
}
|
1485
1517
|
}
|
1486
1518
|
|
@@ -1502,7 +1534,10 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
1502
1534
|
if (info) {
|
1503
1535
|
participant = RemoteParticipant.fromParticipantInfo(this.engine.client, info);
|
1504
1536
|
} else {
|
1505
|
-
participant = new RemoteParticipant(this.engine.client, id, '', undefined, undefined
|
1537
|
+
participant = new RemoteParticipant(this.engine.client, id, '', undefined, undefined, {
|
1538
|
+
loggerContextCb: () => this.logContext,
|
1539
|
+
loggerName: this.options.loggerName,
|
1540
|
+
});
|
1506
1541
|
}
|
1507
1542
|
if (this.options.expWebAudioMix) {
|
1508
1543
|
participant.setAudioContext(this.audioContext);
|
@@ -1510,7 +1545,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
1510
1545
|
if (this.options.audioOutput?.deviceId) {
|
1511
1546
|
participant
|
1512
1547
|
.setAudioOutput(this.options.audioOutput)
|
1513
|
-
.catch((e) => log.warn(`Could not set audio output: ${e.message}
|
1548
|
+
.catch((e) => this.log.warn(`Could not set audio output: ${e.message}`, this.logContext));
|
1514
1549
|
}
|
1515
1550
|
return participant;
|
1516
1551
|
}
|
@@ -1643,7 +1678,10 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
1643
1678
|
!this.engine.verifyTransport()
|
1644
1679
|
) {
|
1645
1680
|
consecutiveFailures++;
|
1646
|
-
log.warn('detected connection state mismatch', {
|
1681
|
+
this.log.warn('detected connection state mismatch', {
|
1682
|
+
...this.logContext,
|
1683
|
+
numFailures: consecutiveFailures,
|
1684
|
+
});
|
1647
1685
|
if (consecutiveFailures >= 3) {
|
1648
1686
|
this.recreateEngine();
|
1649
1687
|
this.handleDisconnect(
|
@@ -1799,7 +1837,11 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
1799
1837
|
true,
|
1800
1838
|
true,
|
1801
1839
|
),
|
1840
|
+
undefined,
|
1841
|
+
false,
|
1842
|
+
{ loggerName: this.options.loggerName, loggerContextCb: () => this.logContext },
|
1802
1843
|
),
|
1844
|
+
{ loggerName: this.options.loggerName, loggerContextCb: () => this.logContext },
|
1803
1845
|
);
|
1804
1846
|
// @ts-ignore
|
1805
1847
|
this.localParticipant.addTrackPublication(camPub);
|
@@ -1817,7 +1859,12 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
1817
1859
|
publishOptions.useRealTracks
|
1818
1860
|
? (await navigator.mediaDevices.getUserMedia({ audio: true })).getAudioTracks()[0]
|
1819
1861
|
: getEmptyAudioStreamTrack(),
|
1862
|
+
undefined,
|
1863
|
+
false,
|
1864
|
+
this.audioContext,
|
1865
|
+
{ loggerName: this.options.loggerName, loggerContextCb: () => this.logContext },
|
1820
1866
|
),
|
1867
|
+
{ loggerName: this.options.loggerName, loggerContextCb: () => this.logContext },
|
1821
1868
|
);
|
1822
1869
|
// @ts-ignore
|
1823
1870
|
this.localParticipant.addTrackPublication(audioPub);
|
@@ -1870,12 +1917,29 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
1870
1917
|
): boolean {
|
1871
1918
|
// active speaker updates are too spammy
|
1872
1919
|
if (event !== RoomEvent.ActiveSpeakersChanged) {
|
1873
|
-
|
1920
|
+
// only extract logContext from arguments in order to avoid logging the whole object tree
|
1921
|
+
const minimizedArgs = mapArgs(args).filter((arg: unknown) => arg !== undefined);
|
1922
|
+
this.log.debug(`room event ${event}`, { ...this.logContext, event, args: minimizedArgs });
|
1874
1923
|
}
|
1875
1924
|
return super.emit(event, ...args);
|
1876
1925
|
}
|
1877
1926
|
}
|
1878
1927
|
|
1928
|
+
function mapArgs(args: unknown[]): any {
|
1929
|
+
return args.map((arg: unknown) => {
|
1930
|
+
if (!arg) {
|
1931
|
+
return;
|
1932
|
+
}
|
1933
|
+
if (Array.isArray(arg)) {
|
1934
|
+
return mapArgs(arg);
|
1935
|
+
}
|
1936
|
+
if (typeof arg === 'object') {
|
1937
|
+
return 'logContext' in arg && arg.logContext;
|
1938
|
+
}
|
1939
|
+
return arg;
|
1940
|
+
});
|
1941
|
+
}
|
1942
|
+
|
1879
1943
|
export default Room;
|
1880
1944
|
|
1881
1945
|
export type RoomEventCallbacks = {
|