@stream-io/video-client 1.35.0 → 1.36.0

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 (52) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/index.browser.es.js +217 -236
  3. package/dist/index.browser.es.js.map +1 -1
  4. package/dist/index.cjs.js +239 -240
  5. package/dist/index.cjs.js.map +1 -1
  6. package/dist/index.es.js +217 -236
  7. package/dist/index.es.js.map +1 -1
  8. package/dist/src/Call.d.ts +3 -2
  9. package/dist/src/StreamVideoClient.d.ts +3 -2
  10. package/dist/src/coordinator/connection/client.d.ts +3 -2
  11. package/dist/src/coordinator/connection/connection.d.ts +2 -1
  12. package/dist/src/coordinator/connection/types.d.ts +17 -1
  13. package/dist/src/devices/DeviceManager.d.ts +2 -2
  14. package/dist/src/logger.d.ts +9 -6
  15. package/dist/src/rpc/createClient.d.ts +3 -2
  16. package/dist/src/rtc/BasePeerConnection.d.ts +3 -2
  17. package/dist/src/store/CallState.d.ts +1 -1
  18. package/package.json +4 -3
  19. package/src/Call.ts +36 -48
  20. package/src/StreamSfuClient.ts +11 -11
  21. package/src/StreamVideoClient.ts +19 -21
  22. package/src/coordinator/connection/client.ts +21 -30
  23. package/src/coordinator/connection/connection.ts +5 -4
  24. package/src/coordinator/connection/location.ts +4 -4
  25. package/src/coordinator/connection/types.ts +21 -2
  26. package/src/devices/BrowserPermission.ts +5 -5
  27. package/src/devices/CameraManager.ts +3 -4
  28. package/src/devices/DeviceManager.ts +11 -11
  29. package/src/devices/MicrophoneManager.ts +8 -8
  30. package/src/devices/devices.ts +18 -14
  31. package/src/events/call.ts +6 -9
  32. package/src/events/internal.ts +4 -4
  33. package/src/events/mutes.ts +3 -8
  34. package/src/helpers/DynascaleManager.ts +9 -9
  35. package/src/helpers/RNSpeechDetector.ts +5 -5
  36. package/src/helpers/clientUtils.ts +1 -3
  37. package/src/helpers/ensureExhausted.ts +2 -2
  38. package/src/logger.ts +9 -34
  39. package/src/rpc/__tests__/createClient.test.ts +5 -1
  40. package/src/rpc/createClient.ts +4 -3
  41. package/src/rpc/retryable.ts +4 -2
  42. package/src/rtc/BasePeerConnection.ts +19 -22
  43. package/src/rtc/Dispatcher.ts +4 -4
  44. package/src/rtc/IceTrickleBuffer.ts +5 -5
  45. package/src/rtc/Publisher.ts +8 -8
  46. package/src/rtc/Subscriber.ts +12 -16
  47. package/src/rtc/signal.ts +7 -7
  48. package/src/stats/CallStateStatsReporter.ts +4 -4
  49. package/src/stats/SfuStatsReporter.ts +6 -6
  50. package/src/store/CallState.ts +3 -3
  51. package/src/store/rxUtils.ts +4 -2
  52. package/src/store/stateStore.ts +6 -6
@@ -9,12 +9,12 @@ import {
9
9
  startWith,
10
10
  tap,
11
11
  } from 'rxjs';
12
- import { getLogger } from '../logger';
13
12
  import { BrowserPermission } from './BrowserPermission';
14
13
  import { lazy } from '../helpers/lazy';
15
14
  import { isFirefox } from '../helpers/browsers';
16
15
  import { dumpStream, Tracer } from '../stats';
17
16
  import { getCurrentValue } from '../store/rxUtils';
17
+ import { videoLoggerSystem } from '../logger';
18
18
 
19
19
  /**
20
20
  * Returns an Observable that emits the list of available devices
@@ -266,15 +266,16 @@ export const getAudioStream = async (
266
266
  if (isNotFoundOrOverconstrainedError(error) && trackConstraints?.deviceId) {
267
267
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
268
268
  const { deviceId, ...relaxedConstraints } = trackConstraints;
269
- getLogger(['devices'])(
270
- 'warn',
271
- 'Failed to get audio stream, will try again with relaxed constraints',
272
- { error, constraints, relaxedConstraints },
273
- );
269
+ videoLoggerSystem
270
+ .getLogger('devices')
271
+ .warn(
272
+ 'Failed to get audio stream, will try again with relaxed constraints',
273
+ { error, constraints, relaxedConstraints },
274
+ );
274
275
  return getAudioStream(relaxedConstraints);
275
276
  }
276
277
 
277
- getLogger(['devices'])('error', 'Failed to get audio stream', {
278
+ videoLoggerSystem.getLogger('devices').error('Failed to get audio stream', {
278
279
  error,
279
280
  constraints,
280
281
  });
@@ -310,15 +311,16 @@ export const getVideoStream = async (
310
311
  if (isNotFoundOrOverconstrainedError(error) && trackConstraints?.deviceId) {
311
312
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
312
313
  const { deviceId, ...relaxedConstraints } = trackConstraints;
313
- getLogger(['devices'])(
314
- 'warn',
315
- 'Failed to get video stream, will try again with relaxed constraints',
316
- { error, constraints, relaxedConstraints },
317
- );
314
+ videoLoggerSystem
315
+ .getLogger('devices')
316
+ .warn(
317
+ 'Failed to get video stream, will try again with relaxed constraints',
318
+ { error, constraints, relaxedConstraints },
319
+ );
318
320
  return getVideoStream(relaxedConstraints);
319
321
  }
320
322
 
321
- getLogger(['devices'])('error', 'Failed to get video stream', {
323
+ videoLoggerSystem.getLogger('devices').error('Failed to get video stream', {
322
324
  error,
323
325
  constraints,
324
326
  });
@@ -373,7 +375,9 @@ export const getScreenShareStream = async (
373
375
  return stream;
374
376
  } catch (e) {
375
377
  tracer?.trace(`${tag}OnFailure`, (e as Error).name);
376
- getLogger(['devices'])('error', 'Failed to get screen share stream', e);
378
+ videoLoggerSystem
379
+ .getLogger('devices')
380
+ .error('Failed to get screen share stream', e);
377
381
  throw e;
378
382
  }
379
383
  };
@@ -38,8 +38,7 @@ export const watchCallRejected = (call: Call) => {
38
38
  const { session: callSession } = eventCall;
39
39
 
40
40
  if (!callSession) {
41
- call.logger(
42
- 'warn',
41
+ call.logger.warn(
43
42
  'No call session provided. Ignoring call.rejected event.',
44
43
  event,
45
44
  );
@@ -49,8 +48,7 @@ export const watchCallRejected = (call: Call) => {
49
48
  const rejectedBy = callSession.rejected_by;
50
49
  const { members, callingState } = call.state;
51
50
  if (callingState !== CallingState.RINGING) {
52
- call.logger(
53
- 'info',
51
+ call.logger.info(
54
52
  'Call is not in ringing mode (it is either accepted or rejected already). Ignoring call.rejected event.',
55
53
  event,
56
54
  );
@@ -61,7 +59,7 @@ export const watchCallRejected = (call: Call) => {
61
59
  .filter((m) => m.user_id !== call.currentUserId)
62
60
  .every((m) => rejectedBy[m.user_id]);
63
61
  if (everyoneElseRejected) {
64
- call.logger('info', 'everyone rejected, leaving the call');
62
+ call.logger.info('everyone rejected, leaving the call');
65
63
  await call.leave({
66
64
  reject: true,
67
65
  reason: 'cancel',
@@ -70,7 +68,7 @@ export const watchCallRejected = (call: Call) => {
70
68
  }
71
69
  } else {
72
70
  if (rejectedBy[eventCall.created_by.id]) {
73
- call.logger('info', 'call creator rejected, leaving call');
71
+ call.logger.info('call creator rejected, leaving call');
74
72
  await call.leave({ message: 'ring: creator rejected' });
75
73
  }
76
74
  }
@@ -90,7 +88,7 @@ export const watchCallEnded = (call: Call) => {
90
88
  call
91
89
  .leave({ message: 'call.ended event received', reject: false })
92
90
  .catch((err) => {
93
- call.logger('error', 'Failed to leave call after call.ended ', err);
91
+ call.logger.error('Failed to leave call after call.ended ', err);
94
92
  });
95
93
  }
96
94
  };
@@ -117,8 +115,7 @@ export const watchSfuCallEnded = (call: Call) => {
117
115
  const reason = CallEndedReason[e.reason];
118
116
  await call.leave({ message: `callEnded received: ${reason}` });
119
117
  } catch (err) {
120
- call.logger(
121
- 'error',
118
+ call.logger.error(
122
119
  'Failed to leave call after being ended by the SFU',
123
120
  err,
124
121
  );
@@ -2,7 +2,6 @@ import { Dispatcher } from '../rtc';
2
2
  import { Call } from '../Call';
3
3
  import { CallState } from '../store';
4
4
  import { StreamVideoParticipantPatches } from '../types';
5
- import { getLogger } from '../logger';
6
5
  import { pushToIfMissing, removeFromIfPresent } from '../helpers/array';
7
6
  import type {
8
7
  InboundStateNotification,
@@ -13,6 +12,7 @@ import {
13
12
  WebsocketReconnectStrategy,
14
13
  } from '../gen/video/sfu/models/models';
15
14
  import { OwnCapability } from '../gen/coordinator';
15
+ import { videoLoggerSystem } from '../logger';
16
16
 
17
17
  export const watchConnectionQualityChanged = (
18
18
  dispatcher: Dispatcher,
@@ -60,7 +60,7 @@ export const watchLiveEnded = (dispatcher: Dispatcher, call: Call) => {
60
60
  call.state.setBackstage(true);
61
61
  if (!call.permissionsContext.hasPermission(OwnCapability.JOIN_BACKSTAGE)) {
62
62
  call.leave({ message: 'live ended' }).catch((err) => {
63
- call.logger('error', 'Failed to leave call after live ended', err);
63
+ call.logger.error('Failed to leave call after live ended', err);
64
64
  });
65
65
  }
66
66
  });
@@ -72,9 +72,9 @@ export const watchLiveEnded = (dispatcher: Dispatcher, call: Call) => {
72
72
  export const watchSfuErrorReports = (dispatcher: Dispatcher) => {
73
73
  return dispatcher.on('error', (e) => {
74
74
  if (!e.error) return;
75
- const logger = getLogger(['SfuClient']);
75
+ const logger = videoLoggerSystem.getLogger('SfuClient');
76
76
  const { error, reconnectStrategy } = e;
77
- logger('error', 'SFU reported error', {
77
+ logger.error('SFU reported error', {
78
78
  code: ErrorCode[error.code],
79
79
  reconnectStrategy: WebsocketReconnectStrategy[reconnectStrategy],
80
80
  message: error.message,
@@ -18,8 +18,7 @@ export const handleRemoteSoftMute = (call: Call) => {
18
18
  sessionId === localParticipant?.sessionId
19
19
  ) {
20
20
  const logger = call.logger;
21
- logger(
22
- 'info',
21
+ logger.info(
23
22
  `Local participant's ${TrackType[type]} track is muted remotely`,
24
23
  );
25
24
  try {
@@ -33,14 +32,10 @@ export const handleRemoteSoftMute = (call: Call) => {
33
32
  ) {
34
33
  await call.screenShare.disable();
35
34
  } else {
36
- logger(
37
- 'warn',
38
- 'Unsupported track type to soft mute',
39
- TrackType[type],
40
- );
35
+ logger.warn('Unsupported track type to soft mute', TrackType[type]);
41
36
  }
42
37
  } catch (error) {
43
- logger('error', 'Failed to stop publishing', error);
38
+ logger.error('Failed to stop publishing', error);
44
39
  }
45
40
  }
46
41
  });
@@ -15,7 +15,6 @@ import {
15
15
  takeWhile,
16
16
  } from 'rxjs';
17
17
  import { ViewportTracker } from './ViewportTracker';
18
- import { getLogger } from '../logger';
19
18
  import { isFirefox, isSafari } from './browsers';
20
19
  import {
21
20
  hasScreenShare,
@@ -27,6 +26,7 @@ import type { CallState } from '../store';
27
26
  import type { StreamSfuClient } from '../StreamSfuClient';
28
27
  import { SpeakerManager } from '../devices';
29
28
  import { getCurrentValue, setCurrentValue } from '../store/rxUtils';
29
+ import { videoLoggerSystem } from '../logger';
30
30
 
31
31
  const DEFAULT_VIEWPORT_VISIBILITY_STATE: Record<
32
32
  VideoTrackType,
@@ -66,7 +66,7 @@ export class DynascaleManager {
66
66
  */
67
67
  readonly viewportTracker = new ViewportTracker();
68
68
 
69
- private logger = getLogger(['DynascaleManager']);
69
+ private logger = videoLoggerSystem.getLogger('DynascaleManager');
70
70
  private callState: CallState;
71
71
  private speaker: SpeakerManager;
72
72
  private audioContext: AudioContext | undefined;
@@ -212,7 +212,7 @@ export class DynascaleManager {
212
212
  this.sfuClient
213
213
  ?.updateSubscriptions(this.trackSubscriptions)
214
214
  .catch((err: unknown) => {
215
- this.logger('debug', `Failed to update track subscriptions`, err);
215
+ this.logger.debug(`Failed to update track subscriptions`, err);
216
216
  });
217
217
  };
218
218
 
@@ -324,7 +324,7 @@ export class DynascaleManager {
324
324
  // is not visible (e.g., has display: none).
325
325
  // we treat this as "unsubscription" as we don't want to keep
326
326
  // consuming bandwidth for a video that is not visible on the screen.
327
- this.logger('debug', `Ignoring 0x0 dimension`, boundParticipant);
327
+ this.logger.debug(`Ignoring 0x0 dimension`, boundParticipant);
328
328
  dimension = undefined;
329
329
  }
330
330
  this.callState.updateParticipantTracks(trackType, {
@@ -468,7 +468,7 @@ export class DynascaleManager {
468
468
  setTimeout(() => {
469
469
  videoElement.srcObject = source ?? null;
470
470
  videoElement.play().catch((e) => {
471
- this.logger('warn', `Failed to play stream`, e);
471
+ this.logger.warn(`Failed to play stream`, e);
472
472
  });
473
473
  // we add extra delay until we attempt to force-play
474
474
  // the participant's media stream in Firefox and Safari,
@@ -519,14 +519,14 @@ export class DynascaleManager {
519
519
  if (!deviceId) return;
520
520
  if ('setSinkId' in audioElement) {
521
521
  audioElement.setSinkId(deviceId).catch((e) => {
522
- this.logger('warn', `Can't to set AudioElement sinkId`, e);
522
+ this.logger.warn(`Can't to set AudioElement sinkId`, e);
523
523
  });
524
524
  }
525
525
 
526
526
  if (audioContext && 'setSinkId' in audioContext) {
527
527
  // @ts-expect-error setSinkId is not available in all browsers
528
528
  audioContext.setSinkId(deviceId).catch((e) => {
529
- this.logger('warn', `Can't to set AudioContext sinkId`, e);
529
+ this.logger.warn(`Can't to set AudioContext sinkId`, e);
530
530
  });
531
531
  }
532
532
  };
@@ -574,7 +574,7 @@ export class DynascaleManager {
574
574
  // we will play audio directly through the audio element in other browsers
575
575
  audioElement.muted = false;
576
576
  audioElement.play().catch((e) => {
577
- this.logger('warn', `Failed to play audio stream`, e);
577
+ this.logger.warn(`Failed to play audio stream`, e);
578
578
  });
579
579
  }
580
580
 
@@ -630,7 +630,7 @@ export class DynascaleManager {
630
630
  if (this.audioContext?.state === 'suspended') {
631
631
  this.audioContext
632
632
  .resume()
633
- .catch((err) => this.logger('warn', `Can't resume audio context`, err))
633
+ .catch((err) => this.logger.warn(`Can't resume audio context`, err))
634
634
  .then(() => {
635
635
  document.removeEventListener('click', this.resumeAudioContext);
636
636
  });
@@ -1,7 +1,7 @@
1
1
  import { BaseStats } from '../stats';
2
2
  import { SoundStateChangeHandler } from './sound-detector';
3
3
  import { flatten } from '../stats/utils';
4
- import { getLogger } from '../logger';
4
+ import { videoLoggerSystem } from '../logger';
5
5
 
6
6
  export class RNSpeechDetector {
7
7
  private pc1 = new RTCPeerConnection({});
@@ -64,8 +64,8 @@ export class RNSpeechDetector {
64
64
  this.stop();
65
65
  };
66
66
  } catch (error) {
67
- const logger = getLogger(['RNSpeechDetector']);
68
- logger('error', 'error handling permissions: ', error);
67
+ const logger = videoLoggerSystem.getLogger('RNSpeechDetector');
68
+ logger.error('error handling permissions: ', error);
69
69
  return () => {};
70
70
  }
71
71
  }
@@ -164,8 +164,8 @@ export class RNSpeechDetector {
164
164
  }
165
165
  }
166
166
  } catch (error) {
167
- const logger = getLogger(['RNSpeechDetector']);
168
- logger('error', 'error checking audio level from stats', error);
167
+ const logger = videoLoggerSystem.getLogger('RNSpeechDetector');
168
+ logger.error('error checking audio level from stats', error);
169
169
  }
170
170
  };
171
171
 
@@ -4,7 +4,6 @@ import type {
4
4
  TokenOrProvider,
5
5
  User,
6
6
  } from '../coordinator/connection/types';
7
- import { getLogger } from '../logger';
8
7
  import { StreamClient } from '../coordinator/connection/client';
9
8
  import { getSdkInfo } from './client-details';
10
9
  import { SdkType } from '../gen/video/sfu/models/models';
@@ -50,12 +49,11 @@ export const createCoordinatorClient = (
50
49
  options: StreamClientOptions | undefined,
51
50
  ) => {
52
51
  const clientAppIdentifier = getClientAppIdentifier(options);
53
- const coordinatorLogger = getLogger(['coordinator']);
52
+
54
53
  return new StreamClient(apiKey, {
55
54
  persistUserOnConnectionFailure: true,
56
55
  ...options,
57
56
  clientAppIdentifier,
58
- logger: coordinatorLogger,
59
57
  });
60
58
  };
61
59
 
@@ -1,5 +1,5 @@
1
- import { getLogger } from '../logger';
1
+ import { videoLoggerSystem } from '../logger';
2
2
 
3
3
  export const ensureExhausted = (x: never, message: string) => {
4
- getLogger(['helpers'])('warn', message, x);
4
+ videoLoggerSystem.getLogger('helpers').warn(message, x);
5
5
  };
package/src/logger.ts CHANGED
@@ -1,17 +1,6 @@
1
- import { Logger, LogLevel } from './coordinator/connection/types';
1
+ import * as scopedLogger from '@stream-io/logger';
2
2
  import { isReactNative } from './helpers/platforms';
3
-
4
- // log levels, sorted by verbosity
5
- export const logLevels: Record<LogLevel, number> = Object.freeze({
6
- trace: 0,
7
- debug: 1,
8
- info: 2,
9
- warn: 3,
10
- error: 4,
11
- });
12
-
13
- let logger: Logger | undefined;
14
- let level: LogLevel = 'info';
3
+ import type { Logger } from './coordinator/connection/types';
15
4
 
16
5
  export const logToConsole: Logger = (logLevel, message, ...args) => {
17
6
  let logMethod;
@@ -46,26 +35,12 @@ export const logToConsole: Logger = (logLevel, message, ...args) => {
46
35
  logMethod(message, ...args);
47
36
  };
48
37
 
49
- export const setLogger = (l: Logger, lvl?: LogLevel) => {
50
- logger = l;
51
- if (lvl) {
52
- setLogLevel(lvl);
53
- }
54
- };
38
+ /**
39
+ * @internal
40
+ */
41
+ export type ScopedLogger = scopedLogger.Logger;
55
42
 
56
- export const setLogLevel = (l: LogLevel) => {
57
- level = l;
58
- };
59
-
60
- export const getLogLevel = (): LogLevel => level;
43
+ export { LogLevelEnum } from '@stream-io/logger';
44
+ export type { LogLevel, Sink } from '@stream-io/logger';
61
45
 
62
- export const getLogger = (withTags?: string[]) => {
63
- const loggerMethod = logger || logToConsole;
64
- const tags = (withTags || []).filter(Boolean).join(':');
65
- const result: Logger = (logLevel, message, ...args) => {
66
- if (logLevels[logLevel] >= logLevels[level]) {
67
- loggerMethod(logLevel, `[${tags}]: ${message}`, ...args);
68
- }
69
- };
70
- return result;
71
- };
46
+ export const videoLoggerSystem = scopedLogger.createLoggerSystem();
@@ -8,6 +8,7 @@ import {
8
8
  import { TwirpFetchTransport } from '@protobuf-ts/twirp-transport';
9
9
  import { NextUnaryFn, UnaryCall } from '@protobuf-ts/runtime-rpc';
10
10
  import { promiseWithResolvers } from '../../helpers/promise';
11
+ import { ScopedLogger } from '../../logger';
11
12
 
12
13
  describe('createClient', () => {
13
14
  it('should create a client with TwirpFetchTransport', () => {
@@ -30,7 +31,10 @@ describe('createClient', () => {
30
31
 
31
32
  it('withRequestLogger should log the request', () => {
32
33
  const logger = vi.fn();
33
- const interceptor = withRequestLogger(logger, 'debug');
34
+ const interceptor = withRequestLogger(
35
+ { debug: logger } as unknown as ScopedLogger,
36
+ 'debug',
37
+ );
34
38
  const next = vi.fn().mockReturnValue({});
35
39
  // @ts-expect-error - private field
36
40
  interceptor.interceptUnary(next, { name: 'test' }, null, null);
@@ -10,9 +10,10 @@ import {
10
10
  TwirpOptions,
11
11
  } from '@protobuf-ts/twirp-transport';
12
12
  import { SignalServerClient } from '../gen/video/sfu/signal_rpc/signal.client';
13
- import { Logger, LogLevel } from '../coordinator/connection/types';
14
13
  import type { Trace } from '../stats';
15
14
  import type { SfuResponseWithError } from './retryable';
15
+ import type { ScopedLogger } from '../logger';
16
+ import type { LogLevel } from '@stream-io/logger';
16
17
 
17
18
  const defaultOptions: TwirpOptions = {
18
19
  baseUrl: '',
@@ -40,7 +41,7 @@ export const withHeaders = (
40
41
  };
41
42
 
42
43
  export const withRequestLogger = (
43
- logger: Logger,
44
+ logger: ScopedLogger,
44
45
  level: LogLevel,
45
46
  ): RpcInterceptor => {
46
47
  return {
@@ -51,7 +52,7 @@ export const withRequestLogger = (
51
52
  options: RpcOptions,
52
53
  ): UnaryCall => {
53
54
  const invocation = next(method, input, options);
54
- logger(level, `Invoked SFU RPC method ${method.name}`, {
55
+ logger[level](`Invoked SFU RPC method ${method.name}`, {
55
56
  request: invocation.request,
56
57
  headers: invocation.requestHeaders,
57
58
  response: invocation.response,
@@ -6,7 +6,7 @@ import {
6
6
  import { TwirpErrorCode } from '@protobuf-ts/twirp-transport';
7
7
  import { retryInterval, sleep } from '../coordinator/connection/utils';
8
8
  import { Error as SfuError } from '../gen/video/sfu/models/models';
9
- import { getLogger } from '../logger';
9
+ import { videoLoggerSystem } from '../logger';
10
10
 
11
11
  /**
12
12
  * An internal interface which asserts that "retryable" SFU responses
@@ -48,7 +48,9 @@ export const retryable = async <
48
48
  err.code === TwirpErrorCode[TwirpErrorCode.cancelled];
49
49
  const isAborted = signal?.aborted ?? false;
50
50
  if (isRequestCancelled || isAborted) throw err;
51
- getLogger(['sfu-client', 'rpc'])('debug', `rpc failed (${attempt})`, err);
51
+ videoLoggerSystem
52
+ .getLogger('sfu-client', { tags: ['rpc'] })
53
+ .debug(`rpc failed (${attempt})`, err);
52
54
  attempt++;
53
55
  }
54
56
  } while (!result || result.response.error?.shouldRetry);
@@ -1,8 +1,5 @@
1
- import { getLogger } from '../logger';
2
- import type {
3
- CallEventListener,
4
- Logger,
5
- } from '../coordinator/connection/types';
1
+ import { ScopedLogger, videoLoggerSystem } from '../logger';
2
+ import type { CallEventListener } from '../coordinator/connection/types';
6
3
  import { CallingState, CallState } from '../store';
7
4
  import { createSafeAsyncSubscription } from '../store/rxUtils';
8
5
  import {
@@ -23,7 +20,7 @@ import { BasePeerConnectionOpts, OnReconnectionNeeded } from './types';
23
20
  * @internal
24
21
  */
25
22
  export abstract class BasePeerConnection {
26
- protected readonly logger: Logger;
23
+ protected readonly logger: ScopedLogger;
27
24
  protected readonly peerType: PeerType;
28
25
  protected readonly pc: RTCPeerConnection;
29
26
  protected readonly state: CallState;
@@ -67,10 +64,10 @@ export abstract class BasePeerConnection {
67
64
  this.dispatcher = dispatcher;
68
65
  this.iceRestartDelay = iceRestartDelay;
69
66
  this.onReconnectionNeeded = onReconnectionNeeded;
70
- this.logger = getLogger([
67
+ this.logger = videoLoggerSystem.getLogger(
71
68
  peerType === PeerType.SUBSCRIBER ? 'Subscriber' : 'Publisher',
72
- tag,
73
- ]);
69
+ { tags: [tag] },
70
+ );
74
71
  this.pc = this.createPeerConnection(connectionConfig);
75
72
  this.stats = new StatsTracer(this.pc, peerType, this.trackIdToTrackType);
76
73
  if (enableTracing) {
@@ -142,7 +139,7 @@ export abstract class BasePeerConnection {
142
139
  protected tryRestartIce = () => {
143
140
  this.restartIce().catch((e) => {
144
141
  const reason = 'restartICE() failed, initiating reconnect';
145
- this.logger('error', reason, e);
142
+ this.logger.error(reason, e);
146
143
  const strategy =
147
144
  e instanceof NegotiationError &&
148
145
  e.error.code === ErrorCode.PARTICIPANT_SIGNAL_LOST
@@ -165,7 +162,7 @@ export abstract class BasePeerConnection {
165
162
  const lockKey = `pc.${this.lock}.${event}`;
166
163
  withoutConcurrency(lockKey, async () => fn(e)).catch((err) => {
167
164
  if (this.isDisposed) return;
168
- this.logger('warn', `Error handling ${event}`, err);
165
+ this.logger.warn(`Error handling ${event}`, err);
169
166
  });
170
167
  }),
171
168
  );
@@ -187,7 +184,7 @@ export abstract class BasePeerConnection {
187
184
  async (candidate) => {
188
185
  return this.pc.addIceCandidate(candidate).catch((e) => {
189
186
  if (this.isDisposed) return;
190
- this.logger('warn', `ICE candidate error`, e, candidate);
187
+ this.logger.warn(`ICE candidate error`, e, candidate);
191
188
  });
192
189
  },
193
190
  );
@@ -240,7 +237,7 @@ export abstract class BasePeerConnection {
240
237
  private onIceCandidate = (e: RTCPeerConnectionIceEvent) => {
241
238
  const { candidate } = e;
242
239
  if (!candidate) {
243
- this.logger('debug', 'null ice candidate');
240
+ this.logger.debug('null ice candidate');
244
241
  return;
245
242
  }
246
243
 
@@ -249,7 +246,7 @@ export abstract class BasePeerConnection {
249
246
  .iceTrickle({ peerType: this.peerType, iceCandidate })
250
247
  .catch((err) => {
251
248
  if (this.isDisposed) return;
252
- this.logger('warn', `ICETrickle failed`, err);
249
+ this.logger.warn(`ICETrickle failed`, err);
253
250
  });
254
251
  };
255
252
 
@@ -272,7 +269,7 @@ export abstract class BasePeerConnection {
272
269
  */
273
270
  private onConnectionStateChange = async () => {
274
271
  const state = this.pc.connectionState;
275
- this.logger('debug', `Connection state changed`, state);
272
+ this.logger.debug(`Connection state changed`, state);
276
273
  if (this.tracer && (state === 'connected' || state === 'failed')) {
277
274
  try {
278
275
  const stats = await this.stats.get();
@@ -299,7 +296,7 @@ export abstract class BasePeerConnection {
299
296
  */
300
297
  private onIceConnectionStateChange = () => {
301
298
  const state = this.pc.iceConnectionState;
302
- this.logger('debug', `ICE connection state changed`, state);
299
+ this.logger.debug(`ICE connection state changed`, state);
303
300
  this.handleConnectionStateUpdate(state);
304
301
  };
305
302
 
@@ -316,14 +313,14 @@ export abstract class BasePeerConnection {
316
313
  switch (state) {
317
314
  case 'failed':
318
315
  // in the `failed` state, we try to restart ICE immediately
319
- this.logger('info', 'restartICE due to failed connection');
316
+ this.logger.info('restartICE due to failed connection');
320
317
  this.tryRestartIce();
321
318
  break;
322
319
 
323
320
  case 'disconnected':
324
321
  // in the `disconnected` state, we schedule a restartICE() after a delay
325
322
  // as the browser might recover the connection in the meantime
326
- this.logger('info', 'disconnected connection, scheduling restartICE');
323
+ this.logger.info('disconnected connection, scheduling restartICE');
327
324
  clearTimeout(this.iceRestartTimeout);
328
325
  this.iceRestartTimeout = setTimeout(() => {
329
326
  const currentState = this.pc.iceConnectionState;
@@ -336,7 +333,7 @@ export abstract class BasePeerConnection {
336
333
  case 'connected':
337
334
  // in the `connected` state, we clear the ice restart timeout if it exists
338
335
  if (this.iceRestartTimeout) {
339
- this.logger('info', 'connected connection, canceling restartICE');
336
+ this.logger.info('connected connection, canceling restartICE');
340
337
  clearTimeout(this.iceRestartTimeout);
341
338
  this.iceRestartTimeout = undefined;
342
339
  }
@@ -352,20 +349,20 @@ export abstract class BasePeerConnection {
352
349
  e instanceof RTCPeerConnectionIceErrorEvent
353
350
  ? `${e.errorCode}: ${e.errorText}`
354
351
  : e;
355
- this.logger('debug', 'ICE Candidate error', errorMessage);
352
+ this.logger.debug('ICE Candidate error', errorMessage);
356
353
  };
357
354
 
358
355
  /**
359
356
  * Handles the ICE gathering state change event.
360
357
  */
361
358
  private onIceGatherChange = () => {
362
- this.logger('debug', `ICE Gathering State`, this.pc.iceGatheringState);
359
+ this.logger.debug(`ICE Gathering State`, this.pc.iceGatheringState);
363
360
  };
364
361
 
365
362
  /**
366
363
  * Handles the signaling state change event.
367
364
  */
368
365
  private onSignalingChange = () => {
369
- this.logger('debug', `Signaling state changed`, this.pc.signalingState);
366
+ this.logger.debug(`Signaling state changed`, this.pc.signalingState);
370
367
  };
371
368
  }
@@ -1,6 +1,6 @@
1
1
  import { CallEventListener, EventTypes } from '../coordinator/connection/types';
2
2
  import type { SfuEvent } from '../gen/video/sfu/event/events';
3
- import { getLogger } from '../logger';
3
+ import { videoLoggerSystem } from '../logger';
4
4
 
5
5
  export type SfuEventKinds = NonNullable<SfuEvent['eventPayload']['oneofKind']>;
6
6
  export type AllSfuEvents = {
@@ -53,7 +53,7 @@ export const isSfuEvent = (
53
53
  };
54
54
 
55
55
  export class Dispatcher {
56
- private readonly logger = getLogger(['Dispatcher']);
56
+ private readonly logger = videoLoggerSystem.getLogger('Dispatcher');
57
57
  private subscribers: Partial<
58
58
  Record<SfuEventKinds, CallEventListener<any>[] | undefined>
59
59
  > = {};
@@ -65,14 +65,14 @@ export class Dispatcher {
65
65
  const eventKind = message.eventPayload.oneofKind;
66
66
  if (!eventKind) return;
67
67
  const payload = message.eventPayload[eventKind];
68
- this.logger('debug', `Dispatching ${eventKind}, tag=${tag}`, payload);
68
+ this.logger.debug(`Dispatching ${eventKind}, tag=${tag}`, payload);
69
69
  const listeners = this.subscribers[eventKind];
70
70
  if (!listeners) return;
71
71
  for (const fn of listeners) {
72
72
  try {
73
73
  fn(payload);
74
74
  } catch (e) {
75
- this.logger('warn', 'Listener failed with error', e);
75
+ this.logger.warn('Listener failed with error', e);
76
76
  }
77
77
  }
78
78
  };