livekit-client 1.15.6 → 1.15.8

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.
Files changed (117) hide show
  1. package/dist/livekit-client.e2ee.worker.js +1 -1
  2. package/dist/livekit-client.e2ee.worker.js.map +1 -1
  3. package/dist/livekit-client.e2ee.worker.mjs +14 -1
  4. package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
  5. package/dist/livekit-client.esm.mjs +556 -348
  6. package/dist/livekit-client.esm.mjs.map +1 -1
  7. package/dist/livekit-client.umd.js +1 -1
  8. package/dist/livekit-client.umd.js.map +1 -1
  9. package/dist/src/api/SignalClient.d.ts +5 -1
  10. package/dist/src/api/SignalClient.d.ts.map +1 -1
  11. package/dist/src/index.d.ts +2 -2
  12. package/dist/src/index.d.ts.map +1 -1
  13. package/dist/src/logger.d.ts +19 -3
  14. package/dist/src/logger.d.ts.map +1 -1
  15. package/dist/src/options.d.ts +1 -0
  16. package/dist/src/options.d.ts.map +1 -1
  17. package/dist/src/room/PCTransport.d.ts +5 -1
  18. package/dist/src/room/PCTransport.d.ts.map +1 -1
  19. package/dist/src/room/PCTransportManager.d.ts +5 -1
  20. package/dist/src/room/PCTransportManager.d.ts.map +1 -1
  21. package/dist/src/room/RTCEngine.d.ts +8 -0
  22. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  23. package/dist/src/room/Room.d.ts +2 -0
  24. package/dist/src/room/Room.d.ts.map +1 -1
  25. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  26. package/dist/src/room/participant/Participant.d.ts +9 -1
  27. package/dist/src/room/participant/Participant.d.ts.map +1 -1
  28. package/dist/src/room/participant/RemoteParticipant.d.ts +2 -1
  29. package/dist/src/room/participant/RemoteParticipant.d.ts.map +1 -1
  30. package/dist/src/room/participant/publishUtils.d.ts +2 -1
  31. package/dist/src/room/participant/publishUtils.d.ts.map +1 -1
  32. package/dist/src/room/timers.d.ts +5 -4
  33. package/dist/src/room/timers.d.ts.map +1 -1
  34. package/dist/src/room/track/LocalAudioTrack.d.ts +2 -1
  35. package/dist/src/room/track/LocalAudioTrack.d.ts.map +1 -1
  36. package/dist/src/room/track/LocalTrack.d.ts +2 -1
  37. package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
  38. package/dist/src/room/track/LocalTrackPublication.d.ts +2 -1
  39. package/dist/src/room/track/LocalTrackPublication.d.ts.map +1 -1
  40. package/dist/src/room/track/LocalVideoTrack.d.ts +2 -1
  41. package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -1
  42. package/dist/src/room/track/RemoteAudioTrack.d.ts +2 -1
  43. package/dist/src/room/track/RemoteAudioTrack.d.ts.map +1 -1
  44. package/dist/src/room/track/RemoteTrack.d.ts +2 -1
  45. package/dist/src/room/track/RemoteTrack.d.ts.map +1 -1
  46. package/dist/src/room/track/RemoteTrackPublication.d.ts +2 -1
  47. package/dist/src/room/track/RemoteTrackPublication.d.ts.map +1 -1
  48. package/dist/src/room/track/RemoteVideoTrack.d.ts +2 -1
  49. package/dist/src/room/track/RemoteVideoTrack.d.ts.map +1 -1
  50. package/dist/src/room/track/Track.d.ts +10 -1
  51. package/dist/src/room/track/Track.d.ts.map +1 -1
  52. package/dist/src/room/track/TrackPublication.d.ts +7 -1
  53. package/dist/src/room/track/TrackPublication.d.ts.map +1 -1
  54. package/dist/src/room/track/create.d.ts.map +1 -1
  55. package/dist/src/room/track/options.d.ts +8 -3
  56. package/dist/src/room/track/options.d.ts.map +1 -1
  57. package/dist/src/room/track/utils.d.ts +1 -0
  58. package/dist/src/room/track/utils.d.ts.map +1 -1
  59. package/dist/src/room/types.d.ts +4 -0
  60. package/dist/src/room/types.d.ts.map +1 -1
  61. package/dist/src/room/utils.d.ts +1 -0
  62. package/dist/src/room/utils.d.ts.map +1 -1
  63. package/dist/ts4.2/src/api/SignalClient.d.ts +5 -1
  64. package/dist/ts4.2/src/index.d.ts +2 -2
  65. package/dist/ts4.2/src/logger.d.ts +19 -3
  66. package/dist/ts4.2/src/options.d.ts +1 -0
  67. package/dist/ts4.2/src/room/PCTransport.d.ts +5 -1
  68. package/dist/ts4.2/src/room/PCTransportManager.d.ts +5 -1
  69. package/dist/ts4.2/src/room/RTCEngine.d.ts +8 -0
  70. package/dist/ts4.2/src/room/Room.d.ts +2 -0
  71. package/dist/ts4.2/src/room/participant/Participant.d.ts +9 -1
  72. package/dist/ts4.2/src/room/participant/RemoteParticipant.d.ts +2 -1
  73. package/dist/ts4.2/src/room/participant/publishUtils.d.ts +2 -1
  74. package/dist/ts4.2/src/room/timers.d.ts +5 -4
  75. package/dist/ts4.2/src/room/track/LocalAudioTrack.d.ts +2 -1
  76. package/dist/ts4.2/src/room/track/LocalTrack.d.ts +2 -1
  77. package/dist/ts4.2/src/room/track/LocalTrackPublication.d.ts +2 -1
  78. package/dist/ts4.2/src/room/track/LocalVideoTrack.d.ts +2 -1
  79. package/dist/ts4.2/src/room/track/RemoteAudioTrack.d.ts +2 -1
  80. package/dist/ts4.2/src/room/track/RemoteTrack.d.ts +2 -1
  81. package/dist/ts4.2/src/room/track/RemoteTrackPublication.d.ts +2 -1
  82. package/dist/ts4.2/src/room/track/RemoteVideoTrack.d.ts +2 -1
  83. package/dist/ts4.2/src/room/track/Track.d.ts +10 -1
  84. package/dist/ts4.2/src/room/track/TrackPublication.d.ts +7 -1
  85. package/dist/ts4.2/src/room/track/options.d.ts +8 -3
  86. package/dist/ts4.2/src/room/track/utils.d.ts +1 -0
  87. package/dist/ts4.2/src/room/types.d.ts +4 -0
  88. package/dist/ts4.2/src/room/utils.d.ts +1 -0
  89. package/package.json +2 -2
  90. package/src/api/SignalClient.ts +43 -21
  91. package/src/index.ts +2 -1
  92. package/src/logger.ts +32 -8
  93. package/src/options.ts +2 -0
  94. package/src/room/PCTransport.ts +29 -8
  95. package/src/room/PCTransportManager.ts +29 -9
  96. package/src/room/RTCEngine.ts +71 -34
  97. package/src/room/Room.ts +91 -60
  98. package/src/room/participant/LocalParticipant.ts +165 -47
  99. package/src/room/participant/Participant.ts +26 -3
  100. package/src/room/participant/RemoteParticipant.ts +23 -15
  101. package/src/room/participant/publishUtils.test.ts +2 -2
  102. package/src/room/participant/publishUtils.ts +7 -4
  103. package/src/room/track/LocalAudioTrack.ts +8 -7
  104. package/src/room/track/LocalTrack.ts +23 -19
  105. package/src/room/track/LocalTrackPublication.ts +3 -2
  106. package/src/room/track/LocalVideoTrack.ts +31 -13
  107. package/src/room/track/RemoteAudioTrack.ts +4 -3
  108. package/src/room/track/RemoteTrack.ts +4 -1
  109. package/src/room/track/RemoteTrackPublication.ts +21 -13
  110. package/src/room/track/RemoteVideoTrack.ts +5 -4
  111. package/src/room/track/Track.ts +32 -2
  112. package/src/room/track/TrackPublication.ts +18 -3
  113. package/src/room/track/create.ts +4 -3
  114. package/src/room/track/options.ts +12 -5
  115. package/src/room/track/utils.ts +23 -1
  116. package/src/room/types.ts +5 -0
  117. package/src/room/utils.ts +5 -0
@@ -2,6 +2,7 @@ import type { SignalClient } from '../../api/SignalClient';
2
2
  import { VideoLayer, VideoQuality } from '../../proto/livekit_models_pb';
3
3
  import { SubscribedCodec, SubscribedQuality } from '../../proto/livekit_rtc_pb';
4
4
  import type { VideoSenderStats } from '../stats';
5
+ import type { LoggerOptions } from '../types';
5
6
  import LocalTrack from './LocalTrack';
6
7
  import { Track } from './Track';
7
8
  import type { VideoCaptureOptions, VideoCodec } from './options';
@@ -26,7 +27,7 @@ export default class LocalVideoTrack extends LocalTrack {
26
27
  * @param constraints MediaTrackConstraints that are being used when restarting or reacquiring tracks
27
28
  * @param userProvidedTrack Signals to the SDK whether or not the mediaTrack should be managed (i.e. released and reacquired) internally by the SDK
28
29
  */
29
- constructor(mediaTrack: MediaStreamTrack, constraints?: MediaTrackConstraints, userProvidedTrack?: boolean);
30
+ constructor(mediaTrack: MediaStreamTrack, constraints?: MediaTrackConstraints, userProvidedTrack?: boolean, loggerOptions?: LoggerOptions);
30
31
  get isSimulcast(): boolean;
31
32
  startMonitor(signalClient: SignalClient): void;
32
33
  stop(): void;
@@ -1,4 +1,5 @@
1
1
  import type { AudioReceiverStats } from '../stats';
2
+ import type { LoggerOptions } from '../types';
2
3
  import RemoteTrack from './RemoteTrack';
3
4
  import type { AudioOutputOptions } from './options';
4
5
  export default class RemoteAudioTrack extends RemoteTrack {
@@ -9,7 +10,7 @@ export default class RemoteAudioTrack extends RemoteTrack {
9
10
  private sourceNode?;
10
11
  private webAudioPluginNodes;
11
12
  private sinkId?;
12
- constructor(mediaTrack: MediaStreamTrack, sid: string, receiver?: RTCRtpReceiver, audioContext?: AudioContext, audioOutput?: AudioOutputOptions);
13
+ constructor(mediaTrack: MediaStreamTrack, sid: string, receiver?: RTCRtpReceiver, audioContext?: AudioContext, audioOutput?: AudioOutputOptions, loggerOptions?: LoggerOptions);
13
14
  /**
14
15
  * sets the volume for all attached audio elements
15
16
  */
@@ -1,8 +1,9 @@
1
+ import type { LoggerOptions } from '../types';
1
2
  import { Track } from './Track';
2
3
  export default abstract class RemoteTrack extends Track {
3
4
  /** @internal */
4
5
  receiver?: RTCRtpReceiver;
5
- constructor(mediaTrack: MediaStreamTrack, sid: string, kind: Track.Kind, receiver?: RTCRtpReceiver);
6
+ constructor(mediaTrack: MediaStreamTrack, sid: string, kind: Track.Kind, receiver?: RTCRtpReceiver, loggerOptions?: LoggerOptions);
6
7
  /** @internal */
7
8
  setMuted(muted: boolean): void;
8
9
  /** @internal */
@@ -1,4 +1,5 @@
1
1
  import { SubscriptionError, TrackInfo, VideoQuality } from '../../proto/livekit_models_pb';
2
+ import type { LoggerOptions } from '../types';
2
3
  import type RemoteTrack from './RemoteTrack';
3
4
  import { Track } from './Track';
4
5
  import { TrackPublication } from './TrackPublication';
@@ -12,7 +13,7 @@ export default class RemoteTrackPublication extends TrackPublication {
12
13
  protected videoDimensions?: Track.Dimensions;
13
14
  protected fps?: number;
14
15
  protected subscriptionError?: SubscriptionError;
15
- constructor(kind: Track.Kind, ti: TrackInfo, autoSubscribe: boolean | undefined);
16
+ constructor(kind: Track.Kind, ti: TrackInfo, autoSubscribe: boolean | undefined, loggerOptions?: LoggerOptions);
16
17
  /**
17
18
  * Subscribe or unsubscribe to this remote track
18
19
  * @param subscribed true to subscribe to a track, false to unsubscribe
@@ -1,3 +1,4 @@
1
+ import type { LoggerOptions } from '../types';
1
2
  import RemoteTrack from './RemoteTrack';
2
3
  import type { AdaptiveStreamSettings } from './types';
3
4
  export default class RemoteVideoTrack extends RemoteTrack {
@@ -6,7 +7,7 @@ export default class RemoteVideoTrack extends RemoteTrack {
6
7
  private adaptiveStreamSettings?;
7
8
  private lastVisible?;
8
9
  private lastDimensions?;
9
- constructor(mediaTrack: MediaStreamTrack, sid: string, receiver?: RTCRtpReceiver, adaptiveStreamSettings?: AdaptiveStreamSettings);
10
+ constructor(mediaTrack: MediaStreamTrack, sid: string, receiver?: RTCRtpReceiver, adaptiveStreamSettings?: AdaptiveStreamSettings, loggerOptions?: LoggerOptions);
10
11
  get isAdaptiveStream(): boolean;
11
12
  /**
12
13
  * Note: When using adaptiveStream, you need to use remoteVideoTrack.attach() to add the track to a HTMLVideoElement, otherwise your video tracks might never start
@@ -1,7 +1,9 @@
1
1
  import type TypedEventEmitter from 'typed-emitter';
2
2
  import type { SignalClient } from '../../api/SignalClient';
3
+ import { StructuredLogger } from '../../logger';
3
4
  import { TrackSource, TrackType } from '../../proto/livekit_models_pb';
4
5
  import { StreamState as ProtoStreamState } from '../../proto/livekit_rtc_pb';
6
+ import type { LoggerOptions } from '../types';
5
7
  declare const Track_base: new () => TypedEventEmitter<TrackEventCallbacks>;
6
8
  export declare abstract class Track extends Track_base {
7
9
  kind: Track.Kind;
@@ -25,9 +27,14 @@ export declare abstract class Track extends Track_base {
25
27
  protected _mediaStreamID: string;
26
28
  protected isInBackground: boolean;
27
29
  private backgroundTimeout;
30
+ private loggerContextCb;
28
31
  protected _currentBitrate: number;
29
32
  protected monitorInterval?: ReturnType<typeof setInterval>;
30
- protected constructor(mediaTrack: MediaStreamTrack, kind: Track.Kind);
33
+ protected log: StructuredLogger;
34
+ protected constructor(mediaTrack: MediaStreamTrack, kind: Track.Kind, loggerOptions?: LoggerOptions);
35
+ protected get logContext(): {
36
+ [x: string]: unknown;
37
+ };
31
38
  /** current receive bits per second */
32
39
  get currentBitrate(): number;
33
40
  get mediaStreamTrack(): MediaStreamTrack;
@@ -59,6 +66,8 @@ export declare abstract class Track extends Track_base {
59
66
  protected disable(): void;
60
67
  abstract startMonitor(signalClient?: SignalClient): void;
61
68
  stopMonitor(): void;
69
+ /** @internal */
70
+ updateLoggerOptions(loggerOptions: LoggerOptions): void;
62
71
  private recycleElement;
63
72
  protected appVisibilityChangedListener: () => void;
64
73
  protected handleAppVisibilityChanged(): Promise<void>;
@@ -2,6 +2,7 @@ import type TypedEventEmitter from 'typed-emitter';
2
2
  import { Encryption_Type } from '../../proto/livekit_models_pb';
3
3
  import type { SubscriptionError, TrackInfo } from '../../proto/livekit_models_pb';
4
4
  import type { UpdateSubscription, UpdateTrackSettings } from '../../proto/livekit_rtc_pb';
5
+ import type { LoggerOptions } from '../types';
5
6
  import LocalAudioTrack from './LocalAudioTrack';
6
7
  import LocalVideoTrack from './LocalVideoTrack';
7
8
  import RemoteAudioTrack from './RemoteAudioTrack';
@@ -25,9 +26,14 @@ export declare class TrackPublication extends TrackPublication_base {
25
26
  trackInfo?: TrackInfo;
26
27
  protected metadataMuted: boolean;
27
28
  protected encryption: Encryption_Type;
28
- constructor(kind: Track.Kind, id: string, name: string);
29
+ protected log: import("../../logger").StructuredLogger;
30
+ private loggerContextCb?;
31
+ constructor(kind: Track.Kind, id: string, name: string, loggerOptions?: LoggerOptions);
29
32
  /** @internal */
30
33
  setTrack(track?: Track): void;
34
+ protected get logContext(): {
35
+ [x: string]: unknown;
36
+ };
31
37
  get isMuted(): boolean;
32
38
  get isEnabled(): boolean;
33
39
  get isSubscribed(): boolean;
@@ -149,9 +149,10 @@ export interface ScreenShareCaptureOptions {
149
149
  displaySurface?: 'window' | 'browser' | 'monitor';
150
150
  };
151
151
  /**
152
- * capture resolution, defaults to screen resolution
153
- * NOTE: In Safari 17, specifying any resolution at all would lead to a low-resolution
154
- * capture. https://bugs.webkit.org/show_bug.cgi?id=263015
152
+ * capture resolution, defaults to 1080 for all browsers other than Safari
153
+ * On Safari 17, default resolution is not capped, due to a bug, specifying
154
+ * any resolution at all would lead to a low-resolution capture.
155
+ * https://bugs.webkit.org/show_bug.cgi?id=263015
155
156
  */
156
157
  resolution?: VideoResolution;
157
158
  /** a CaptureController object instance containing methods that can be used to further manipulate the capture session if included. */
@@ -162,6 +163,8 @@ export interface ScreenShareCaptureOptions {
162
163
  surfaceSwitching?: 'include' | 'exclude';
163
164
  /** specifies whether the browser should include the system audio among the possible audio sources offered to the user */
164
165
  systemAudio?: 'include' | 'exclude';
166
+ /** specify the type of content, see: https://www.w3.org/TR/mst-content-hint/#video-content-hints */
167
+ contentHint?: 'detail' | 'text' | 'motion';
165
168
  /**
166
169
  * Experimental option to control whether the audio playing in a tab will continue to be played out of a user's
167
170
  * local speakers when the tab is captured.
@@ -288,11 +291,13 @@ export declare const VideoPresets43: {
288
291
  };
289
292
  export declare const ScreenSharePresets: {
290
293
  readonly h360fps3: VideoPreset;
294
+ readonly h360fps15: VideoPreset;
291
295
  readonly h720fps5: VideoPreset;
292
296
  readonly h720fps15: VideoPreset;
293
297
  readonly h720fps30: VideoPreset;
294
298
  readonly h1080fps15: VideoPreset;
295
299
  readonly h1080fps30: VideoPreset;
300
+ readonly original: VideoPreset;
296
301
  };
297
302
  export {};
298
303
  //# sourceMappingURL=options.d.ts.map
@@ -28,4 +28,5 @@ export declare function sourceToKind(source: Track.Source): MediaDeviceKind | un
28
28
  export declare function screenCaptureToDisplayMediaStreamOptions(options: ScreenShareCaptureOptions): DisplayMediaStreamOptions;
29
29
  export declare function mimeTypeToVideoCodecString(mimeType: string): "vp8" | "h264" | "vp9" | "av1";
30
30
  export declare function getTrackPublicationInfo<T extends TrackPublication>(tracks: T[]): TrackPublishedResponse[];
31
+ export declare function getLogContextFromTrack(track: Track | TrackPublication): Record<string, unknown>;
31
32
  //# sourceMappingURL=utils.d.ts.map
@@ -23,4 +23,8 @@ export type LiveKitReactNativeInfo = {
23
23
  devicePixelRatio: number;
24
24
  };
25
25
  export type SimulationScenario = 'signal-reconnect' | 'speaker' | 'node-failure' | 'server-leave' | 'migration' | 'resume-reconnect' | 'force-tcp' | 'force-tls' | 'full-reconnect' | 'subscriber-bandwidth';
26
+ export type LoggerOptions = {
27
+ loggerName?: string;
28
+ loggerContextCb?: () => Record<string, unknown>;
29
+ };
26
30
  //# sourceMappingURL=types.d.ts.map
@@ -20,6 +20,7 @@ export declare function isBrowserSupported(): boolean;
20
20
  export declare function isFireFox(): boolean;
21
21
  export declare function isChromiumBased(): boolean;
22
22
  export declare function isSafari(): boolean;
23
+ export declare function isSafari17(): boolean;
23
24
  export declare function isMobile(): boolean;
24
25
  export declare function isWeb(): boolean;
25
26
  export declare function isReactNative(): boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "livekit-client",
3
- "version": "1.15.6",
3
+ "version": "1.15.8",
4
4
  "description": "JavaScript/TypeScript client SDK for LiveKit",
5
5
  "main": "./dist/livekit-client.umd.js",
6
6
  "unpkg": "./dist/livekit-client.umd.js",
@@ -89,7 +89,7 @@
89
89
  "build:watch": "rollup --watch --config rollup.config.js",
90
90
  "build-docs": "typedoc",
91
91
  "proto": "protoc --es_out src/proto --es_opt target=ts -I./protocol ./protocol/livekit_rtc.proto ./protocol/livekit_models.proto",
92
- "sample": "vite example -c vite.config.js",
92
+ "sample": "vite example -c vite.config.mjs",
93
93
  "lint": "eslint src",
94
94
  "test": "vitest run src",
95
95
  "deploy": "gh-pages -d example/dist",
@@ -1,5 +1,5 @@
1
1
  import { protoInt64 } from '@bufbuild/protobuf';
2
- import log from '../logger';
2
+ import log, { LoggerNames, getLogger } from '../logger';
3
3
  import {
4
4
  ClientInfo,
5
5
  DisconnectReason,
@@ -39,6 +39,7 @@ import {
39
39
  } from '../proto/livekit_rtc_pb';
40
40
  import { ConnectionError, ConnectionErrorReason } from '../room/errors';
41
41
  import CriticalTimers from '../room/timers';
42
+ import type { LoggerOptions } from '../room/types';
42
43
  import { Mutex, getClientInfo, isReactNative, sleep, toWebsocketUrl } from '../room/utils';
43
44
  import { AsyncQueue } from '../utils/AsyncQueue';
44
45
 
@@ -172,7 +173,13 @@ export class SignalClient {
172
173
 
173
174
  private connectionLock: Mutex;
174
175
 
175
- constructor(useJSON: boolean = false) {
176
+ private log = log;
177
+
178
+ private loggerContextCb?: LoggerOptions['loggerContextCb'];
179
+
180
+ constructor(useJSON: boolean = false, loggerOptions: LoggerOptions = {}) {
181
+ this.log = getLogger(loggerOptions.loggerName ?? LoggerNames.Signal);
182
+ this.loggerContextCb = loggerOptions.loggerContextCb;
176
183
  this.useJSON = useJSON;
177
184
  this.requestQueue = new AsyncQueue();
178
185
  this.queuedRequests = [];
@@ -181,6 +188,10 @@ export class SignalClient {
181
188
  this.state = SignalConnectionState.DISCONNECTED;
182
189
  }
183
190
 
191
+ private get logContext() {
192
+ return this.loggerContextCb?.() ?? {};
193
+ }
194
+
184
195
  async join(
185
196
  url: string,
186
197
  token: string,
@@ -202,7 +213,10 @@ export class SignalClient {
202
213
  reason?: ReconnectReason,
203
214
  ): Promise<ReconnectResponse | void> {
204
215
  if (!this.options) {
205
- log.warn('attempted to reconnect without signal options being set, ignoring');
216
+ this.log.warn(
217
+ 'attempted to reconnect without signal options being set, ignoring',
218
+ this.logContext,
219
+ );
206
220
  return;
207
221
  }
208
222
  this.state = SignalConnectionState.RECONNECTING;
@@ -251,7 +265,7 @@ export class SignalClient {
251
265
  abortHandler();
252
266
  }
253
267
  abortSignal?.addEventListener('abort', abortHandler);
254
- log.debug(`connecting to ${url + params}`);
268
+ this.log.debug(`connecting to ${url + params}`, this.logContext);
255
269
  if (this.ws) {
256
270
  await this.close();
257
271
  }
@@ -302,7 +316,10 @@ export class SignalClient {
302
316
  } else if (ev.data instanceof ArrayBuffer) {
303
317
  resp = SignalResponse.fromBinary(new Uint8Array(ev.data));
304
318
  } else {
305
- log.error(`could not decode websocket message: ${typeof ev.data}`);
319
+ this.log.error(
320
+ `could not decode websocket message: ${typeof ev.data}`,
321
+ this.logContext,
322
+ );
306
323
  return;
307
324
  }
308
325
 
@@ -316,7 +333,8 @@ export class SignalClient {
316
333
  this.pingIntervalDuration = resp.message.value.pingInterval;
317
334
 
318
335
  if (this.pingTimeoutDuration && this.pingTimeoutDuration > 0) {
319
- log.debug('ping config', {
336
+ this.log.debug('ping config', {
337
+ ...this.logContext,
320
338
  timeout: this.pingTimeoutDuration,
321
339
  interval: this.pingIntervalDuration,
322
340
  });
@@ -354,7 +372,7 @@ export class SignalClient {
354
372
  };
355
373
 
356
374
  this.ws.onclose = (ev: CloseEvent) => {
357
- log.warn(`websocket closed`, { ev });
375
+ this.log.warn(`websocket closed`, { ...this.logContext, reason: ev.reason });
358
376
  this.handleOnClose(ev.reason);
359
377
  };
360
378
  } finally {
@@ -414,7 +432,7 @@ export class SignalClient {
414
432
 
415
433
  // initial offer after joining
416
434
  sendOffer(offer: RTCSessionDescriptionInit) {
417
- log.debug('sending offer', offer);
435
+ this.log.debug('sending offer', { ...this.logContext, offerSdp: offer.sdp });
418
436
  this.sendRequest({
419
437
  case: 'offer',
420
438
  value: toProtoSessionDescription(offer),
@@ -423,7 +441,7 @@ export class SignalClient {
423
441
 
424
442
  // answer a server-initiated offer
425
443
  sendAnswer(answer: RTCSessionDescriptionInit) {
426
- log.debug('sending answer');
444
+ this.log.debug('sending answer', { ...this.logContext, answerSdp: answer.sdp });
427
445
  return this.sendRequest({
428
446
  case: 'answer',
429
447
  value: toProtoSessionDescription(answer),
@@ -431,7 +449,7 @@ export class SignalClient {
431
449
  }
432
450
 
433
451
  sendIceCandidate(candidate: RTCIceCandidateInit, target: SignalTarget) {
434
- log.trace('sending ice candidate', candidate);
452
+ this.log.trace('sending ice candidate', { ...this.logContext, candidate });
435
453
  return this.sendRequest({
436
454
  case: 'trickle',
437
455
  value: new TrickleRequest({
@@ -561,7 +579,10 @@ export class SignalClient {
561
579
  await sleep(this.signalLatency);
562
580
  }
563
581
  if (!this.ws || this.ws.readyState !== this.ws.OPEN) {
564
- log.error(`cannot send signal request before connected, type: ${message?.case}`);
582
+ this.log.error(
583
+ `cannot send signal request before connected, type: ${message?.case}`,
584
+ this.logContext,
585
+ );
565
586
  return;
566
587
  }
567
588
  const req = new SignalRequest({ message });
@@ -573,14 +594,14 @@ export class SignalClient {
573
594
  this.ws.send(req.toBinary());
574
595
  }
575
596
  } catch (e) {
576
- log.error('error sending signal message', { error: e });
597
+ this.log.error('error sending signal message', { ...this.logContext, error: e });
577
598
  }
578
599
  }
579
600
 
580
601
  private handleSignalResponse(res: SignalResponse) {
581
602
  const msg = res.message;
582
603
  if (msg == undefined) {
583
- log.debug('received unsupported message');
604
+ this.log.debug('received unsupported message', this.logContext);
584
605
  return;
585
606
  }
586
607
 
@@ -658,7 +679,7 @@ export class SignalClient {
658
679
  this.resetPingTimeout();
659
680
  pingHandled = true;
660
681
  } else {
661
- log.debug('unsupported message', msg);
682
+ this.log.debug('unsupported message', { ...this.logContext, msgCase: msg.case });
662
683
  }
663
684
 
664
685
  if (!pingHandled) {
@@ -679,14 +700,14 @@ export class SignalClient {
679
700
  if (this.state === SignalConnectionState.DISCONNECTED) return;
680
701
  const onCloseCallback = this.onClose;
681
702
  await this.close();
682
- log.debug(`websocket connection closed: ${reason}`);
703
+ this.log.debug(`websocket connection closed: ${reason}`, { ...this.logContext, reason });
683
704
  if (onCloseCallback) {
684
705
  onCloseCallback(reason);
685
706
  }
686
707
  }
687
708
 
688
709
  private handleWSError(ev: Event) {
689
- log.error('websocket error', ev);
710
+ this.log.error('websocket error', { ...this.logContext, error: ev });
690
711
  }
691
712
 
692
713
  /**
@@ -696,14 +717,15 @@ export class SignalClient {
696
717
  private resetPingTimeout() {
697
718
  this.clearPingTimeout();
698
719
  if (!this.pingTimeoutDuration) {
699
- log.warn('ping timeout duration not set');
720
+ this.log.warn('ping timeout duration not set', this.logContext);
700
721
  return;
701
722
  }
702
723
  this.pingTimeout = CriticalTimers.setTimeout(() => {
703
- log.warn(
724
+ this.log.warn(
704
725
  `ping timeout triggered. last pong received at: ${new Date(
705
726
  Date.now() - this.pingTimeoutDuration! * 1000,
706
727
  ).toUTCString()}`,
728
+ this.logContext,
707
729
  );
708
730
  this.handleOnClose('ping timeout');
709
731
  }, this.pingTimeoutDuration * 1000);
@@ -722,17 +744,17 @@ export class SignalClient {
722
744
  this.clearPingInterval();
723
745
  this.resetPingTimeout();
724
746
  if (!this.pingIntervalDuration) {
725
- log.warn('ping interval duration not set');
747
+ this.log.warn('ping interval duration not set', this.logContext);
726
748
  return;
727
749
  }
728
- log.debug('start ping interval');
750
+ this.log.debug('start ping interval', this.logContext);
729
751
  this.pingInterval = CriticalTimers.setInterval(() => {
730
752
  this.sendPing();
731
753
  }, this.pingIntervalDuration * 1000);
732
754
  }
733
755
 
734
756
  private clearPingInterval() {
735
- log.debug('clearing ping interval');
757
+ this.log.debug('clearing ping interval', this.logContext);
736
758
  this.clearPingTimeout();
737
759
  if (this.pingInterval) {
738
760
  CriticalTimers.clearInterval(this.pingInterval);
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { LogLevel, setLogExtension, setLogLevel } from './logger';
1
+ import { LogLevel, getLogger, setLogExtension, setLogLevel } from './logger';
2
2
  import { DataPacket_Kind, DisconnectReason, VideoQuality } from './proto/livekit_models_pb';
3
3
  import DefaultReconnectPolicy from './room/DefaultReconnectPolicy';
4
4
  import Room, { ConnectionState, RoomState } from './room/Room';
@@ -55,6 +55,7 @@ export {
55
55
  supportsVP9,
56
56
  createAudioAnalyser,
57
57
  LogLevel,
58
+ getLogger,
58
59
  Room,
59
60
  ConnectionState,
60
61
  RoomState,
package/src/logger.ts CHANGED
@@ -9,9 +9,22 @@ export enum LogLevel {
9
9
  silent = 5,
10
10
  }
11
11
 
12
+ export enum LoggerNames {
13
+ Default = 'livekit',
14
+ Room = 'livekit-room',
15
+ Participant = 'livekit-participant',
16
+ Track = 'livekit-track',
17
+ Publication = 'livekit-track-publication',
18
+ Engine = 'livekit-engine',
19
+ Signal = 'livekit-signal',
20
+ PCManager = 'livekit-pc-manager',
21
+ PCTransport = 'livekit-pc-transport',
22
+ E2EE = 'lk-e2ee',
23
+ }
24
+
12
25
  type LogLevelString = keyof typeof LogLevel;
13
26
 
14
- type StructuredLogger = {
27
+ export type StructuredLogger = {
15
28
  trace: (msg: string, context?: object) => void;
16
29
  debug: (msg: string, context?: object) => void;
17
30
  info: (msg: string, context?: object) => void;
@@ -20,17 +33,28 @@ type StructuredLogger = {
20
33
  setDefaultLevel: (level: log.LogLevelDesc) => void;
21
34
  };
22
35
 
23
- const livekitLogger = log.getLogger('livekit');
36
+ let livekitLogger = log.getLogger('livekit');
24
37
 
25
38
  livekitLogger.setDefaultLevel(LogLevel.info);
26
39
 
27
40
  export default livekitLogger as StructuredLogger;
28
41
 
29
- export function setLogLevel(level: LogLevel | LogLevelString, loggerName?: 'livekit' | 'lk-e2ee') {
42
+ /**
43
+ * @internal
44
+ */
45
+ export function getLogger(name: string) {
46
+ const logger = log.getLogger(name);
47
+ logger.setDefaultLevel(livekitLogger.getLevel());
48
+ return logger as StructuredLogger;
49
+ }
50
+
51
+ export function setLogLevel(level: LogLevel | LogLevelString, loggerName?: LoggerNames) {
30
52
  if (loggerName) {
31
53
  log.getLogger(loggerName).setLevel(level);
32
54
  }
33
- for (const logger of Object.values(log.getLoggers())) {
55
+ for (const logger of Object.entries(log.getLoggers())
56
+ .filter(([logrName]) => logrName.startsWith('livekit'))
57
+ .map(([, logr]) => logr)) {
34
58
  logger.setLevel(level);
35
59
  }
36
60
  }
@@ -41,10 +65,10 @@ export type LogExtension = (level: LogLevel, msg: string, context?: object) => v
41
65
  * use this to hook into the logging function to allow sending internal livekit logs to third party services
42
66
  * if set, the browser logs will lose their stacktrace information (see https://github.com/pimterry/loglevel#writing-plugins)
43
67
  */
44
- export function setLogExtension(extension: LogExtension) {
45
- const originalFactory = livekitLogger.methodFactory;
68
+ export function setLogExtension(extension: LogExtension, logger = livekitLogger) {
69
+ const originalFactory = logger.methodFactory;
46
70
 
47
- livekitLogger.methodFactory = (methodName, configLevel, loggerName) => {
71
+ logger.methodFactory = (methodName, configLevel, loggerName) => {
48
72
  const rawMethod = originalFactory(methodName, configLevel, loggerName);
49
73
 
50
74
  const logLevel = LogLevel[methodName as LogLevelString];
@@ -58,7 +82,7 @@ export function setLogExtension(extension: LogExtension) {
58
82
  }
59
83
  };
60
84
  };
61
- livekitLogger.setLevel(livekitLogger.getLevel()); // Be sure to call setLevel method in order to apply plugin
85
+ logger.setLevel(logger.getLevel()); // Be sure to call setLevel method in order to apply plugin
62
86
  }
63
87
 
64
88
  export const workerLogger = log.getLogger('lk-e2ee') as StructuredLogger;
package/src/options.ts CHANGED
@@ -92,6 +92,8 @@ export interface InternalRoomOptions {
92
92
  * @experimental
93
93
  */
94
94
  e2ee?: E2EEOptions;
95
+
96
+ loggerName?: string;
95
97
  }
96
98
 
97
99
  /**
@@ -2,8 +2,9 @@ import { EventEmitter } from 'events';
2
2
  import type { MediaDescription } from 'sdp-transform';
3
3
  import { parse, write } from 'sdp-transform';
4
4
  import { debounce } from 'ts-debounce';
5
- import log from '../logger';
5
+ import log, { LoggerNames, getLogger } from '../logger';
6
6
  import { NegotiationError, UnexpectedConnectionState } from './errors';
7
+ import type { LoggerOptions } from './types';
7
8
  import { ddExtensionURI, isChromiumBased, isSVCCodec } from './utils';
8
9
 
9
10
  /** @internal */
@@ -43,6 +44,10 @@ export default class PCTransport extends EventEmitter {
43
44
 
44
45
  private mediaConstraints: Record<string, unknown>;
45
46
 
47
+ private log = log;
48
+
49
+ private loggerOptions: LoggerOptions;
50
+
46
51
  pendingCandidates: RTCIceCandidateInit[] = [];
47
52
 
48
53
  restartingIce: boolean = false;
@@ -71,8 +76,14 @@ export default class PCTransport extends EventEmitter {
71
76
 
72
77
  onTrack?: (ev: RTCTrackEvent) => void;
73
78
 
74
- constructor(config?: RTCConfiguration, mediaConstraints: Record<string, unknown> = {}) {
79
+ constructor(
80
+ config?: RTCConfiguration,
81
+ mediaConstraints: Record<string, unknown> = {},
82
+ loggerOptions: LoggerOptions = {},
83
+ ) {
75
84
  super();
85
+ this.log = getLogger(loggerOptions.loggerName ?? LoggerNames.PCTransport);
86
+ this.loggerOptions = loggerOptions;
76
87
  this.config = config;
77
88
  this.mediaConstraints = mediaConstraints;
78
89
  this._pc = this.createPC();
@@ -112,6 +123,12 @@ export default class PCTransport extends EventEmitter {
112
123
  return pc;
113
124
  }
114
125
 
126
+ private get logContext() {
127
+ return {
128
+ ...this.loggerOptions.loggerContextCb?.(),
129
+ };
130
+ }
131
+
115
132
  get isICEConnected(): boolean {
116
133
  return (
117
134
  this._pc !== null &&
@@ -229,7 +246,7 @@ export default class PCTransport extends EventEmitter {
229
246
  }
230
247
 
231
248
  if (options?.iceRestart) {
232
- log.debug('restarting ICE');
249
+ this.log.debug('restarting ICE', this.logContext);
233
250
  this.restartingIce = true;
234
251
  }
235
252
 
@@ -246,12 +263,12 @@ export default class PCTransport extends EventEmitter {
246
263
  return;
247
264
  }
248
265
  } else if (!this._pc || this._pc.signalingState === 'closed') {
249
- log.warn('could not createOffer with closed peer connection');
266
+ this.log.warn('could not createOffer with closed peer connection', this.logContext);
250
267
  return;
251
268
  }
252
269
 
253
270
  // actually negotiate
254
- log.debug('starting to negotiate');
271
+ this.log.debug('starting to negotiate', this.logContext);
255
272
  const offer = await this.pc.createOffer(options);
256
273
 
257
274
  const sdpParsed = parse(offer.sdp ?? '');
@@ -452,7 +469,10 @@ export default class PCTransport extends EventEmitter {
452
469
  const originalSdp = sd.sdp;
453
470
  sd.sdp = munged;
454
471
  try {
455
- log.debug(`setting munged ${remote ? 'remote' : 'local'} description`);
472
+ this.log.debug(
473
+ `setting munged ${remote ? 'remote' : 'local'} description`,
474
+ this.logContext,
475
+ );
456
476
  if (remote) {
457
477
  await this.pc.setRemoteDescription(sd);
458
478
  } else {
@@ -460,7 +480,8 @@ export default class PCTransport extends EventEmitter {
460
480
  }
461
481
  return;
462
482
  } catch (e) {
463
- log.warn(`not able to set ${sd.type}, falling back to unmodified sdp`, {
483
+ this.log.warn(`not able to set ${sd.type}, falling back to unmodified sdp`, {
484
+ ...this.logContext,
464
485
  error: e,
465
486
  sdp: munged,
466
487
  });
@@ -491,7 +512,7 @@ export default class PCTransport extends EventEmitter {
491
512
  if (!remote && this.pc.remoteDescription) {
492
513
  fields.remoteSdp = this.pc.remoteDescription;
493
514
  }
494
- log.error(`unable to set ${sd.type}`, fields);
515
+ this.log.error(`unable to set ${sd.type}`, { ...this.logContext, fields });
495
516
  throw new NegotiationError(msg);
496
517
  }
497
518
  }