@stream-io/video-client 0.3.12 → 0.3.13
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.
- package/CHANGELOG.md +7 -0
- package/dist/index.browser.es.js +250 -126
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +249 -125
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +250 -126
- package/dist/index.es.js.map +1 -1
- package/dist/src/Call.d.ts +6 -1
- package/dist/src/devices/SpeakerManager.d.ts +28 -0
- package/dist/src/devices/SpeakerState.d.ts +64 -0
- package/dist/src/devices/__tests__/SpeakerManager.test.d.ts +1 -0
- package/dist/src/types.d.ts +2 -0
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/Call.ts +12 -1
- package/src/devices/SpeakerManager.ts +50 -0
- package/src/devices/SpeakerState.ts +90 -0
- package/src/devices/__tests__/SpeakerManager.test.ts +66 -0
- package/src/helpers/DynascaleManager.ts +25 -7
- package/src/helpers/__tests__/DynascaleManager.test.ts +30 -2
- package/src/types.ts +2 -0
package/dist/src/Call.d.ts
CHANGED
|
@@ -7,7 +7,9 @@ import { DynascaleManager } from './helpers/DynascaleManager';
|
|
|
7
7
|
import { PermissionsContext } from './permissions';
|
|
8
8
|
import { StreamClient } from './coordinator/connection/client';
|
|
9
9
|
import { CallEventHandler, CallEventTypes, EventTypes, Logger } from './coordinator/connection/types';
|
|
10
|
-
import { CameraManager
|
|
10
|
+
import { CameraManager } from './devices/CameraManager';
|
|
11
|
+
import { MicrophoneManager } from './devices/MicrophoneManager';
|
|
12
|
+
import { SpeakerManager } from './devices/SpeakerManager';
|
|
11
13
|
/**
|
|
12
14
|
* An object representation of a `Call`.
|
|
13
15
|
*/
|
|
@@ -45,6 +47,7 @@ export declare class Call {
|
|
|
45
47
|
* The DynascaleManager instance.
|
|
46
48
|
*/
|
|
47
49
|
readonly dynascaleManager: DynascaleManager;
|
|
50
|
+
readonly speaker: SpeakerManager;
|
|
48
51
|
/**
|
|
49
52
|
* Flag telling whether this call is a "ringing" call.
|
|
50
53
|
*/
|
|
@@ -251,6 +254,8 @@ export declare class Call {
|
|
|
251
254
|
*
|
|
252
255
|
*
|
|
253
256
|
* @param deviceId the selected device, `undefined` means the user wants to use the system's default audio output
|
|
257
|
+
*
|
|
258
|
+
* @deprecated use `call.speaker` instead
|
|
254
259
|
*/
|
|
255
260
|
setAudioOutputDevice: (deviceId?: string) => void;
|
|
256
261
|
/**
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { SpeakerState } from './SpeakerState';
|
|
2
|
+
export declare class SpeakerManager {
|
|
3
|
+
readonly state: SpeakerState;
|
|
4
|
+
constructor();
|
|
5
|
+
/**
|
|
6
|
+
* Lists the available audio output devices
|
|
7
|
+
*
|
|
8
|
+
* Note: It prompts the user for a permission to use devices (if not already granted)
|
|
9
|
+
*
|
|
10
|
+
* @returns an Observable that will be updated if a device is connected or disconnected
|
|
11
|
+
*/
|
|
12
|
+
listDevices(): import("rxjs").Observable<MediaDeviceInfo[]>;
|
|
13
|
+
/**
|
|
14
|
+
* Select device
|
|
15
|
+
*
|
|
16
|
+
* Note: this method is not supported in React Native
|
|
17
|
+
*
|
|
18
|
+
* @param deviceId empty string means the system default
|
|
19
|
+
*/
|
|
20
|
+
select(deviceId: string): void;
|
|
21
|
+
/**
|
|
22
|
+
* Set the volume of the audio elements
|
|
23
|
+
* @param volume a number between 0 and 1
|
|
24
|
+
*
|
|
25
|
+
* Note: this method is not supported in React Native
|
|
26
|
+
*/
|
|
27
|
+
setVolume(volume: number): void;
|
|
28
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { BehaviorSubject, Observable } from 'rxjs';
|
|
2
|
+
import { RxUtils } from '../store';
|
|
3
|
+
export declare class SpeakerState {
|
|
4
|
+
protected selectedDeviceSubject: BehaviorSubject<string>;
|
|
5
|
+
protected volumeSubject: BehaviorSubject<number>;
|
|
6
|
+
/**
|
|
7
|
+
* [Tells if the browser supports audio output change on 'audio' elements](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/setSinkId).
|
|
8
|
+
*/
|
|
9
|
+
readonly isDeviceSelectionSupported: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* An Observable that emits the currently selected device
|
|
12
|
+
*
|
|
13
|
+
* Note: this feature is not supported in React Native
|
|
14
|
+
*/
|
|
15
|
+
selectedDevice$: Observable<string>;
|
|
16
|
+
/**
|
|
17
|
+
* An Observable that emits the currently selected volume
|
|
18
|
+
*
|
|
19
|
+
* Note: this feature is not supported in React Native
|
|
20
|
+
*/
|
|
21
|
+
volume$: Observable<number>;
|
|
22
|
+
constructor();
|
|
23
|
+
/**
|
|
24
|
+
* The currently selected device
|
|
25
|
+
*
|
|
26
|
+
* Note: this feature is not supported in React Native
|
|
27
|
+
*/
|
|
28
|
+
get selectedDevice(): string;
|
|
29
|
+
/**
|
|
30
|
+
* The currently selected volume
|
|
31
|
+
*
|
|
32
|
+
* Note: this feature is not supported in React Native
|
|
33
|
+
*/
|
|
34
|
+
get volume(): number;
|
|
35
|
+
/**
|
|
36
|
+
* Gets the current value of an observable, or undefined if the observable has
|
|
37
|
+
* not emitted a value yet.
|
|
38
|
+
*
|
|
39
|
+
* @param observable$ the observable to get the value from.
|
|
40
|
+
*/
|
|
41
|
+
getCurrentValue: <T>(observable$: Observable<T>) => T;
|
|
42
|
+
/**
|
|
43
|
+
* @internal
|
|
44
|
+
* @param deviceId
|
|
45
|
+
*/
|
|
46
|
+
setDevice(deviceId: string): void;
|
|
47
|
+
/**
|
|
48
|
+
* @internal
|
|
49
|
+
* @param volume
|
|
50
|
+
*/
|
|
51
|
+
setVolume(volume: number): void;
|
|
52
|
+
/**
|
|
53
|
+
* Updates the value of the provided Subject.
|
|
54
|
+
* An `update` can either be a new value or a function which takes
|
|
55
|
+
* the current value and returns a new value.
|
|
56
|
+
*
|
|
57
|
+
* @internal
|
|
58
|
+
*
|
|
59
|
+
* @param subject the subject to update.
|
|
60
|
+
* @param update the update to apply to the subject.
|
|
61
|
+
* @return the updated value.
|
|
62
|
+
*/
|
|
63
|
+
protected setCurrentValue: <T>(subject: import("rxjs").Subject<T>, update: RxUtils.Patch<T>) => T;
|
|
64
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/src/types.d.ts
CHANGED
|
@@ -77,6 +77,8 @@ export interface StreamVideoLocalParticipant extends StreamVideoParticipant {
|
|
|
77
77
|
* The device ID of the currently selected audio output device of the local participant (returned by the [MediaDevices API](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia))
|
|
78
78
|
*
|
|
79
79
|
* If the value is not defined, the user hasn't selected any device (in these cases the default system audio output could be used)
|
|
80
|
+
*
|
|
81
|
+
* @deprecated use call.speaker.state.selectedDevice
|
|
80
82
|
*/
|
|
81
83
|
audioOutputDeviceId?: string;
|
|
82
84
|
}
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "0.3.
|
|
1
|
+
export declare const version = "0.3.13";
|
package/package.json
CHANGED
package/src/Call.ts
CHANGED
|
@@ -116,7 +116,10 @@ import {
|
|
|
116
116
|
} from './coordinator/connection/types';
|
|
117
117
|
import { getClientDetails, getSdkInfo } from './client-details';
|
|
118
118
|
import { getLogger } from './logger';
|
|
119
|
-
import {
|
|
119
|
+
import { CameraManager } from './devices/CameraManager';
|
|
120
|
+
import { MicrophoneManager } from './devices/MicrophoneManager';
|
|
121
|
+
import { CameraDirection } from './devices/CameraManagerState';
|
|
122
|
+
import { SpeakerManager } from './devices/SpeakerManager';
|
|
120
123
|
|
|
121
124
|
/**
|
|
122
125
|
* An object representation of a `Call`.
|
|
@@ -163,6 +166,11 @@ export class Call {
|
|
|
163
166
|
*/
|
|
164
167
|
readonly dynascaleManager = new DynascaleManager(this);
|
|
165
168
|
|
|
169
|
+
/*
|
|
170
|
+
* Device manager for the speaker
|
|
171
|
+
*/
|
|
172
|
+
readonly speaker: SpeakerManager;
|
|
173
|
+
|
|
166
174
|
/**
|
|
167
175
|
* Flag telling whether this call is a "ringing" call.
|
|
168
176
|
*/
|
|
@@ -269,6 +277,7 @@ export class Call {
|
|
|
269
277
|
|
|
270
278
|
this.camera = new CameraManager(this);
|
|
271
279
|
this.microphone = new MicrophoneManager(this);
|
|
280
|
+
this.speaker = new SpeakerManager();
|
|
272
281
|
}
|
|
273
282
|
|
|
274
283
|
private registerEffects() {
|
|
@@ -1230,6 +1239,8 @@ export class Call {
|
|
|
1230
1239
|
*
|
|
1231
1240
|
*
|
|
1232
1241
|
* @param deviceId the selected device, `undefined` means the user wants to use the system's default audio output
|
|
1242
|
+
*
|
|
1243
|
+
* @deprecated use `call.speaker` instead
|
|
1233
1244
|
*/
|
|
1234
1245
|
setAudioOutputDevice = (deviceId?: string) => {
|
|
1235
1246
|
if (!this.sfuClient) return;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { isReactNative } from '../helpers/platforms';
|
|
2
|
+
import { SpeakerState } from './SpeakerState';
|
|
3
|
+
import { getAudioOutputDevices } from './devices';
|
|
4
|
+
|
|
5
|
+
export class SpeakerManager {
|
|
6
|
+
public readonly state = new SpeakerState();
|
|
7
|
+
|
|
8
|
+
constructor() {}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Lists the available audio output devices
|
|
12
|
+
*
|
|
13
|
+
* Note: It prompts the user for a permission to use devices (if not already granted)
|
|
14
|
+
*
|
|
15
|
+
* @returns an Observable that will be updated if a device is connected or disconnected
|
|
16
|
+
*/
|
|
17
|
+
listDevices() {
|
|
18
|
+
return getAudioOutputDevices();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Select device
|
|
23
|
+
*
|
|
24
|
+
* Note: this method is not supported in React Native
|
|
25
|
+
*
|
|
26
|
+
* @param deviceId empty string means the system default
|
|
27
|
+
*/
|
|
28
|
+
select(deviceId: string) {
|
|
29
|
+
if (isReactNative()) {
|
|
30
|
+
throw new Error('This feature is not supported in React Native');
|
|
31
|
+
}
|
|
32
|
+
this.state.setDevice(deviceId);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Set the volume of the audio elements
|
|
37
|
+
* @param volume a number between 0 and 1
|
|
38
|
+
*
|
|
39
|
+
* Note: this method is not supported in React Native
|
|
40
|
+
*/
|
|
41
|
+
setVolume(volume: number) {
|
|
42
|
+
if (isReactNative()) {
|
|
43
|
+
throw new Error('This feature is not supported in React Native');
|
|
44
|
+
}
|
|
45
|
+
if (volume && (volume < 0 || volume > 1)) {
|
|
46
|
+
throw new Error('Volume must be between 0 and 1');
|
|
47
|
+
}
|
|
48
|
+
this.state.setVolume(volume);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { BehaviorSubject, Observable, distinctUntilChanged } from 'rxjs';
|
|
2
|
+
import { RxUtils } from '../store';
|
|
3
|
+
import { checkIfAudioOutputChangeSupported } from './devices';
|
|
4
|
+
|
|
5
|
+
export class SpeakerState {
|
|
6
|
+
protected selectedDeviceSubject = new BehaviorSubject<string>('');
|
|
7
|
+
protected volumeSubject = new BehaviorSubject<number>(1);
|
|
8
|
+
/**
|
|
9
|
+
* [Tells if the browser supports audio output change on 'audio' elements](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/setSinkId).
|
|
10
|
+
*/
|
|
11
|
+
readonly isDeviceSelectionSupported = checkIfAudioOutputChangeSupported();
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* An Observable that emits the currently selected device
|
|
15
|
+
*
|
|
16
|
+
* Note: this feature is not supported in React Native
|
|
17
|
+
*/
|
|
18
|
+
selectedDevice$: Observable<string>;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* An Observable that emits the currently selected volume
|
|
22
|
+
*
|
|
23
|
+
* Note: this feature is not supported in React Native
|
|
24
|
+
*/
|
|
25
|
+
volume$: Observable<number>;
|
|
26
|
+
|
|
27
|
+
constructor() {
|
|
28
|
+
this.selectedDevice$ = this.selectedDeviceSubject
|
|
29
|
+
.asObservable()
|
|
30
|
+
.pipe(distinctUntilChanged());
|
|
31
|
+
this.volume$ = this.volumeSubject
|
|
32
|
+
.asObservable()
|
|
33
|
+
.pipe(distinctUntilChanged());
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The currently selected device
|
|
38
|
+
*
|
|
39
|
+
* Note: this feature is not supported in React Native
|
|
40
|
+
*/
|
|
41
|
+
get selectedDevice() {
|
|
42
|
+
return this.getCurrentValue(this.selectedDevice$);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The currently selected volume
|
|
47
|
+
*
|
|
48
|
+
* Note: this feature is not supported in React Native
|
|
49
|
+
*/
|
|
50
|
+
get volume() {
|
|
51
|
+
return this.getCurrentValue(this.volume$);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Gets the current value of an observable, or undefined if the observable has
|
|
56
|
+
* not emitted a value yet.
|
|
57
|
+
*
|
|
58
|
+
* @param observable$ the observable to get the value from.
|
|
59
|
+
*/
|
|
60
|
+
getCurrentValue = RxUtils.getCurrentValue;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @internal
|
|
64
|
+
* @param deviceId
|
|
65
|
+
*/
|
|
66
|
+
setDevice(deviceId: string) {
|
|
67
|
+
this.setCurrentValue(this.selectedDeviceSubject, deviceId);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @internal
|
|
72
|
+
* @param volume
|
|
73
|
+
*/
|
|
74
|
+
setVolume(volume: number) {
|
|
75
|
+
this.setCurrentValue(this.volumeSubject, volume);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Updates the value of the provided Subject.
|
|
80
|
+
* An `update` can either be a new value or a function which takes
|
|
81
|
+
* the current value and returns a new value.
|
|
82
|
+
*
|
|
83
|
+
* @internal
|
|
84
|
+
*
|
|
85
|
+
* @param subject the subject to update.
|
|
86
|
+
* @param update the update to apply to the subject.
|
|
87
|
+
* @return the updated value.
|
|
88
|
+
*/
|
|
89
|
+
protected setCurrentValue = RxUtils.setCurrentValue;
|
|
90
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, vi, it, expect } from 'vitest';
|
|
2
|
+
import { mockAudioDevices } from './mocks';
|
|
3
|
+
import { of } from 'rxjs';
|
|
4
|
+
import { SpeakerManager } from '../SpeakerManager';
|
|
5
|
+
import { checkIfAudioOutputChangeSupported } from '../devices';
|
|
6
|
+
|
|
7
|
+
vi.mock('../devices.ts', () => {
|
|
8
|
+
console.log('MOCKING devices');
|
|
9
|
+
return {
|
|
10
|
+
getAudioOutputDevices: vi.fn(() => of(mockAudioDevices)),
|
|
11
|
+
checkIfAudioOutputChangeSupported: vi.fn(() => true),
|
|
12
|
+
};
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
describe('SpeakerManager.test', () => {
|
|
16
|
+
let manager: SpeakerManager;
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
manager = new SpeakerManager();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('list devices', () => {
|
|
23
|
+
const spy = vi.fn();
|
|
24
|
+
manager.listDevices().subscribe(spy);
|
|
25
|
+
|
|
26
|
+
expect(spy).toHaveBeenCalledWith(mockAudioDevices);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('tell is browser supports audio output selection', async () => {
|
|
30
|
+
expect(checkIfAudioOutputChangeSupported).toHaveBeenCalled();
|
|
31
|
+
expect(manager.state.isDeviceSelectionSupported).toBe(true);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('select', async () => {
|
|
35
|
+
expect(manager.state.selectedDevice).toBe('');
|
|
36
|
+
|
|
37
|
+
manager.select('new-device');
|
|
38
|
+
|
|
39
|
+
expect(manager.state.selectedDevice).toBe('new-device');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('set volume', async () => {
|
|
43
|
+
expect(manager.state.volume).toBe(1);
|
|
44
|
+
|
|
45
|
+
expect(() => manager.setVolume(2)).toThrowError();
|
|
46
|
+
|
|
47
|
+
expect(manager.state.volume).toBe(1);
|
|
48
|
+
|
|
49
|
+
manager.setVolume(0);
|
|
50
|
+
|
|
51
|
+
expect(manager.state.volume).toBe(0);
|
|
52
|
+
|
|
53
|
+
manager.setVolume(1);
|
|
54
|
+
|
|
55
|
+
expect(manager.state.volume).toBe(1);
|
|
56
|
+
|
|
57
|
+
manager.setVolume(0.5);
|
|
58
|
+
|
|
59
|
+
expect(manager.state.volume).toBe(0.5);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
afterEach(() => {
|
|
63
|
+
vi.clearAllMocks();
|
|
64
|
+
vi.resetModules();
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -6,8 +6,13 @@ import {
|
|
|
6
6
|
VideoTrackType,
|
|
7
7
|
VisibilityState,
|
|
8
8
|
} from '../types';
|
|
9
|
-
import { TrackType, VideoDimension } from '../gen/video/sfu/models/models';
|
|
10
9
|
import {
|
|
10
|
+
SdkType,
|
|
11
|
+
TrackType,
|
|
12
|
+
VideoDimension,
|
|
13
|
+
} from '../gen/video/sfu/models/models';
|
|
14
|
+
import {
|
|
15
|
+
combineLatest,
|
|
11
16
|
distinctUntilChanged,
|
|
12
17
|
distinctUntilKeyChanged,
|
|
13
18
|
map,
|
|
@@ -15,6 +20,7 @@ import {
|
|
|
15
20
|
} from 'rxjs';
|
|
16
21
|
import { ViewportTracker } from './ViewportTracker';
|
|
17
22
|
import { getLogger } from '../logger';
|
|
23
|
+
import { getSdkInfo } from '../client-details';
|
|
18
24
|
|
|
19
25
|
const DEFAULT_VIEWPORT_VISIBILITY_STATE: Record<
|
|
20
26
|
VideoTrackType,
|
|
@@ -326,12 +332,23 @@ export class DynascaleManager {
|
|
|
326
332
|
});
|
|
327
333
|
});
|
|
328
334
|
|
|
329
|
-
const sinkIdSubscription =
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
+
const sinkIdSubscription = combineLatest([
|
|
336
|
+
this.call.state.localParticipant$,
|
|
337
|
+
this.call.speaker.state.selectedDevice$,
|
|
338
|
+
]).subscribe(([p, selectedDevice]) => {
|
|
339
|
+
const deviceId =
|
|
340
|
+
getSdkInfo()?.type === SdkType.REACT
|
|
341
|
+
? p?.audioOutputDeviceId
|
|
342
|
+
: selectedDevice;
|
|
343
|
+
if ('setSinkId' in audioElement) {
|
|
344
|
+
// @ts-expect-error setSinkId is not yet in the lib
|
|
345
|
+
audioElement.setSinkId(deviceId);
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
const volumeSubscription = this.call.speaker.state.volume$.subscribe(
|
|
350
|
+
(volume) => {
|
|
351
|
+
audioElement.volume = volume;
|
|
335
352
|
},
|
|
336
353
|
);
|
|
337
354
|
|
|
@@ -339,6 +356,7 @@ export class DynascaleManager {
|
|
|
339
356
|
|
|
340
357
|
return () => {
|
|
341
358
|
sinkIdSubscription.unsubscribe();
|
|
359
|
+
volumeSubscription.unsubscribe();
|
|
342
360
|
updateMediaStreamSubscription.unsubscribe();
|
|
343
361
|
};
|
|
344
362
|
};
|
|
@@ -4,14 +4,21 @@
|
|
|
4
4
|
|
|
5
5
|
import '../../rtc/__tests__/mocks/webrtc.mocks';
|
|
6
6
|
|
|
7
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
7
|
+
import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
8
8
|
import { DynascaleManager } from '../DynascaleManager';
|
|
9
9
|
import { Call } from '../../Call';
|
|
10
10
|
import { StreamClient } from '../../coordinator/connection/client';
|
|
11
11
|
import { StreamVideoWriteableStateStore } from '../../store';
|
|
12
12
|
import { DebounceType, VisibilityState } from '../../types';
|
|
13
13
|
import { noopComparator } from '../../sorting';
|
|
14
|
-
import { TrackType } from '../../gen/video/sfu/models/models';
|
|
14
|
+
import { SdkType, TrackType } from '../../gen/video/sfu/models/models';
|
|
15
|
+
import { getSdkInfo } from '../../client-details';
|
|
16
|
+
|
|
17
|
+
vi.mock('../../client-details.ts', () => {
|
|
18
|
+
return {
|
|
19
|
+
getSdkInfo: vi.fn(),
|
|
20
|
+
};
|
|
21
|
+
});
|
|
15
22
|
|
|
16
23
|
describe('DynascaleManager', () => {
|
|
17
24
|
let dynascaleManager: DynascaleManager;
|
|
@@ -131,6 +138,23 @@ describe('DynascaleManager', () => {
|
|
|
131
138
|
expect(play).toHaveBeenCalled();
|
|
132
139
|
expect(audioElement.srcObject).toBe(mediaStream);
|
|
133
140
|
|
|
141
|
+
expect(audioElement.volume).toBe(1);
|
|
142
|
+
|
|
143
|
+
// @ts-expect-error setSinkId is not defined in types
|
|
144
|
+
expect(audioElement.setSinkId).toHaveBeenCalledWith('');
|
|
145
|
+
|
|
146
|
+
call.speaker.select('different-device-id');
|
|
147
|
+
|
|
148
|
+
// @ts-expect-error setSinkId is not defined in types
|
|
149
|
+
expect(audioElement.setSinkId).toHaveBeenCalledWith(
|
|
150
|
+
'different-device-id',
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
const mock = getSdkInfo as Mock;
|
|
154
|
+
mock.mockImplementation(() => ({
|
|
155
|
+
type: SdkType.REACT,
|
|
156
|
+
}));
|
|
157
|
+
|
|
134
158
|
call.state.updateParticipant('session-id-local', {
|
|
135
159
|
audioOutputDeviceId: 'new-device-id',
|
|
136
160
|
});
|
|
@@ -138,6 +162,10 @@ describe('DynascaleManager', () => {
|
|
|
138
162
|
// @ts-expect-error setSinkId is not defined in types
|
|
139
163
|
expect(audioElement.setSinkId).toHaveBeenCalledWith('new-device-id');
|
|
140
164
|
|
|
165
|
+
call.speaker.setVolume(0.5);
|
|
166
|
+
|
|
167
|
+
expect(audioElement.volume).toBe(0.5);
|
|
168
|
+
|
|
141
169
|
cleanup?.();
|
|
142
170
|
});
|
|
143
171
|
|
package/src/types.ts
CHANGED
|
@@ -103,6 +103,8 @@ export interface StreamVideoLocalParticipant extends StreamVideoParticipant {
|
|
|
103
103
|
* The device ID of the currently selected audio output device of the local participant (returned by the [MediaDevices API](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia))
|
|
104
104
|
*
|
|
105
105
|
* If the value is not defined, the user hasn't selected any device (in these cases the default system audio output could be used)
|
|
106
|
+
*
|
|
107
|
+
* @deprecated use call.speaker.state.selectedDevice
|
|
106
108
|
*/
|
|
107
109
|
audioOutputDeviceId?: string;
|
|
108
110
|
}
|