@stream-io/video-client 1.20.2 → 1.22.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 (70) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/index.browser.es.js +521 -285
  3. package/dist/index.browser.es.js.map +1 -1
  4. package/dist/index.cjs.js +521 -285
  5. package/dist/index.cjs.js.map +1 -1
  6. package/dist/index.d.ts +0 -1
  7. package/dist/index.es.js +521 -285
  8. package/dist/index.es.js.map +1 -1
  9. package/dist/src/Call.d.ts +3 -0
  10. package/dist/src/StreamSfuClient.d.ts +1 -1
  11. package/dist/src/devices/InputMediaDeviceManager.d.ts +3 -3
  12. package/dist/src/devices/InputMediaDeviceManagerState.d.ts +0 -20
  13. package/dist/src/devices/SpeakerState.d.ts +3 -21
  14. package/dist/src/devices/devices.d.ts +8 -8
  15. package/dist/src/events/call.d.ts +1 -1
  16. package/dist/src/gen/video/sfu/models/models.d.ts +50 -0
  17. package/dist/src/gen/video/sfu/signal_rpc/signal.d.ts +29 -3
  18. package/dist/src/rpc/createClient.d.ts +1 -1
  19. package/dist/src/rtc/BasePeerConnection.d.ts +13 -7
  20. package/dist/src/rtc/Publisher.d.ts +4 -4
  21. package/dist/src/stats/CallStateStatsReporter.d.ts +5 -3
  22. package/dist/src/stats/SfuStatsReporter.d.ts +8 -1
  23. package/dist/src/stats/rtc/StatsTracer.d.ts +54 -0
  24. package/dist/src/stats/rtc/Tracer.d.ts +1 -5
  25. package/dist/src/stats/rtc/index.d.ts +2 -0
  26. package/dist/src/stats/rtc/types.d.ts +19 -0
  27. package/dist/src/stats/types.d.ts +13 -0
  28. package/dist/src/stats/utils.d.ts +14 -0
  29. package/index.ts +0 -4
  30. package/package.json +10 -10
  31. package/src/Call.ts +15 -4
  32. package/src/StreamSfuClient.ts +30 -18
  33. package/src/devices/CameraManager.ts +27 -23
  34. package/src/devices/CameraManagerState.ts +3 -2
  35. package/src/devices/InputMediaDeviceManager.ts +8 -5
  36. package/src/devices/InputMediaDeviceManagerState.ts +10 -31
  37. package/src/devices/MicrophoneManager.ts +1 -1
  38. package/src/devices/MicrophoneManagerState.ts +3 -2
  39. package/src/devices/ScreenShareManager.ts +2 -2
  40. package/src/devices/ScreenShareState.ts +5 -4
  41. package/src/devices/SpeakerManager.ts +2 -1
  42. package/src/devices/SpeakerState.ts +11 -27
  43. package/src/devices/__tests__/CameraManager.test.ts +43 -27
  44. package/src/devices/__tests__/MicrophoneManager.test.ts +5 -3
  45. package/src/devices/__tests__/ScreenShareManager.test.ts +5 -1
  46. package/src/devices/__tests__/mocks.ts +2 -3
  47. package/src/devices/devices.ts +38 -16
  48. package/src/events/__tests__/call.test.ts +23 -0
  49. package/src/events/call.ts +12 -1
  50. package/src/gen/video/sfu/models/models.ts +84 -0
  51. package/src/gen/video/sfu/signal_rpc/signal.ts +50 -2
  52. package/src/helpers/DynascaleManager.ts +0 -9
  53. package/src/rpc/createClient.ts +1 -1
  54. package/src/rtc/BasePeerConnection.ts +43 -16
  55. package/src/rtc/Publisher.ts +18 -16
  56. package/src/rtc/Subscriber.ts +2 -0
  57. package/src/rtc/__tests__/Publisher.test.ts +19 -0
  58. package/src/rtc/__tests__/Subscriber.test.ts +15 -1
  59. package/src/stats/CallStateStatsReporter.ts +19 -31
  60. package/src/stats/SfuStatsReporter.ts +45 -16
  61. package/src/stats/rtc/StatsTracer.ts +289 -0
  62. package/src/stats/rtc/Tracer.ts +1 -6
  63. package/src/stats/rtc/__tests__/Tracer.test.ts +57 -0
  64. package/src/stats/rtc/index.ts +3 -0
  65. package/src/stats/rtc/pc.ts +6 -76
  66. package/src/stats/rtc/types.ts +22 -0
  67. package/src/stats/types.ts +15 -0
  68. package/src/stats/utils.ts +15 -0
  69. package/dist/src/stats/rtc/mediaDevices.d.ts +0 -2
  70. package/src/stats/rtc/mediaDevices.ts +0 -42
@@ -14,6 +14,7 @@ import { TrackType } from '../../gen/video/sfu/models/models';
14
14
  import { CameraManager } from '../CameraManager';
15
15
  import { of } from 'rxjs';
16
16
  import { PermissionsContext } from '../../permissions';
17
+ import { Tracer } from '../../stats';
17
18
 
18
19
  const getVideoStream = vi.hoisted(() =>
19
20
  vi.fn(() => Promise.resolve(mockVideoStream())),
@@ -78,11 +79,14 @@ describe('CameraManager', () => {
78
79
  it('get stream', async () => {
79
80
  await manager.enable();
80
81
 
81
- expect(getVideoStream).toHaveBeenCalledWith({
82
- deviceId: undefined,
83
- width: 1280,
84
- height: 720,
85
- });
82
+ expect(getVideoStream).toHaveBeenCalledWith(
83
+ {
84
+ deviceId: undefined,
85
+ width: 1280,
86
+ height: 720,
87
+ },
88
+ expect.any(Tracer),
89
+ );
86
90
  });
87
91
 
88
92
  it('should get device id from stream', async () => {
@@ -133,29 +137,38 @@ describe('CameraManager', () => {
133
137
 
134
138
  await manager.enable();
135
139
 
136
- expect(getVideoStream).toHaveBeenCalledWith({
137
- deviceId: undefined,
138
- width: 1280,
139
- height: 720,
140
- });
140
+ expect(getVideoStream).toHaveBeenCalledWith(
141
+ {
142
+ deviceId: undefined,
143
+ width: 1280,
144
+ height: 720,
145
+ },
146
+ expect.any(Tracer),
147
+ );
141
148
 
142
149
  await manager.selectDirection('front');
143
150
 
144
- expect(getVideoStream).toHaveBeenCalledWith({
145
- deviceId: undefined,
146
- width: 1280,
147
- height: 720,
148
- facingMode: 'user',
149
- });
151
+ expect(getVideoStream).toHaveBeenCalledWith(
152
+ {
153
+ deviceId: undefined,
154
+ width: 1280,
155
+ height: 720,
156
+ facingMode: 'user',
157
+ },
158
+ expect.any(Tracer),
159
+ );
150
160
 
151
161
  await manager.selectDirection('back');
152
162
 
153
- expect(getVideoStream).toHaveBeenCalledWith({
154
- deviceId: undefined,
155
- facingMode: 'environment',
156
- width: 1280,
157
- height: 720,
158
- });
163
+ expect(getVideoStream).toHaveBeenCalledWith(
164
+ {
165
+ deviceId: undefined,
166
+ facingMode: 'environment',
167
+ width: 1280,
168
+ height: 720,
169
+ },
170
+ expect.any(Tracer),
171
+ );
159
172
  });
160
173
 
161
174
  it(`shouldn't set deviceId and facingMode at the same time`, async () => {
@@ -163,11 +176,14 @@ describe('CameraManager', () => {
163
176
 
164
177
  await manager.flip();
165
178
 
166
- expect(getVideoStream).toHaveBeenCalledWith({
167
- facingMode: 'environment',
168
- width: 1280,
169
- height: 720,
170
- });
179
+ expect(getVideoStream).toHaveBeenCalledWith(
180
+ {
181
+ facingMode: 'environment',
182
+ width: 1280,
183
+ height: 720,
184
+ },
185
+ expect.any(Tracer),
186
+ );
171
187
 
172
188
  const deviceId = mockVideoDevices[1].deviceId;
173
189
  await manager.select(deviceId);
@@ -24,6 +24,7 @@ import {
24
24
  SoundStateChangeHandler,
25
25
  } from '../../helpers/sound-detector';
26
26
  import { PermissionsContext } from '../../permissions';
27
+ import { Tracer } from '../../stats';
27
28
 
28
29
  vi.mock('../devices.ts', () => {
29
30
  console.log('MOCKING devices API');
@@ -92,9 +93,10 @@ describe('MicrophoneManager', () => {
92
93
  it('get stream', async () => {
93
94
  await manager.enable();
94
95
 
95
- expect(getAudioStream).toHaveBeenCalledWith({
96
- deviceId: undefined,
97
- });
96
+ expect(getAudioStream).toHaveBeenCalledWith(
97
+ { deviceId: undefined },
98
+ expect.any(Tracer),
99
+ );
98
100
  });
99
101
 
100
102
  it('should get device id from stream', async () => {
@@ -7,6 +7,7 @@ import * as RxUtils from '../../store/rxUtils';
7
7
  import { mockCall, mockDeviceIds$, mockScreenShareStream } from './mocks';
8
8
  import { getScreenShareStream } from '../devices';
9
9
  import { TrackType } from '../../gen/video/sfu/models/models';
10
+ import { Tracer } from '../../stats';
10
11
 
11
12
  vi.mock('../devices.ts', () => {
12
13
  console.log('MOCKING devices API');
@@ -50,7 +51,7 @@ describe('ScreenShareManager', () => {
50
51
  });
51
52
 
52
53
  it('select device', async () => {
53
- await expect(manager.select('any-device-id')).rejects.toThrowError();
54
+ await expect(manager.select()).rejects.toThrowError();
54
55
  });
55
56
 
56
57
  it('get stream', async () => {
@@ -62,6 +63,7 @@ describe('ScreenShareManager', () => {
62
63
  expect.objectContaining({
63
64
  deviceId: undefined,
64
65
  }),
66
+ expect.any(Tracer),
65
67
  );
66
68
  });
67
69
 
@@ -75,6 +77,7 @@ describe('ScreenShareManager', () => {
75
77
  deviceId: undefined,
76
78
  audio: false,
77
79
  }),
80
+ expect.any(Tracer),
78
81
  );
79
82
  });
80
83
 
@@ -106,6 +109,7 @@ describe('ScreenShareManager', () => {
106
109
  height: 600,
107
110
  },
108
111
  }),
112
+ expect.any(Tracer),
109
113
  );
110
114
  });
111
115
 
@@ -7,6 +7,7 @@ import {
7
7
  import { Call } from '../../Call';
8
8
  import { of, Subject } from 'rxjs';
9
9
  import { BrowserPermission } from '../BrowserPermission';
10
+ import { Tracer } from '../../stats';
10
11
 
11
12
  export const mockVideoDevices = [
12
13
  {
@@ -93,13 +94,11 @@ export const mockCall = (): Partial<Call> => {
93
94
  });
94
95
  return {
95
96
  state: callState,
96
- publishVideoStream: vi.fn(),
97
- publishAudioStream: vi.fn(),
98
- publishScreenShareStream: vi.fn(),
99
97
  publish: vi.fn(),
100
98
  stopPublish: vi.fn(),
101
99
  notifyNoiseCancellationStarting: vi.fn().mockResolvedValue(undefined),
102
100
  notifyNoiseCancellationStopped: vi.fn().mockResolvedValue(undefined),
101
+ tracer: new Tracer('tests'),
103
102
  };
104
103
  };
105
104
 
@@ -12,6 +12,7 @@ import { getLogger } from '../logger';
12
12
  import { BrowserPermission } from './BrowserPermission';
13
13
  import { lazy } from '../helpers/lazy';
14
14
  import { isFirefox } from '../helpers/browsers';
15
+ import { dumpStream, Tracer } from '../stats';
15
16
 
16
17
  /**
17
18
  * Returns an Observable that emits the list of available devices
@@ -158,15 +159,27 @@ export const getAudioOutputDevices = lazy(() => {
158
159
  );
159
160
  });
160
161
 
161
- const getStream = async (constraints: MediaStreamConstraints) => {
162
- const stream = await navigator.mediaDevices.getUserMedia(constraints);
163
- if (isFirefox()) {
164
- // When enumerating devices, Firefox will hide device labels unless there's been
165
- // an active user media stream on the page. So we force device list updates after
166
- // every successful getUserMedia call.
167
- navigator.mediaDevices.dispatchEvent(new Event('devicechange'));
162
+ let getUserMediaExecId = 0;
163
+ const getStream = async (
164
+ constraints: MediaStreamConstraints,
165
+ tracer: Tracer | undefined,
166
+ ) => {
167
+ const tag = `navigator.mediaDevices.getUserMedia.${getUserMediaExecId++}.`;
168
+ try {
169
+ tracer?.trace(tag, constraints);
170
+ const stream = await navigator.mediaDevices.getUserMedia(constraints);
171
+ tracer?.trace(`${tag}OnSuccess`, dumpStream(stream));
172
+ if (isFirefox()) {
173
+ // When enumerating devices, Firefox will hide device labels unless there's been
174
+ // an active user media stream on the page. So we force device list updates after
175
+ // every successful getUserMedia call.
176
+ navigator.mediaDevices.dispatchEvent(new Event('devicechange'));
177
+ }
178
+ return stream;
179
+ } catch (error) {
180
+ tracer?.trace(`${tag}OnFailure`, (error as Error).name);
181
+ throw error;
168
182
  }
169
- return stream;
170
183
  };
171
184
 
172
185
  function isNotFoundOrOverconstrainedError(error: unknown) {
@@ -195,12 +208,13 @@ function isNotFoundOrOverconstrainedError(error: unknown) {
195
208
  * Returns an audio media stream that fulfills the given constraints.
196
209
  * If no constraints are provided, it uses the browser's default ones.
197
210
  *
198
- * @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
199
211
  * @param trackConstraints the constraints to use when requesting the stream.
200
- * @returns the new `MediaStream` fulfilling the given constraints.
212
+ * @param tracer the tracer to use for tracing the stream creation.
213
+ * @returns a new `MediaStream` fulfilling the given constraints.
201
214
  */
202
215
  export const getAudioStream = async (
203
216
  trackConstraints?: MediaTrackConstraints,
217
+ tracer?: Tracer,
204
218
  ): Promise<MediaStream> => {
205
219
  const constraints: MediaStreamConstraints = {
206
220
  audio: {
@@ -214,7 +228,7 @@ export const getAudioStream = async (
214
228
  throwOnNotAllowed: true,
215
229
  forcePrompt: true,
216
230
  });
217
- return await getStream(constraints);
231
+ return await getStream(constraints, tracer);
218
232
  } catch (error) {
219
233
  if (isNotFoundOrOverconstrainedError(error) && trackConstraints?.deviceId) {
220
234
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -239,12 +253,13 @@ export const getAudioStream = async (
239
253
  * Returns a video media stream that fulfills the given constraints.
240
254
  * If no constraints are provided, it uses the browser's default ones.
241
255
  *
242
- * @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
243
256
  * @param trackConstraints the constraints to use when requesting the stream.
257
+ * @param tracer the tracer to use for tracing the stream creation.
244
258
  * @returns a new `MediaStream` fulfilling the given constraints.
245
259
  */
246
260
  export const getVideoStream = async (
247
261
  trackConstraints?: MediaTrackConstraints,
262
+ tracer?: Tracer,
248
263
  ): Promise<MediaStream> => {
249
264
  const constraints: MediaStreamConstraints = {
250
265
  video: {
@@ -257,7 +272,7 @@ export const getVideoStream = async (
257
272
  throwOnNotAllowed: true,
258
273
  forcePrompt: true,
259
274
  });
260
- return await getStream(constraints);
275
+ return await getStream(constraints, tracer);
261
276
  } catch (error) {
262
277
  if (isNotFoundOrOverconstrainedError(error) && trackConstraints?.deviceId) {
263
278
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -278,21 +293,25 @@ export const getVideoStream = async (
278
293
  }
279
294
  };
280
295
 
296
+ let getDisplayMediaExecId = 0;
297
+
281
298
  /**
282
299
  * Prompts the user for a permission to share a screen.
283
300
  * If the user grants the permission, a screen sharing stream is returned. Throws otherwise.
284
301
  *
285
302
  * The callers of this API are responsible to handle the possible errors.
286
303
  *
287
- * @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
288
- *
289
304
  * @param options any additional options to pass to the [`getDisplayMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia) API.
305
+ * @param tracer the tracer to use for tracing the stream creation.
290
306
  */
291
307
  export const getScreenShareStream = async (
292
308
  options?: DisplayMediaStreamOptions,
309
+ tracer?: Tracer | undefined,
293
310
  ) => {
311
+ const tag = `navigator.mediaDevices.getDisplayMedia.${getDisplayMediaExecId++}.`;
294
312
  try {
295
- return await navigator.mediaDevices.getDisplayMedia({
313
+ tracer?.trace(tag, options);
314
+ const stream = await navigator.mediaDevices.getDisplayMedia({
296
315
  video: true,
297
316
  audio: {
298
317
  channelCount: {
@@ -306,7 +325,10 @@ export const getScreenShareStream = async (
306
325
  systemAudio: 'include',
307
326
  ...options,
308
327
  });
328
+ tracer?.trace(`${tag}OnSuccess`, dumpStream(stream));
329
+ return stream;
309
330
  } catch (e) {
331
+ tracer?.trace(`${tag}OnFailure`, (e as Error).name);
310
332
  getLogger(['devices'])('error', 'Failed to get screen share stream', e);
311
333
  throw e;
312
334
  }
@@ -10,6 +10,7 @@ import {
10
10
  CallAcceptedEvent,
11
11
  CallEndedEvent,
12
12
  CallResponse,
13
+ OwnCapability,
13
14
  RejectCallResponse,
14
15
  } from '../../gen/coordinator';
15
16
  import { Call } from '../../Call';
@@ -295,6 +296,28 @@ describe('Call ringing events', () => {
295
296
 
296
297
  expect(call.leave).not.toHaveBeenCalled();
297
298
  });
299
+
300
+ it('will stay in backstage if live ended and has permission', async () => {
301
+ const call = fakeCall();
302
+ call.state.setBackstage(false);
303
+ call.permissionsContext.setPermissions([OwnCapability.JOIN_BACKSTAGE]);
304
+ vi.spyOn(call, 'leave').mockImplementation(async () => {
305
+ console.log(`TEST: leave() called`);
306
+ });
307
+
308
+ watchSfuCallEnded(call);
309
+ const event: SfuEvent = {
310
+ eventPayload: {
311
+ oneofKind: 'callEnded',
312
+ callEnded: { reason: CallEndedReason.LIVE_ENDED },
313
+ },
314
+ };
315
+ // @ts-expect-error type issue
316
+ call['dispatcher'].dispatch(event);
317
+
318
+ expect(call.leave).not.toHaveBeenCalled();
319
+ expect(call.state.backstage).toBe(true);
320
+ });
298
321
  });
299
322
 
300
323
  describe('call.leave', () => {
@@ -1,6 +1,10 @@
1
1
  import { CallingState } from '../store';
2
2
  import { Call } from '../Call';
3
- import type { CallAcceptedEvent, CallRejectedEvent } from '../gen/coordinator';
3
+ import {
4
+ CallAcceptedEvent,
5
+ CallRejectedEvent,
6
+ OwnCapability,
7
+ } from '../gen/coordinator';
4
8
  import { CallEnded } from '../gen/video/sfu/event/events';
5
9
  import { CallEndedReason } from '../gen/video/sfu/models/models';
6
10
 
@@ -99,6 +103,13 @@ export const watchSfuCallEnded = (call: Call) => {
99
103
  return call.on('callEnded', async (e: CallEnded) => {
100
104
  if (call.state.callingState === CallingState.LEFT) return;
101
105
  try {
106
+ if (e.reason === CallEndedReason.LIVE_ENDED) {
107
+ call.state.setBackstage(true);
108
+
109
+ // don't leave the call if the user has permission to join backstage
110
+ const { hasPermission } = call.permissionsContext;
111
+ if (hasPermission(OwnCapability.JOIN_BACKSTAGE)) return;
112
+ }
102
113
  // `call.ended` event arrived after the call is already left
103
114
  // and all event handlers are detached. We need to manually
104
115
  // update the call state to reflect the call has ended.
@@ -626,6 +626,49 @@ export interface AppleState {
626
626
  */
627
627
  isLowPowerModeEnabled: boolean;
628
628
  }
629
+ /**
630
+ * PerformanceStats represents the encoding/decoding statistics for a track.
631
+ *
632
+ * @generated from protobuf message stream.video.sfu.models.PerformanceStats
633
+ */
634
+ export interface PerformanceStats {
635
+ /**
636
+ * the type of the track (e.g., video, audio, screen share)
637
+ *
638
+ * @generated from protobuf field: stream.video.sfu.models.TrackType track_type = 1;
639
+ */
640
+ trackType: TrackType;
641
+ /**
642
+ * the codec used for the track
643
+ *
644
+ * @generated from protobuf field: stream.video.sfu.models.Codec codec = 2;
645
+ */
646
+ codec?: Codec;
647
+ /**
648
+ * the average encode/decode time in ms
649
+ *
650
+ * @generated from protobuf field: float avg_frame_time_ms = 3;
651
+ */
652
+ avgFrameTimeMs: number;
653
+ /**
654
+ * the average fps for the track
655
+ *
656
+ * @generated from protobuf field: float avg_fps = 4;
657
+ */
658
+ avgFps: number;
659
+ /**
660
+ * the track dimensions
661
+ *
662
+ * @generated from protobuf field: stream.video.sfu.models.VideoDimension video_dimension = 5;
663
+ */
664
+ videoDimension?: VideoDimension;
665
+ /**
666
+ * the target bitrate for the track, only for published tracks
667
+ *
668
+ * @generated from protobuf field: int32 target_bitrate = 6;
669
+ */
670
+ targetBitrate: number;
671
+ }
629
672
  /**
630
673
  * @generated from protobuf enum stream.video.sfu.models.PeerType
631
674
  */
@@ -1636,3 +1679,44 @@ class AppleState$Type extends MessageType<AppleState> {
1636
1679
  * @generated MessageType for protobuf message stream.video.sfu.models.AppleState
1637
1680
  */
1638
1681
  export const AppleState = new AppleState$Type();
1682
+ // @generated message type with reflection information, may provide speed optimized methods
1683
+ class PerformanceStats$Type extends MessageType<PerformanceStats> {
1684
+ constructor() {
1685
+ super('stream.video.sfu.models.PerformanceStats', [
1686
+ {
1687
+ no: 1,
1688
+ name: 'track_type',
1689
+ kind: 'enum',
1690
+ T: () => [
1691
+ 'stream.video.sfu.models.TrackType',
1692
+ TrackType,
1693
+ 'TRACK_TYPE_',
1694
+ ],
1695
+ },
1696
+ { no: 2, name: 'codec', kind: 'message', T: () => Codec },
1697
+ {
1698
+ no: 3,
1699
+ name: 'avg_frame_time_ms',
1700
+ kind: 'scalar',
1701
+ T: 2 /*ScalarType.FLOAT*/,
1702
+ },
1703
+ { no: 4, name: 'avg_fps', kind: 'scalar', T: 2 /*ScalarType.FLOAT*/ },
1704
+ {
1705
+ no: 5,
1706
+ name: 'video_dimension',
1707
+ kind: 'message',
1708
+ T: () => VideoDimension,
1709
+ },
1710
+ {
1711
+ no: 6,
1712
+ name: 'target_bitrate',
1713
+ kind: 'scalar',
1714
+ T: 5 /*ScalarType.INT32*/,
1715
+ },
1716
+ ]);
1717
+ }
1718
+ }
1719
+ /**
1720
+ * @generated MessageType for protobuf message stream.video.sfu.models.PerformanceStats
1721
+ */
1722
+ export const PerformanceStats = new PerformanceStats$Type();
@@ -8,6 +8,7 @@ import {
8
8
  ICETrickle,
9
9
  InputDevices,
10
10
  PeerType,
11
+ PerformanceStats,
11
12
  RTMPIngress,
12
13
  TrackInfo,
13
14
  TrackType,
@@ -158,13 +159,39 @@ export interface SendStatsRequest {
158
159
  */
159
160
  rtmp?: RTMPIngress;
160
161
  /**
161
- * @generated from protobuf field: string subscriber_rtc_stats = 13;
162
+ * @deprecated
163
+ * @generated from protobuf field: string subscriber_rtc_stats = 13 [deprecated = true];
162
164
  */
163
165
  subscriberRtcStats: string;
164
166
  /**
165
- * @generated from protobuf field: string publisher_rtc_stats = 14;
167
+ * @deprecated
168
+ * @generated from protobuf field: string publisher_rtc_stats = 14 [deprecated = true];
166
169
  */
167
170
  publisherRtcStats: string;
171
+ /**
172
+ * @generated from protobuf field: string rtc_stats = 15;
173
+ */
174
+ rtcStats: string;
175
+ /**
176
+ * Encode stats for the publisher
177
+ *
178
+ * @generated from protobuf field: repeated stream.video.sfu.models.PerformanceStats encode_stats = 16;
179
+ */
180
+ encodeStats: PerformanceStats[];
181
+ /**
182
+ * Decode stats for the subscriber
183
+ *
184
+ * @generated from protobuf field: repeated stream.video.sfu.models.PerformanceStats decode_stats = 17;
185
+ */
186
+ decodeStats: PerformanceStats[];
187
+ /**
188
+ * user_session id can change during reconnects, this helps us to
189
+ * identify the user across reconnects and should remain consistent until the user explicitly
190
+ * disconnects, is kicked or the call is ended.
191
+ *
192
+ * @generated from protobuf field: string unified_session_id = 18;
193
+ */
194
+ unifiedSessionId: string;
168
195
  }
169
196
  /**
170
197
  * @generated from protobuf message stream.video.sfu.signal.SendStatsResponse
@@ -534,6 +561,27 @@ class SendStatsRequest$Type extends MessageType<SendStatsRequest> {
534
561
  kind: 'scalar',
535
562
  T: 9 /*ScalarType.STRING*/,
536
563
  },
564
+ { no: 15, name: 'rtc_stats', kind: 'scalar', T: 9 /*ScalarType.STRING*/ },
565
+ {
566
+ no: 16,
567
+ name: 'encode_stats',
568
+ kind: 'message',
569
+ repeat: 1 /*RepeatType.PACKED*/,
570
+ T: () => PerformanceStats,
571
+ },
572
+ {
573
+ no: 17,
574
+ name: 'decode_stats',
575
+ kind: 'message',
576
+ repeat: 1 /*RepeatType.PACKED*/,
577
+ T: () => PerformanceStats,
578
+ },
579
+ {
580
+ no: 18,
581
+ name: 'unified_session_id',
582
+ kind: 'scalar',
583
+ T: 9 /*ScalarType.STRING*/,
584
+ },
537
585
  ]);
538
586
  }
539
587
  }
@@ -28,7 +28,6 @@ import type { CallState } from '../store';
28
28
  import type { StreamSfuClient } from '../StreamSfuClient';
29
29
  import { SpeakerManager } from '../devices';
30
30
  import { getCurrentValue, setCurrentValue } from '../store/rxUtils';
31
- import { tracer as mediaStatsTracer } from '../stats/rtc/mediaDevices';
32
31
 
33
32
  const DEFAULT_VIEWPORT_VISIBILITY_STATE: Record<
34
33
  VideoTrackType,
@@ -536,10 +535,6 @@ export class DynascaleManager {
536
535
  const { selectedDevice } = this.speaker.state;
537
536
  if (selectedDevice && 'setSinkId' in audioElement) {
538
537
  audioElement.setSinkId(selectedDevice);
539
- mediaStatsTracer.trace(
540
- 'navigator.mediaDevices.setSinkId',
541
- selectedDevice,
542
- );
543
538
  }
544
539
  }
545
540
  });
@@ -550,10 +545,6 @@ export class DynascaleManager {
550
545
  : this.speaker.state.selectedDevice$.subscribe((deviceId) => {
551
546
  if (deviceId) {
552
547
  audioElement.setSinkId(deviceId);
553
- mediaStatsTracer.trace(
554
- 'navigator.mediaDevices.setSinkId',
555
- deviceId,
556
- );
557
548
  }
558
549
  });
559
550
 
@@ -11,7 +11,7 @@ import {
11
11
  } from '@protobuf-ts/twirp-transport';
12
12
  import { SignalServerClient } from '../gen/video/sfu/signal_rpc/signal.client';
13
13
  import { Logger, LogLevel } from '../coordinator/connection/types';
14
- import type { Trace } from '../stats/rtc/types';
14
+ import type { Trace } from '../stats';
15
15
 
16
16
  const defaultOptions: TwirpOptions = {
17
17
  baseUrl: '',