@stream-io/video-react-sdk 1.12.10 → 1.13.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.
- package/CHANGELOG.md +278 -207
- package/dist/index.cjs.js +113 -125
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +114 -126
- package/dist/index.es.js.map +1 -1
- package/dist/src/components/DeviceSettings/DeviceSelector.d.ts +0 -1
- package/dist/src/components/Search/SearchResults.d.ts +1 -1
- package/dist/src/core/hooks/useCalculateHardLimit.d.ts +9 -1
- package/dist/src/hooks/usePersistedDevicePreferences.d.ts +5 -2
- package/package.json +6 -7
- package/src/components/BackgroundFilters/BackgroundFilters.tsx +2 -2
- package/src/components/CallControls/RecordCallButton.tsx +1 -1
- package/src/components/CallControls/ToggleAudioButton.tsx +3 -3
- package/src/components/CallControls/ToggleVideoButton.tsx +2 -2
- package/src/components/DeviceSettings/DeviceSelector.tsx +2 -3
- package/src/components/Search/SearchResults.tsx +3 -3
- package/src/core/components/Video/Video.tsx +2 -2
- package/src/hooks/usePersistedDevicePreferences.ts +180 -124
- package/src/utilities/filter.ts +1 -1
|
@@ -11,4 +11,4 @@ export type SearchResultsProps<T> = Pick<SearchController<T>, 'searchResults' |
|
|
|
11
11
|
/** Component to be displayed while the search query request is in progress */
|
|
12
12
|
LoadingIndicator?: ComponentType;
|
|
13
13
|
};
|
|
14
|
-
export declare
|
|
14
|
+
export declare function SearchResults<T>({ EmptySearchResultComponent, LoadingIndicator, searchQueryInProgress, searchResults, SearchResultList, }: SearchResultsProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
export declare const useCalculateHardLimit: (
|
|
1
|
+
export declare const useCalculateHardLimit: (
|
|
2
|
+
/**
|
|
3
|
+
* Element that stretches to 100% of the whole layout component
|
|
4
|
+
*/
|
|
5
|
+
wrapperElement: HTMLDivElement | null,
|
|
6
|
+
/**
|
|
7
|
+
* Element that directly hosts individual `ParticipantView` (or wrapper) elements
|
|
8
|
+
*/
|
|
9
|
+
hostElement: HTMLDivElement | null, limit?: "dynamic" | number) => {
|
|
2
10
|
vertical: number | null;
|
|
3
11
|
horizontal: number | null;
|
|
4
12
|
};
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
export type LocalDevicePreference = {
|
|
2
2
|
selectedDeviceId: string;
|
|
3
|
-
|
|
3
|
+
selectedDeviceLabel: string;
|
|
4
|
+
muted?: boolean;
|
|
4
5
|
};
|
|
5
6
|
export type LocalDevicePreferences = {
|
|
6
|
-
[type in
|
|
7
|
+
[type in DeviceKey]?: LocalDevicePreference | LocalDevicePreference[];
|
|
7
8
|
};
|
|
9
|
+
type DeviceKey = 'microphone' | 'camera' | 'speaker';
|
|
8
10
|
/**
|
|
9
11
|
* This hook will apply and persist the device preferences from local storage.
|
|
10
12
|
*
|
|
11
13
|
* @param key the key to use for local storage.
|
|
12
14
|
*/
|
|
13
15
|
export declare const usePersistedDevicePreferences: (key?: string) => void;
|
|
16
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stream-io/video-react-sdk",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"packageManager": "yarn@3.2.4",
|
|
3
|
+
"version": "1.13.0",
|
|
5
4
|
"main": "./dist/index.cjs.js",
|
|
6
5
|
"module": "./dist/index.es.js",
|
|
7
6
|
"types": "./dist/index.d.ts",
|
|
@@ -31,9 +30,9 @@
|
|
|
31
30
|
],
|
|
32
31
|
"dependencies": {
|
|
33
32
|
"@floating-ui/react": "^0.26.24",
|
|
34
|
-
"@stream-io/video-client": "1.18.
|
|
33
|
+
"@stream-io/video-client": "1.18.8",
|
|
35
34
|
"@stream-io/video-filters-web": "0.1.7",
|
|
36
|
-
"@stream-io/video-react-bindings": "1.5.
|
|
35
|
+
"@stream-io/video-react-bindings": "1.5.10",
|
|
37
36
|
"chart.js": "^4.4.4",
|
|
38
37
|
"clsx": "^2.0.0",
|
|
39
38
|
"react-chartjs-2": "^5.3.0"
|
|
@@ -52,8 +51,8 @@
|
|
|
52
51
|
"@types/react-dom": "^18.3.0",
|
|
53
52
|
"react": "^18.3.1",
|
|
54
53
|
"react-dom": "^18.3.1",
|
|
55
|
-
"rimraf": "^
|
|
56
|
-
"rollup": "^4.
|
|
57
|
-
"typescript": "^5.
|
|
54
|
+
"rimraf": "^6.0.1",
|
|
55
|
+
"rollup": "^4.36.0",
|
|
56
|
+
"typescript": "^5.8.2"
|
|
58
57
|
}
|
|
59
58
|
}
|
|
@@ -321,8 +321,8 @@ const useRenderer = (tfLite: TFLite) => {
|
|
|
321
321
|
output,
|
|
322
322
|
stop: () => {
|
|
323
323
|
renderer?.dispose();
|
|
324
|
-
videoRef.current
|
|
325
|
-
outputStream
|
|
324
|
+
if (videoRef.current) videoRef.current.srcObject = null;
|
|
325
|
+
if (outputStream) disposeOfMediaStream(outputStream);
|
|
326
326
|
},
|
|
327
327
|
};
|
|
328
328
|
},
|
|
@@ -13,8 +13,8 @@ import { Icon } from '../Icon';
|
|
|
13
13
|
import { WithTooltip } from '../Tooltip';
|
|
14
14
|
import { useState } from 'react';
|
|
15
15
|
import {
|
|
16
|
-
PropsWithErrorHandler,
|
|
17
16
|
createCallControlHandler,
|
|
17
|
+
PropsWithErrorHandler,
|
|
18
18
|
} from '../../utilities/callControlHandler';
|
|
19
19
|
|
|
20
20
|
export type ToggleAudioPreviewButtonProps = PropsWithErrorHandler<
|
|
@@ -46,7 +46,7 @@ export const ToggleAudioPreviewButton = (
|
|
|
46
46
|
title={
|
|
47
47
|
!hasBrowserPermission
|
|
48
48
|
? t('Check your browser audio permissions')
|
|
49
|
-
: caption ?? t('Mic')
|
|
49
|
+
: (caption ?? t('Mic'))
|
|
50
50
|
}
|
|
51
51
|
tooltipDisabled={tooltipDisabled}
|
|
52
52
|
>
|
|
@@ -143,7 +143,7 @@ export const ToggleAudioPublishingButton = (
|
|
|
143
143
|
? t('You have no permission to share your audio')
|
|
144
144
|
: !hasBrowserPermission
|
|
145
145
|
? t('Check your browser mic permissions')
|
|
146
|
-
: caption ?? t('Mic')
|
|
146
|
+
: (caption ?? t('Mic'))
|
|
147
147
|
}
|
|
148
148
|
tooltipDisabled={tooltipDisabled}
|
|
149
149
|
>
|
|
@@ -13,8 +13,8 @@ import { Icon } from '../Icon';
|
|
|
13
13
|
import { WithTooltip } from '../Tooltip';
|
|
14
14
|
import { useState } from 'react';
|
|
15
15
|
import {
|
|
16
|
-
PropsWithErrorHandler,
|
|
17
16
|
createCallControlHandler,
|
|
17
|
+
PropsWithErrorHandler,
|
|
18
18
|
} from '../../utilities/callControlHandler';
|
|
19
19
|
|
|
20
20
|
export type ToggleVideoPreviewButtonProps = PropsWithErrorHandler<
|
|
@@ -50,7 +50,7 @@ export const ToggleVideoPreviewButton = (
|
|
|
50
50
|
title={
|
|
51
51
|
!hasBrowserPermission
|
|
52
52
|
? t('Check your browser video permissions')
|
|
53
|
-
: caption ?? t('Video')
|
|
53
|
+
: (caption ?? t('Video'))
|
|
54
54
|
}
|
|
55
55
|
tooltipDisabled={tooltipDisabled}
|
|
56
56
|
>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import clsx from 'clsx';
|
|
2
2
|
import { ChangeEventHandler, useCallback } from 'react';
|
|
3
3
|
|
|
4
|
-
import { useDeviceList } from '../../hooks
|
|
4
|
+
import { useDeviceList } from '../../hooks';
|
|
5
5
|
import { DropDownSelect, DropDownSelectOption } from '../DropdownSelect';
|
|
6
6
|
import { useMenuContext } from '../Menu';
|
|
7
7
|
|
|
@@ -147,9 +147,8 @@ export const DeviceSelector = (props: {
|
|
|
147
147
|
title?: string;
|
|
148
148
|
onChange?: (deviceId: string) => void;
|
|
149
149
|
visualType?: 'list' | 'dropdown';
|
|
150
|
-
placeholder?: string;
|
|
151
150
|
}) => {
|
|
152
|
-
const { visualType = 'list', icon,
|
|
151
|
+
const { visualType = 'list', icon, ...rest } = props;
|
|
153
152
|
|
|
154
153
|
if (visualType === 'list') {
|
|
155
154
|
return <DeviceSelectorList {...rest} />;
|
|
@@ -18,13 +18,13 @@ export type SearchResultsProps<T> = Pick<
|
|
|
18
18
|
LoadingIndicator?: ComponentType;
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
-
export
|
|
21
|
+
export function SearchResults<T>({
|
|
22
22
|
EmptySearchResultComponent,
|
|
23
23
|
LoadingIndicator = DefaultLoadingIndicator,
|
|
24
24
|
searchQueryInProgress,
|
|
25
25
|
searchResults,
|
|
26
26
|
SearchResultList,
|
|
27
|
-
}: SearchResultsProps<T>)
|
|
27
|
+
}: SearchResultsProps<T>) {
|
|
28
28
|
if (searchQueryInProgress) {
|
|
29
29
|
return (
|
|
30
30
|
<div className="str-video__search-results--loading">
|
|
@@ -37,4 +37,4 @@ export const SearchResults = <T extends unknown>({
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
return <SearchResultList data={searchResults} />;
|
|
40
|
-
}
|
|
40
|
+
}
|
|
@@ -196,8 +196,8 @@ export const Video = ({
|
|
|
196
196
|
}}
|
|
197
197
|
/>
|
|
198
198
|
)}
|
|
199
|
-
{isPiP && (
|
|
200
|
-
<
|
|
199
|
+
{isPiP && PictureInPicturePlaceholder && (
|
|
200
|
+
<PictureInPicturePlaceholder
|
|
201
201
|
style={{ position: 'absolute' }}
|
|
202
202
|
participant={participant}
|
|
203
203
|
/>
|
|
@@ -1,150 +1,206 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
2
|
import { CallingState } from '@stream-io/video-client';
|
|
3
|
-
import {
|
|
3
|
+
import { useCallStateHooks } from '@stream-io/video-react-bindings';
|
|
4
4
|
|
|
5
5
|
export type LocalDevicePreference = {
|
|
6
6
|
selectedDeviceId: string;
|
|
7
|
-
|
|
7
|
+
selectedDeviceLabel: string;
|
|
8
|
+
muted?: boolean;
|
|
8
9
|
};
|
|
9
10
|
|
|
10
11
|
export type LocalDevicePreferences = {
|
|
11
|
-
|
|
12
|
+
// Array is preference history with latest preferences first.
|
|
13
|
+
// Single preference still acceptable for backwards compatibility.
|
|
14
|
+
[type in DeviceKey]?: LocalDevicePreference | LocalDevicePreference[];
|
|
12
15
|
};
|
|
13
16
|
|
|
17
|
+
type DeviceKey = 'microphone' | 'camera' | 'speaker';
|
|
18
|
+
|
|
19
|
+
type DeviceState<K extends DeviceKey> = {
|
|
20
|
+
[ManagerKey in K]: DeviceManagerLike;
|
|
21
|
+
} & {
|
|
22
|
+
isMute?: boolean;
|
|
23
|
+
devices: MediaDeviceInfo[];
|
|
24
|
+
selectedDevice: string | undefined;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
interface DeviceManagerLike {
|
|
28
|
+
state: { selectedDevice: string | undefined };
|
|
29
|
+
select(deviceId: string): Promise<void> | void;
|
|
30
|
+
}
|
|
31
|
+
|
|
14
32
|
const defaultDevice = 'default';
|
|
15
33
|
|
|
16
34
|
/**
|
|
17
|
-
* This hook will persist the device
|
|
35
|
+
* This hook will apply and persist the device preferences from local storage.
|
|
18
36
|
*
|
|
19
37
|
* @param key the key to use for local storage.
|
|
20
38
|
*/
|
|
21
|
-
const
|
|
22
|
-
key: string,
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const { useMicrophoneState, useCameraState, useSpeakerState } =
|
|
39
|
+
export const usePersistedDevicePreferences = (
|
|
40
|
+
key: string = '@stream-io/device-preferences',
|
|
41
|
+
): void => {
|
|
42
|
+
const { useCameraState, useMicrophoneState, useSpeakerState } =
|
|
26
43
|
useCallStateHooks();
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const speaker = useSpeakerState();
|
|
31
|
-
useEffect(() => {
|
|
32
|
-
if (!shouldPersistRef.current) return;
|
|
33
|
-
if (!call) return;
|
|
34
|
-
if (call.state.callingState === CallingState.LEFT) return;
|
|
35
|
-
try {
|
|
36
|
-
const preferences: LocalDevicePreferences = {
|
|
37
|
-
mic: {
|
|
38
|
-
selectedDeviceId: mic.selectedDevice || defaultDevice,
|
|
39
|
-
muted: mic.isMute,
|
|
40
|
-
},
|
|
41
|
-
camera: {
|
|
42
|
-
selectedDeviceId: camera.selectedDevice || defaultDevice,
|
|
43
|
-
muted: camera.isMute,
|
|
44
|
-
},
|
|
45
|
-
speaker: {
|
|
46
|
-
selectedDeviceId: speaker.selectedDevice || defaultDevice,
|
|
47
|
-
muted: false,
|
|
48
|
-
},
|
|
49
|
-
};
|
|
50
|
-
window.localStorage.setItem(key, JSON.stringify(preferences));
|
|
51
|
-
} catch (err) {
|
|
52
|
-
console.warn('Failed to save device preferences', err);
|
|
53
|
-
}
|
|
54
|
-
}, [
|
|
55
|
-
call,
|
|
56
|
-
camera.isMute,
|
|
57
|
-
camera.selectedDevice,
|
|
58
|
-
key,
|
|
59
|
-
mic.isMute,
|
|
60
|
-
mic.selectedDevice,
|
|
61
|
-
speaker.selectedDevice,
|
|
62
|
-
shouldPersistRef,
|
|
63
|
-
]);
|
|
44
|
+
usePersistedDevicePreference(key, 'camera', useCameraState());
|
|
45
|
+
usePersistedDevicePreference(key, 'microphone', useMicrophoneState());
|
|
46
|
+
usePersistedDevicePreference(key, 'speaker', useSpeakerState());
|
|
64
47
|
};
|
|
65
48
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
const
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
49
|
+
const usePersistedDevicePreference = <K extends DeviceKey>(
|
|
50
|
+
key: string,
|
|
51
|
+
deviceKey: K,
|
|
52
|
+
state: DeviceState<K>,
|
|
53
|
+
): void => {
|
|
54
|
+
const { useCallCallingState } = useCallStateHooks();
|
|
55
|
+
const callingState = useCallCallingState();
|
|
56
|
+
const [applyingState, setApplyingState] = useState<
|
|
57
|
+
'idle' | 'applying' | 'applied'
|
|
58
|
+
>('idle');
|
|
59
|
+
const manager = state[deviceKey];
|
|
60
|
+
|
|
61
|
+
useEffect(
|
|
62
|
+
function apply() {
|
|
63
|
+
if (
|
|
64
|
+
callingState === CallingState.LEFT ||
|
|
65
|
+
!state.devices?.length ||
|
|
66
|
+
applyingState !== 'idle'
|
|
67
|
+
) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const preferences = parseLocalDevicePreferences(key);
|
|
72
|
+
const preference = preferences[deviceKey];
|
|
73
|
+
|
|
74
|
+
setApplyingState('applying');
|
|
75
|
+
|
|
76
|
+
if (preference && !manager.state.selectedDevice) {
|
|
77
|
+
selectDevice(manager, [preference].flat(), state.devices)
|
|
78
|
+
.catch((err) => {
|
|
79
|
+
console.warn(`Failed to save ${deviceKey} device preferences`, err);
|
|
80
|
+
})
|
|
81
|
+
.finally(() => setApplyingState('applied'));
|
|
82
|
+
} else {
|
|
83
|
+
setApplyingState('applied');
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
[applyingState, callingState, deviceKey, key, manager, state.devices],
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
useEffect(
|
|
90
|
+
function persist() {
|
|
91
|
+
if (
|
|
92
|
+
callingState === CallingState.LEFT ||
|
|
93
|
+
!state.devices?.length ||
|
|
94
|
+
applyingState !== 'applied'
|
|
95
|
+
) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
110
99
|
try {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
100
|
+
patchLocalDevicePreference(key, deviceKey, {
|
|
101
|
+
devices: state.devices,
|
|
102
|
+
selectedDevice: state.selectedDevice,
|
|
103
|
+
isMute: state.isMute,
|
|
104
|
+
});
|
|
114
105
|
} catch (err) {
|
|
115
|
-
console.warn(
|
|
106
|
+
console.warn(`Failed to save ${deviceKey} device preferences`, err);
|
|
116
107
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
108
|
+
},
|
|
109
|
+
[
|
|
110
|
+
applyingState,
|
|
111
|
+
callingState,
|
|
112
|
+
deviceKey,
|
|
113
|
+
key,
|
|
114
|
+
state.devices,
|
|
115
|
+
state.isMute,
|
|
116
|
+
state.selectedDevice,
|
|
117
|
+
],
|
|
118
|
+
);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const parseLocalDevicePreferences = (key: string): LocalDevicePreferences => {
|
|
122
|
+
const preferencesStr = window.localStorage.getItem(key);
|
|
123
|
+
let preferences: LocalDevicePreferences = {};
|
|
124
|
+
|
|
125
|
+
if (preferencesStr) {
|
|
126
|
+
try {
|
|
127
|
+
preferences = JSON.parse(preferencesStr);
|
|
128
|
+
|
|
129
|
+
if (Object.hasOwn(preferences, 'mic')) {
|
|
130
|
+
// for backwards compatibility
|
|
131
|
+
preferences.microphone = (
|
|
132
|
+
preferences as { mic: LocalDevicePreference }
|
|
133
|
+
).mic;
|
|
121
134
|
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
return () => {
|
|
131
|
-
cancel = true;
|
|
132
|
-
};
|
|
133
|
-
}, [call, key]);
|
|
135
|
+
} catch {
|
|
136
|
+
/* assume preferences are empty */
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return preferences;
|
|
134
141
|
};
|
|
135
142
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
143
|
+
const patchLocalDevicePreference = (
|
|
144
|
+
key: string,
|
|
145
|
+
deviceKey: DeviceKey,
|
|
146
|
+
state: Pick<DeviceState<never>, 'devices' | 'selectedDevice' | 'isMute'>,
|
|
147
|
+
): void => {
|
|
148
|
+
const preferences = parseLocalDevicePreferences(key);
|
|
149
|
+
const nextPreference = getSelectedDevicePreference(
|
|
150
|
+
state.devices,
|
|
151
|
+
state.selectedDevice,
|
|
152
|
+
);
|
|
153
|
+
const preferenceHistory = [preferences[deviceKey] ?? []]
|
|
154
|
+
.flat()
|
|
155
|
+
.filter(
|
|
156
|
+
(p) =>
|
|
157
|
+
p.selectedDeviceId !== nextPreference.selectedDeviceId &&
|
|
158
|
+
(p.selectedDeviceLabel === '' ||
|
|
159
|
+
p.selectedDeviceLabel !== nextPreference.selectedDeviceLabel),
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
window.localStorage.setItem(
|
|
163
|
+
key,
|
|
164
|
+
JSON.stringify({
|
|
165
|
+
...preferences,
|
|
166
|
+
mic: undefined, // for backwards compatibility
|
|
167
|
+
[deviceKey]: [
|
|
168
|
+
{
|
|
169
|
+
...nextPreference,
|
|
170
|
+
muted: state.isMute,
|
|
171
|
+
} satisfies LocalDevicePreference,
|
|
172
|
+
...preferenceHistory,
|
|
173
|
+
].slice(0, 3),
|
|
174
|
+
}),
|
|
175
|
+
);
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const selectDevice = async (
|
|
179
|
+
manager: DeviceManagerLike,
|
|
180
|
+
preference: LocalDevicePreference[],
|
|
181
|
+
devices: MediaDeviceInfo[],
|
|
182
|
+
): Promise<void> => {
|
|
183
|
+
for (const p of preference) {
|
|
184
|
+
if (p.selectedDeviceId === defaultDevice) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const device =
|
|
189
|
+
devices.find((d) => d.deviceId === p.selectedDeviceId) ??
|
|
190
|
+
devices.find((d) => d.label === p.selectedDeviceLabel);
|
|
191
|
+
|
|
192
|
+
if (device) {
|
|
193
|
+
await manager.select(device.deviceId);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
147
197
|
};
|
|
148
198
|
|
|
149
|
-
const
|
|
150
|
-
|
|
199
|
+
const getSelectedDevicePreference = (
|
|
200
|
+
devices: MediaDeviceInfo[],
|
|
201
|
+
selectedDevice: string | undefined,
|
|
202
|
+
): Pick<LocalDevicePreference, 'selectedDeviceId' | 'selectedDeviceLabel'> => ({
|
|
203
|
+
selectedDeviceId: selectedDevice || defaultDevice,
|
|
204
|
+
selectedDeviceLabel:
|
|
205
|
+
devices?.find((d) => d.deviceId === selectedDevice)?.label ?? '',
|
|
206
|
+
});
|
package/src/utilities/filter.ts
CHANGED
|
@@ -45,7 +45,7 @@ function checkConditions<T>(obj: T, conditions: Conditions<T>): boolean {
|
|
|
45
45
|
for (const key of Object.keys(conditions) as Array<keyof T>) {
|
|
46
46
|
const operator = conditions[key];
|
|
47
47
|
const maybeOperator = operator && typeof operator === 'object';
|
|
48
|
-
|
|
48
|
+
const value = obj[key];
|
|
49
49
|
|
|
50
50
|
if (maybeOperator && '$eq' in operator) {
|
|
51
51
|
const eqOperator = operator as EqOperator<typeof value>;
|