@stream-io/video-client 1.32.0 → 1.33.1

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 +16 -0
  2. package/dist/index.browser.es.js +344 -91
  3. package/dist/index.browser.es.js.map +1 -1
  4. package/dist/index.cjs.js +345 -92
  5. package/dist/index.cjs.js.map +1 -1
  6. package/dist/index.es.js +344 -91
  7. package/dist/index.es.js.map +1 -1
  8. package/dist/src/Call.d.ts +3 -2
  9. package/dist/src/devices/AudioDeviceManager.d.ts +25 -0
  10. package/dist/src/devices/AudioDeviceManagerState.d.ts +24 -0
  11. package/dist/src/devices/CameraManager.d.ts +2 -2
  12. package/dist/src/devices/CameraManagerState.d.ts +3 -4
  13. package/dist/src/devices/{InputMediaDeviceManager.d.ts → DeviceManager.d.ts} +6 -6
  14. package/dist/src/devices/{InputMediaDeviceManagerState.d.ts → DeviceManagerState.d.ts} +4 -4
  15. package/dist/src/devices/MicrophoneManager.d.ts +5 -3
  16. package/dist/src/devices/MicrophoneManagerState.d.ts +6 -10
  17. package/dist/src/devices/ScreenShareManager.d.ts +4 -2
  18. package/dist/src/devices/ScreenShareState.d.ts +6 -2
  19. package/dist/src/devices/SpeakerState.d.ts +4 -4
  20. package/dist/src/devices/index.d.ts +2 -2
  21. package/dist/src/gen/coordinator/index.d.ts +169 -2
  22. package/dist/src/gen/video/sfu/models/models.d.ts +43 -0
  23. package/dist/src/rtc/BasePeerConnection.d.ts +2 -12
  24. package/dist/src/rtc/Publisher.d.ts +9 -6
  25. package/dist/src/rtc/Subscriber.d.ts +2 -1
  26. package/dist/src/rtc/TransceiverCache.d.ts +10 -11
  27. package/dist/src/rtc/index.d.ts +1 -1
  28. package/dist/src/rtc/{videoLayers.d.ts → layers.d.ts} +7 -1
  29. package/dist/src/rtc/types.d.ts +31 -0
  30. package/dist/src/sorting/participants.d.ts +5 -2
  31. package/package.json +3 -2
  32. package/src/Call.ts +13 -6
  33. package/src/__tests__/Call.publishing.test.ts +14 -3
  34. package/src/__tests__/StreamVideoClient.api.test.ts +1 -1
  35. package/src/devices/AudioDeviceManager.ts +61 -0
  36. package/src/devices/AudioDeviceManagerState.ts +44 -0
  37. package/src/devices/CameraManager.ts +4 -4
  38. package/src/devices/CameraManagerState.ts +9 -8
  39. package/src/devices/{InputMediaDeviceManager.ts → DeviceManager.ts} +11 -8
  40. package/src/devices/{InputMediaDeviceManagerState.ts → DeviceManagerState.ts} +7 -4
  41. package/src/devices/MicrophoneManager.ts +26 -6
  42. package/src/devices/MicrophoneManagerState.ts +18 -19
  43. package/src/devices/ScreenShareManager.ts +23 -4
  44. package/src/devices/ScreenShareState.ts +11 -3
  45. package/src/devices/SpeakerState.ts +6 -14
  46. package/src/devices/__tests__/CameraManager.test.ts +1 -0
  47. package/src/devices/__tests__/{InputMediaDeviceManager.test.ts → DeviceManager.test.ts} +4 -4
  48. package/src/devices/__tests__/{InputMediaDeviceManagerFilters.test.ts → DeviceManagerFilters.test.ts} +4 -4
  49. package/src/devices/__tests__/{InputMediaDeviceManagerState.test.ts → DeviceManagerState.test.ts} +2 -2
  50. package/src/devices/__tests__/MicrophoneManager.test.ts +41 -1
  51. package/src/devices/__tests__/NoiseCancellationStub.ts +3 -1
  52. package/src/devices/__tests__/ScreenShareManager.test.ts +5 -1
  53. package/src/devices/index.ts +2 -2
  54. package/src/events/__tests__/internal.test.ts +25 -11
  55. package/src/gen/coordinator/index.ts +169 -2
  56. package/src/gen/video/sfu/models/models.ts +65 -0
  57. package/src/rtc/BasePeerConnection.ts +1 -16
  58. package/src/rtc/Publisher.ts +74 -31
  59. package/src/rtc/Subscriber.ts +2 -4
  60. package/src/rtc/TransceiverCache.ts +23 -27
  61. package/src/rtc/__tests__/Publisher.test.ts +61 -29
  62. package/src/rtc/__tests__/{videoLayers.test.ts → layers.test.ts} +76 -1
  63. package/src/rtc/index.ts +2 -1
  64. package/src/rtc/{videoLayers.ts → layers.ts} +28 -7
  65. package/src/rtc/types.ts +44 -0
  66. package/src/sorting/__tests__/sorting.test.ts +106 -0
  67. package/src/sorting/participants.ts +30 -14
  68. package/src/sorting/presets.ts +16 -4
  69. package/src/store/CallState.ts +36 -10
  70. package/src/store/__tests__/CallState.test.ts +20 -2
@@ -1,11 +1,14 @@
1
1
  import { combineLatest, Observable } from 'rxjs';
2
2
  import type { INoiseCancellation } from '@stream-io/audio-filters-web';
3
3
  import { Call } from '../Call';
4
- import { InputMediaDeviceManager } from './InputMediaDeviceManager';
4
+ import {
5
+ AudioDeviceManager,
6
+ createAudioConstraints,
7
+ } from './AudioDeviceManager';
5
8
  import { MicrophoneManagerState } from './MicrophoneManagerState';
6
- import { TrackDisableMode } from './InputMediaDeviceManagerState';
9
+ import { TrackDisableMode } from './DeviceManagerState';
7
10
  import { getAudioDevices, getAudioStream } from './devices';
8
- import { TrackType } from '../gen/video/sfu/models/models';
11
+ import { AudioBitrateProfile, TrackType } from '../gen/video/sfu/models/models';
9
12
  import { createSoundDetector } from '../helpers/sound-detector';
10
13
  import { isReactNative } from '../helpers/platforms';
11
14
  import {
@@ -21,7 +24,7 @@ import {
21
24
  import { RNSpeechDetector } from '../helpers/RNSpeechDetector';
22
25
  import { withoutConcurrency } from '../helpers/concurrency';
23
26
 
24
- export class MicrophoneManager extends InputMediaDeviceManager<MicrophoneManagerState> {
27
+ export class MicrophoneManager extends AudioDeviceManager<MicrophoneManagerState> {
25
28
  private speakingWhileMutedNotificationEnabled = true;
26
29
  private soundDetectorConcurrencyTag = Symbol('soundDetectorConcurrencyTag');
27
30
  private soundDetectorCleanup?: Function;
@@ -245,16 +248,33 @@ export class MicrophoneManager extends InputMediaDeviceManager<MicrophoneManager
245
248
  }
246
249
  }
247
250
 
248
- protected getDevices(): Observable<MediaDeviceInfo[]> {
251
+ protected override getDevices(): Observable<MediaDeviceInfo[]> {
249
252
  return getAudioDevices(this.call.tracer);
250
253
  }
251
254
 
252
- protected getStream(
255
+ protected override getStream(
253
256
  constraints: MediaTrackConstraints,
254
257
  ): Promise<MediaStream> {
255
258
  return getAudioStream(constraints, this.call.tracer);
256
259
  }
257
260
 
261
+ protected override doSetAudioBitrateProfile(profile: AudioBitrateProfile) {
262
+ this.setDefaultConstraints({
263
+ ...this.state.defaultConstraints,
264
+ ...createAudioConstraints(profile),
265
+ });
266
+
267
+ if (this.noiseCancellation) {
268
+ const disableAudioProcessing =
269
+ profile === AudioBitrateProfile.MUSIC_HIGH_QUALITY;
270
+ if (disableAudioProcessing) {
271
+ this.noiseCancellation.disable(); // disable for high quality music mode
272
+ } else {
273
+ this.noiseCancellation.enable(); // restore it for other modes if available
274
+ }
275
+ }
276
+ }
277
+
258
278
  private async startSpeakingWhileMutedDetection(deviceId?: string) {
259
279
  await withoutConcurrency(this.soundDetectorConcurrencyTag, async () => {
260
280
  await this.stopSpeakingWhileMutedDetection();
@@ -1,33 +1,30 @@
1
- import { BehaviorSubject, distinctUntilChanged, Observable } from 'rxjs';
1
+ import { BehaviorSubject, distinctUntilChanged } from 'rxjs';
2
2
  import { RxUtils } from '../store';
3
- import {
4
- InputMediaDeviceManagerState,
5
- TrackDisableMode,
6
- } from './InputMediaDeviceManagerState';
3
+ import { TrackDisableMode } from './DeviceManagerState';
4
+ import { AudioDeviceManagerState } from './AudioDeviceManagerState';
7
5
  import { getAudioBrowserPermission, resolveDeviceId } from './devices';
6
+ import { AudioBitrateProfile } from '../gen/video/sfu/models/models';
8
7
 
9
- export class MicrophoneManagerState extends InputMediaDeviceManagerState {
8
+ export class MicrophoneManagerState extends AudioDeviceManagerState<MediaTrackConstraints> {
10
9
  private speakingWhileMutedSubject = new BehaviorSubject<boolean>(false);
11
10
 
12
11
  /**
13
- * An Observable that emits `true` if the user's microphone is muted but they'are speaking.
14
- *
15
- * This feature is not available in the React Native SDK.
12
+ * An Observable that emits `true` if the user's microphone is muted, but they're speaking.
16
13
  */
17
- speakingWhileMuted$: Observable<boolean>;
14
+ speakingWhileMuted$ = this.speakingWhileMutedSubject
15
+ .asObservable()
16
+ .pipe(distinctUntilChanged());
18
17
 
19
18
  constructor(disableMode: TrackDisableMode) {
20
- super(disableMode, getAudioBrowserPermission());
21
-
22
- this.speakingWhileMuted$ = this.speakingWhileMutedSubject
23
- .asObservable()
24
- .pipe(distinctUntilChanged());
19
+ super(
20
+ disableMode,
21
+ getAudioBrowserPermission(),
22
+ AudioBitrateProfile.VOICE_STANDARD_UNSPECIFIED,
23
+ );
25
24
  }
26
25
 
27
26
  /**
28
- * `true` if the user's microphone is muted but they'are speaking.
29
- *
30
- * This feature is not available in the React Native SDK.
27
+ * `true` if the user's microphone is muted but they're speaking.
31
28
  */
32
29
  get speakingWhileMuted() {
33
30
  return RxUtils.getCurrentValue(this.speakingWhileMuted$);
@@ -40,7 +37,9 @@ export class MicrophoneManagerState extends InputMediaDeviceManagerState {
40
37
  RxUtils.setCurrentValue(this.speakingWhileMutedSubject, isSpeaking);
41
38
  }
42
39
 
43
- protected getDeviceIdFromStream(stream: MediaStream): string | undefined {
40
+ protected override getDeviceIdFromStream(
41
+ stream: MediaStream,
42
+ ): string | undefined {
44
43
  const [track] = stream.getAudioTracks();
45
44
  const unresolvedDeviceId = track?.getSettings().deviceId;
46
45
  return resolveDeviceId(unresolvedDeviceId, 'audioinput');
@@ -1,13 +1,16 @@
1
1
  import { Observable, of } from 'rxjs';
2
- import { InputMediaDeviceManager } from './InputMediaDeviceManager';
2
+ import {
3
+ AudioDeviceManager,
4
+ createAudioConstraints,
5
+ } from './AudioDeviceManager';
3
6
  import { ScreenShareState } from './ScreenShareState';
4
7
  import { Call } from '../Call';
5
- import { TrackType } from '../gen/video/sfu/models/models';
8
+ import { AudioBitrateProfile, TrackType } from '../gen/video/sfu/models/models';
6
9
  import { getScreenShareStream } from './devices';
7
10
  import { ScreenShareSettings } from '../types';
8
11
  import { createSubscription } from '../store/rxUtils';
9
12
 
10
- export class ScreenShareManager extends InputMediaDeviceManager<
13
+ export class ScreenShareManager extends AudioDeviceManager<
11
14
  ScreenShareState,
12
15
  DisplayMediaStreamOptions
13
16
  > {
@@ -23,6 +26,7 @@ export class ScreenShareManager extends InputMediaDeviceManager<
23
26
 
24
27
  if (maybeTargetResolution) {
25
28
  this.setDefaultConstraints({
29
+ ...this.state.defaultConstraints,
26
30
  video: {
27
31
  width: maybeTargetResolution.width,
28
32
  height: maybeTargetResolution.height,
@@ -73,7 +77,7 @@ export class ScreenShareManager extends InputMediaDeviceManager<
73
77
  return of([]); // there are no devices to be listed for Screen Share
74
78
  }
75
79
 
76
- protected async getStream(
80
+ protected override async getStream(
77
81
  constraints: DisplayMediaStreamOptions,
78
82
  ): Promise<MediaStream> {
79
83
  if (!this.state.audioEnabled) {
@@ -92,6 +96,21 @@ export class ScreenShareManager extends InputMediaDeviceManager<
92
96
  return stream;
93
97
  }
94
98
 
99
+ protected override doSetAudioBitrateProfile(profile: AudioBitrateProfile) {
100
+ const { defaultConstraints } = this.state;
101
+ const baseAudioConstraints =
102
+ typeof defaultConstraints?.audio !== 'boolean'
103
+ ? defaultConstraints?.audio
104
+ : null;
105
+ this.setDefaultConstraints({
106
+ ...defaultConstraints,
107
+ audio: {
108
+ ...baseAudioConstraints,
109
+ ...createAudioConstraints(profile),
110
+ },
111
+ });
112
+ }
113
+
95
114
  protected override async stopPublishStream(): Promise<void> {
96
115
  return this.call.stopPublish(
97
116
  TrackType.SCREEN_SHARE,
@@ -1,9 +1,10 @@
1
1
  import { BehaviorSubject, distinctUntilChanged } from 'rxjs';
2
- import { InputMediaDeviceManagerState } from './InputMediaDeviceManagerState';
2
+ import { AudioDeviceManagerState } from './AudioDeviceManagerState';
3
+ import { AudioBitrateProfile } from '../gen/video/sfu/models/models';
3
4
  import { ScreenShareSettings } from '../types';
4
5
  import { RxUtils } from '../store';
5
6
 
6
- export class ScreenShareState extends InputMediaDeviceManagerState<DisplayMediaStreamOptions> {
7
+ export class ScreenShareState extends AudioDeviceManagerState<DisplayMediaStreamOptions> {
7
8
  private audioEnabledSubject = new BehaviorSubject<boolean>(true);
8
9
  private settingsSubject = new BehaviorSubject<
9
10
  ScreenShareSettings | undefined
@@ -21,10 +22,17 @@ export class ScreenShareState extends InputMediaDeviceManagerState<DisplayMediaS
21
22
  */
22
23
  settings$ = this.settingsSubject.asObservable();
23
24
 
25
+ /**
26
+ * Constructs a new ScreenShareState instance.
27
+ */
28
+ constructor() {
29
+ super('stop-tracks', undefined, AudioBitrateProfile.MUSIC_HIGH_QUALITY);
30
+ }
31
+
24
32
  /**
25
33
  * @internal
26
34
  */
27
- protected getDeviceIdFromStream = (
35
+ protected override getDeviceIdFromStream = (
28
36
  stream: MediaStream,
29
37
  ): string | undefined => {
30
38
  const [track] = stream.getTracks();
@@ -1,4 +1,4 @@
1
- import { BehaviorSubject, distinctUntilChanged, Observable } from 'rxjs';
1
+ import { BehaviorSubject, distinctUntilChanged } from 'rxjs';
2
2
  import { RxUtils } from '../store';
3
3
  import { checkIfAudioOutputChangeSupported } from './devices';
4
4
  import { Tracer } from '../stats';
@@ -16,26 +16,18 @@ export class SpeakerState {
16
16
  *
17
17
  * Note: this feature is not supported in React Native
18
18
  */
19
- selectedDevice$: Observable<string>;
19
+ selectedDevice$ = this.selectedDeviceSubject
20
+ .asObservable()
21
+ .pipe(distinctUntilChanged());
20
22
 
21
23
  /**
22
24
  * An Observable that emits the currently selected volume
23
25
  *
24
26
  * Note: this feature is not supported in React Native
25
27
  */
26
- volume$: Observable<number>;
28
+ volume$ = this.volumeSubject.asObservable().pipe(distinctUntilChanged());
27
29
 
28
- private tracer: Tracer;
29
-
30
- constructor(tracer: Tracer) {
31
- this.tracer = tracer;
32
- this.selectedDevice$ = this.selectedDeviceSubject
33
- .asObservable()
34
- .pipe(distinctUntilChanged());
35
- this.volume$ = this.volumeSubject
36
- .asObservable()
37
- .pipe(distinctUntilChanged());
38
- }
30
+ constructor(private tracer: Tracer) {}
39
31
 
40
32
  /**
41
33
  * The currently selected device
@@ -106,6 +106,7 @@ describe('CameraManager', () => {
106
106
  expect(manager['call'].publish).toHaveBeenCalledWith(
107
107
  manager.state.mediaStream,
108
108
  TrackType.VIDEO,
109
+ undefined,
109
110
  );
110
111
  });
111
112
 
@@ -12,8 +12,8 @@ import {
12
12
  mockVideoDevices,
13
13
  mockVideoStream,
14
14
  } from './mocks';
15
- import { InputMediaDeviceManager } from '../InputMediaDeviceManager';
16
- import { InputMediaDeviceManagerState } from '../InputMediaDeviceManagerState';
15
+ import { DeviceManager } from '../DeviceManager';
16
+ import { DeviceManagerState } from '../DeviceManagerState';
17
17
  import { of } from 'rxjs';
18
18
  import { TrackType } from '../../gen/video/sfu/models/models';
19
19
 
@@ -34,13 +34,13 @@ vi.mock('../devices.ts', () => {
34
34
  };
35
35
  });
36
36
 
37
- class TestInputMediaDeviceManagerState extends InputMediaDeviceManagerState {
37
+ class TestInputMediaDeviceManagerState extends DeviceManagerState {
38
38
  public getDeviceIdFromStream = vi.fn(
39
39
  (stream) => stream.getVideoTracks()[0].getSettings().deviceId,
40
40
  );
41
41
  }
42
42
 
43
- class TestInputMediaDeviceManager extends InputMediaDeviceManager<TestInputMediaDeviceManagerState> {
43
+ class TestInputMediaDeviceManager extends DeviceManager<TestInputMediaDeviceManagerState> {
44
44
  public getDevices = vi.fn(() => of(mockVideoDevices));
45
45
  public getStream = vi.fn(() => Promise.resolve(mockVideoStream()));
46
46
  public publishStream = vi.fn();
@@ -3,8 +3,8 @@ import { of } from 'rxjs';
3
3
  import { Call } from '../../Call';
4
4
  import { StreamClient } from '../../coordinator/connection/client';
5
5
  import { StreamVideoWriteableStateStore } from '../../store';
6
- import { InputMediaDeviceManagerState } from '../InputMediaDeviceManagerState';
7
- import { InputMediaDeviceManager } from '../InputMediaDeviceManager';
6
+ import { DeviceManagerState } from '../DeviceManagerState';
7
+ import { DeviceManager } from '../DeviceManager';
8
8
  import {
9
9
  mockBrowserPermission,
10
10
  mockVideoDevices,
@@ -14,13 +14,13 @@ import { TrackType } from '../../gen/video/sfu/models/models';
14
14
 
15
15
  import '../../rtc/__tests__/mocks/webrtc.mocks';
16
16
 
17
- class TestInputMediaDeviceManagerState extends InputMediaDeviceManagerState {
17
+ class TestInputMediaDeviceManagerState extends DeviceManagerState {
18
18
  public getDeviceIdFromStream = vi.fn(
19
19
  (stream) => stream.getTracks()[0].getSettings().deviceId,
20
20
  );
21
21
  }
22
22
 
23
- class TestInputMediaDeviceManager extends InputMediaDeviceManager<TestInputMediaDeviceManagerState> {
23
+ class TestInputMediaDeviceManager extends DeviceManager<TestInputMediaDeviceManagerState> {
24
24
  public getDevices = vi.fn(() => of(mockVideoDevices));
25
25
  public getStream = vi.fn(() => Promise.resolve(mockVideoStream()));
26
26
  public publishStream = vi.fn();
@@ -1,9 +1,9 @@
1
1
  import { beforeAll, describe, expect, it, vi } from 'vitest';
2
- import { InputMediaDeviceManagerState } from '../InputMediaDeviceManagerState';
2
+ import { DeviceManagerState } from '../DeviceManagerState';
3
3
  import { firstValueFrom } from 'rxjs';
4
4
  import { BrowserPermission } from '../BrowserPermission';
5
5
 
6
- class TestInputMediaDeviceManagerState extends InputMediaDeviceManagerState {
6
+ class TestInputMediaDeviceManagerState extends DeviceManagerState {
7
7
  constructor() {
8
8
  super(
9
9
  'stop-tracks',
@@ -7,7 +7,10 @@ import {
7
7
  NoiseCancellationSettingsModeEnum,
8
8
  OwnCapability,
9
9
  } from '../../gen/coordinator';
10
- import { TrackType } from '../../gen/video/sfu/models/models';
10
+ import {
11
+ AudioBitrateProfile,
12
+ TrackType,
13
+ } from '../../gen/video/sfu/models/models';
11
14
  import { CallingState, StreamVideoWriteableStateStore } from '../../store';
12
15
  import {
13
16
  mockAudioDevices,
@@ -100,6 +103,7 @@ describe('MicrophoneManager', () => {
100
103
  expect(manager['call'].publish).toHaveBeenCalledWith(
101
104
  manager.state.mediaStream,
102
105
  TrackType.AUDIO,
106
+ { audioBitrateProfile: AudioBitrateProfile.VOICE_STANDARD_UNSPECIFIED },
103
107
  );
104
108
  });
105
109
 
@@ -367,6 +371,42 @@ describe('MicrophoneManager', () => {
367
371
  });
368
372
  });
369
373
 
374
+ describe('Hi-Fi Audio', () => {
375
+ it('enables hi-fi audio', async () => {
376
+ call.state.updateFromCallResponse({
377
+ // @ts-expect-error partial data
378
+ settings: { audio: { hifi_audio_enabled: true } },
379
+ });
380
+
381
+ await manager.enable();
382
+
383
+ // @ts-expect-error - private api
384
+ const apply = vi.spyOn(manager, 'applySettingsToStream');
385
+ const publish = vi.spyOn(call, 'publish');
386
+ const profile = AudioBitrateProfile.MUSIC_HIGH_QUALITY;
387
+ await manager.setAudioBitrateProfile(profile);
388
+
389
+ expect(apply).toHaveBeenCalledOnce();
390
+ expect(publish).toHaveBeenCalledWith(
391
+ manager.state.mediaStream,
392
+ TrackType.AUDIO,
393
+ { audioBitrateProfile: profile },
394
+ );
395
+ });
396
+
397
+ it('throws an error when enabling hi-fi audio if not allowed', async () => {
398
+ call.state.updateFromCallResponse({
399
+ // @ts-expect-error partial data
400
+ settings: { audio: { hifi_audio_enabled: false } },
401
+ });
402
+
403
+ await manager.enable();
404
+ await expect(() =>
405
+ manager.setAudioBitrateProfile(AudioBitrateProfile.VOICE_HIGH_QUALITY),
406
+ ).rejects.toThrowError();
407
+ });
408
+ });
409
+
370
410
  afterEach(() => {
371
411
  vi.clearAllMocks();
372
412
  vi.resetModules();
@@ -3,9 +3,10 @@ import type { INoiseCancellation } from '@stream-io/audio-filters-web';
3
3
  export class NoiseCancellationStub implements INoiseCancellation {
4
4
  private listeners: { [event: string]: Array<(arg: boolean) => void> } = {};
5
5
 
6
+ canAutoEnable = async () => true;
6
7
  isSupported = () => true;
7
8
  init = () => Promise.resolve(undefined);
8
- isEnabled = () => true;
9
+ isEnabled = async () => true;
9
10
  enable = () => this.listeners['change']?.forEach((l) => l(true));
10
11
  disable = () => this.listeners['change']?.forEach((l) => l(false));
11
12
  setSuppressionLevel = () => {};
@@ -16,4 +17,5 @@ export class NoiseCancellationStub implements INoiseCancellation {
16
17
  return () => {};
17
18
  };
18
19
  off = () => {};
20
+ resume = () => {};
19
21
  }
@@ -6,7 +6,10 @@ import { CallingState, StreamVideoWriteableStateStore } from '../../store';
6
6
  import * as RxUtils from '../../store/rxUtils';
7
7
  import { mockCall, mockDeviceIds$, mockScreenShareStream } from './mocks';
8
8
  import { getScreenShareStream } from '../devices';
9
- import { TrackType } from '../../gen/video/sfu/models/models';
9
+ import {
10
+ AudioBitrateProfile,
11
+ TrackType,
12
+ } from '../../gen/video/sfu/models/models';
10
13
  import { Tracer } from '../../stats';
11
14
 
12
15
  vi.mock('../devices.ts', () => {
@@ -121,6 +124,7 @@ describe('ScreenShareManager', () => {
121
124
  expect(call.publish).toHaveBeenCalledWith(
122
125
  manager.state.mediaStream,
123
126
  TrackType.SCREEN_SHARE,
127
+ { audioBitrateProfile: AudioBitrateProfile.MUSIC_HIGH_QUALITY },
124
128
  );
125
129
  });
126
130
 
@@ -1,7 +1,7 @@
1
1
  export * from './utils';
2
2
  export * from './devices';
3
- export * from './InputMediaDeviceManager';
4
- export * from './InputMediaDeviceManagerState';
3
+ export * from './DeviceManager';
4
+ export * from './DeviceManagerState';
5
5
  export * from './CameraManager';
6
6
  export * from './CameraManagerState';
7
7
  export * from './MicrophoneManager';
@@ -1,4 +1,5 @@
1
1
  import { describe, expect, it, vi } from 'vitest';
2
+ import { fromPartial } from '@total-typescript/shoehorn';
2
3
  import { Call } from '../../Call';
3
4
  import { Dispatcher } from '../../rtc';
4
5
  import { CallState } from '../../store';
@@ -30,13 +31,12 @@ describe('internal events', () => {
30
31
  dispatcher.dispatch({
31
32
  eventPayload: {
32
33
  oneofKind: 'connectionQualityChanged',
33
- // @ts-expect-error incomplete data
34
34
  connectionQualityChanged: {
35
35
  connectionQualityUpdates: [
36
- {
36
+ fromPartial({
37
37
  sessionId: 'session-1',
38
38
  connectionQuality: ConnectionQuality.EXCELLENT,
39
- },
39
+ }),
40
40
  ],
41
41
  },
42
42
  },
@@ -60,7 +60,6 @@ describe('internal events', () => {
60
60
  dispatcher.dispatch({
61
61
  eventPayload: {
62
62
  oneofKind: 'healthCheckResponse',
63
- // @ts-expect-error incomplete data
64
63
  healthCheckResponse: { participantCount: { total: 5, anonymous: 2 } },
65
64
  },
66
65
  });
@@ -118,20 +117,35 @@ describe('internal events', () => {
118
117
  it('handles pinUpdated', () => {
119
118
  const state = new CallState();
120
119
  state.setParticipants([
121
- // @ts-expect-error incomplete data
122
- { userId: 'u1', sessionId: 'session-1', pin: { isLocalPin: false } },
123
- // @ts-expect-error incomplete data
124
- { userId: 'u2', sessionId: 'session-2', pin: { isLocalPin: false } },
120
+ fromPartial({
121
+ userId: 'u1',
122
+ sessionId: 'session-1',
123
+ publishedTracks: [],
124
+ }),
125
+ fromPartial({
126
+ userId: 'u2',
127
+ sessionId: 'session-2',
128
+ publishedTracks: [],
129
+ }),
125
130
  ]);
126
- const update = watchPinsUpdated(state);
127
- update({ pins: [{ userId: 'u1', sessionId: 'session-1' }] });
131
+
132
+ watchPinsUpdated(state)({
133
+ pins: [{ userId: 'u1', sessionId: 'session-1' }],
134
+ });
135
+
128
136
  expect(state.participants).toEqual([
129
137
  {
130
138
  userId: 'u1',
131
139
  sessionId: 'session-1',
132
140
  pin: { isLocalPin: false, pinnedAt: expect.any(Number) },
141
+ publishedTracks: [],
142
+ },
143
+ {
144
+ userId: 'u2',
145
+ sessionId: 'session-2',
146
+ pin: undefined,
147
+ publishedTracks: [],
133
148
  },
134
- { userId: 'u2', sessionId: 'session-2', pin: undefined },
135
149
  ]);
136
150
  });
137
151