@stream-io/video-react-sdk 1.28.1 → 1.29.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 +23 -0
- package/dist/background-filters-89nRJ8Uk.cjs.js +352 -0
- package/dist/background-filters-89nRJ8Uk.cjs.js.map +1 -0
- package/dist/background-filters-B5aRj_vl.es.js +350 -0
- package/dist/background-filters-B5aRj_vl.es.js.map +1 -0
- package/dist/index.cjs.js +123 -342
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +125 -344
- package/dist/index.es.js.map +1 -1
- package/dist/src/components/BackgroundFilters/BackgroundFilters.d.ts +5 -144
- package/dist/src/components/BackgroundFilters/BackgroundFiltersProvider.d.ts +15 -0
- package/dist/src/components/BackgroundFilters/index.d.ts +2 -1
- package/dist/src/components/BackgroundFilters/types.d.ts +135 -0
- package/dist/src/core/components/CallLayout/SpeakerLayout.d.ts +6 -1
- package/dist/src/hooks/index.d.ts +1 -0
- package/dist/src/hooks/useDragToScroll.d.ts +18 -0
- package/package.json +4 -4
- package/src/components/BackgroundFilters/BackgroundFilters.tsx +50 -219
- package/src/components/BackgroundFilters/BackgroundFiltersProvider.tsx +60 -0
- package/src/components/BackgroundFilters/index.ts +4 -1
- package/src/components/BackgroundFilters/types.ts +162 -0
- package/src/core/components/CallLayout/SpeakerLayout.tsx +11 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useDragToScroll.ts +162 -0
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
Context,
|
|
3
3
|
PropsWithChildren,
|
|
4
4
|
useCallback,
|
|
5
|
-
useContext,
|
|
6
5
|
useEffect,
|
|
7
6
|
useMemo,
|
|
8
7
|
useRef,
|
|
@@ -13,19 +12,23 @@ import { useCall, useCallStateHooks } from '@stream-io/video-react-bindings';
|
|
|
13
12
|
import { Call, disposeOfMediaStream } from '@stream-io/video-client';
|
|
14
13
|
import {
|
|
15
14
|
BackgroundBlurLevel,
|
|
16
|
-
BackgroundFilter,
|
|
17
15
|
createRenderer,
|
|
18
|
-
isPlatformSupported,
|
|
19
16
|
isMediaPipePlatformSupported,
|
|
20
|
-
|
|
17
|
+
isPlatformSupported,
|
|
21
18
|
loadMediaPipe,
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
loadTFLite,
|
|
20
|
+
PerformanceStats,
|
|
24
21
|
Renderer,
|
|
25
22
|
TFLite,
|
|
26
|
-
|
|
23
|
+
VirtualBackground,
|
|
27
24
|
} from '@stream-io/video-filters-web';
|
|
28
25
|
import clsx from 'clsx';
|
|
26
|
+
import type {
|
|
27
|
+
BackgroundFiltersPerformance,
|
|
28
|
+
BackgroundFiltersProps,
|
|
29
|
+
BackgroundFiltersContextValue,
|
|
30
|
+
PerformanceDegradationReason,
|
|
31
|
+
} from './types';
|
|
29
32
|
|
|
30
33
|
/**
|
|
31
34
|
* Constants for FPS warning calculation.
|
|
@@ -39,32 +42,6 @@ const DEFAULT_FPS = 30;
|
|
|
39
42
|
const DEVIATION_LIMIT = 0.5;
|
|
40
43
|
const OUTLIER_PERSISTENCE = 5;
|
|
41
44
|
|
|
42
|
-
/**
|
|
43
|
-
* Configuration for performance metric thresholds.
|
|
44
|
-
*/
|
|
45
|
-
export type BackgroundFiltersPerformanceThresholds = {
|
|
46
|
-
/**
|
|
47
|
-
* The lower FPS threshold for triggering a performance warning.
|
|
48
|
-
* When the EMA FPS falls below this value, a warning is shown.
|
|
49
|
-
* @default 23
|
|
50
|
-
*/
|
|
51
|
-
fpsWarningThresholdLower?: number;
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* The upper FPS threshold for clearing a performance warning.
|
|
55
|
-
* When the EMA FPS rises above this value, the warning is cleared.
|
|
56
|
-
* @default 25
|
|
57
|
-
*/
|
|
58
|
-
fpsWarningThresholdUpper?: number;
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* The default FPS value used as the initial value for the EMA (Exponential Moving Average)
|
|
62
|
-
* calculation and when stats are unavailable or when resetting the filter.
|
|
63
|
-
* @default 30
|
|
64
|
-
*/
|
|
65
|
-
defaultFps?: number;
|
|
66
|
-
};
|
|
67
|
-
|
|
68
45
|
/**
|
|
69
46
|
* Represents the available background filter processing engines.
|
|
70
47
|
*/
|
|
@@ -74,160 +51,6 @@ enum FilterEngine {
|
|
|
74
51
|
NONE,
|
|
75
52
|
}
|
|
76
53
|
|
|
77
|
-
/**
|
|
78
|
-
* Represents the possible reasons for background filter performance degradation.
|
|
79
|
-
*/
|
|
80
|
-
export enum PerformanceDegradationReason {
|
|
81
|
-
FRAME_DROP = 'frame-drop',
|
|
82
|
-
CPU_THROTTLING = 'cpu-throttling',
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export type BackgroundFiltersProps = PlatformSupportFlags & {
|
|
86
|
-
/**
|
|
87
|
-
* A list of URLs to use as background images.
|
|
88
|
-
*/
|
|
89
|
-
backgroundImages?: string[];
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* The background filter to apply to the video (by default).
|
|
93
|
-
* @default undefined no filter applied
|
|
94
|
-
*/
|
|
95
|
-
backgroundFilter?: BackgroundFilter;
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* The URL of the image to use as the background (by default).
|
|
99
|
-
*/
|
|
100
|
-
backgroundImage?: string;
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* The level of blur to apply to the background (by default).
|
|
104
|
-
* @default 'high'.
|
|
105
|
-
*/
|
|
106
|
-
backgroundBlurLevel?: BackgroundBlurLevel;
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* The base path for the TensorFlow Lite files.
|
|
110
|
-
* @default 'https://unpkg.com/@stream-io/video-filters-web/mediapipe'.
|
|
111
|
-
*/
|
|
112
|
-
basePath?: string;
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* The path to the TensorFlow Lite WebAssembly file.
|
|
116
|
-
*
|
|
117
|
-
* Override this prop to use a custom path to the TensorFlow Lite WebAssembly file
|
|
118
|
-
* (e.g., if you choose to host it yourself).
|
|
119
|
-
*/
|
|
120
|
-
tfFilePath?: string;
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* The path to the MediaPipe model file.
|
|
124
|
-
* Override this prop to use a custom path to the MediaPipe model file
|
|
125
|
-
* (e.g., if you choose to host it yourself).
|
|
126
|
-
*/
|
|
127
|
-
modelFilePath?: string;
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* When true, the filter uses the legacy TensorFlow-based segmentation model.
|
|
131
|
-
* When false, it uses the default MediaPipe Tasks Vision model.
|
|
132
|
-
*
|
|
133
|
-
* Only enable this if you need to mimic the behavior of older SDK versions.
|
|
134
|
-
*/
|
|
135
|
-
useLegacyFilter?: boolean;
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* When a started filter encounters an error, this callback will be executed.
|
|
139
|
-
* The default behavior (not overridable) is unregistering a failed filter.
|
|
140
|
-
* Use this callback to display UI error message, disable the corresponding stream,
|
|
141
|
-
* or to try registering the filter again.
|
|
142
|
-
*/
|
|
143
|
-
onError?: (error: any) => void;
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Configuration for performance metric thresholds.
|
|
147
|
-
* Use this to customize when performance warnings are triggered.
|
|
148
|
-
*/
|
|
149
|
-
performanceThresholds?: BackgroundFiltersPerformanceThresholds;
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Performance degradation information for background filters.
|
|
154
|
-
*
|
|
155
|
-
* Performance is calculated using an Exponential Moving Average (EMA) of FPS values
|
|
156
|
-
* to smooth out quick spikes and provide stable performance warnings.
|
|
157
|
-
*/
|
|
158
|
-
export type BackgroundFiltersPerformance = {
|
|
159
|
-
/**
|
|
160
|
-
* Whether performance is currently degraded.
|
|
161
|
-
*/
|
|
162
|
-
degraded: boolean;
|
|
163
|
-
/**
|
|
164
|
-
* Reasons for performance degradation.
|
|
165
|
-
*/
|
|
166
|
-
reason?: Array<PerformanceDegradationReason>;
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
export type BackgroundFiltersAPI = {
|
|
170
|
-
/**
|
|
171
|
-
* Whether the current platform supports the background filters.
|
|
172
|
-
*/
|
|
173
|
-
isSupported: boolean;
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Indicates whether the background filters engine is loaded and ready.
|
|
177
|
-
*/
|
|
178
|
-
isReady: boolean;
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Performance information for background filters.
|
|
182
|
-
*/
|
|
183
|
-
performance: BackgroundFiltersPerformance;
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Disables all background filters applied to the video.
|
|
187
|
-
*/
|
|
188
|
-
disableBackgroundFilter: () => void;
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Applies a background blur filter to the video.
|
|
192
|
-
*
|
|
193
|
-
* @param blurLevel the level of blur to apply to the background.
|
|
194
|
-
*/
|
|
195
|
-
applyBackgroundBlurFilter: (blurLevel: BackgroundBlurLevel) => void;
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Applies a background image filter to the video.
|
|
199
|
-
*
|
|
200
|
-
* @param imageUrl the URL of the image to use as the background.
|
|
201
|
-
*/
|
|
202
|
-
applyBackgroundImageFilter: (imageUrl: string) => void;
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* The context value for the background filters context.
|
|
207
|
-
*/
|
|
208
|
-
export type BackgroundFiltersContextValue = BackgroundFiltersProps &
|
|
209
|
-
BackgroundFiltersAPI;
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* The context for the background filters.
|
|
213
|
-
*/
|
|
214
|
-
const BackgroundFiltersContext = createContext<
|
|
215
|
-
BackgroundFiltersContextValue | undefined
|
|
216
|
-
>(undefined);
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* A hook to access the background filters context API.
|
|
220
|
-
*/
|
|
221
|
-
export const useBackgroundFilters = () => {
|
|
222
|
-
const context = useContext(BackgroundFiltersContext);
|
|
223
|
-
if (!context) {
|
|
224
|
-
throw new Error(
|
|
225
|
-
'useBackgroundFilters must be used within a BackgroundFiltersProvider',
|
|
226
|
-
);
|
|
227
|
-
}
|
|
228
|
-
return context;
|
|
229
|
-
};
|
|
230
|
-
|
|
231
54
|
/**
|
|
232
55
|
* Determines which filter engine is available.
|
|
233
56
|
* MEDIA_PIPE is the default unless legacy filters are requested or MediaPipe is unsupported.
|
|
@@ -239,12 +62,11 @@ const determineEngine = async (
|
|
|
239
62
|
forceSafariSupport: boolean | undefined,
|
|
240
63
|
forceMobileSupport: boolean | undefined,
|
|
241
64
|
): Promise<FilterEngine> => {
|
|
242
|
-
const isTfPlatformSupported = await isPlatformSupported({
|
|
243
|
-
forceSafariSupport,
|
|
244
|
-
forceMobileSupport,
|
|
245
|
-
});
|
|
246
|
-
|
|
247
65
|
if (useLegacyFilter) {
|
|
66
|
+
const isTfPlatformSupported = await isPlatformSupported({
|
|
67
|
+
forceSafariSupport,
|
|
68
|
+
forceMobileSupport,
|
|
69
|
+
});
|
|
248
70
|
return isTfPlatformSupported ? FilterEngine.TF : FilterEngine.NONE;
|
|
249
71
|
}
|
|
250
72
|
|
|
@@ -263,9 +85,15 @@ const determineEngine = async (
|
|
|
263
85
|
* in your project before using this component.
|
|
264
86
|
*/
|
|
265
87
|
export const BackgroundFiltersProvider = (
|
|
266
|
-
props: PropsWithChildren<BackgroundFiltersProps
|
|
88
|
+
props: PropsWithChildren<BackgroundFiltersProps> & {
|
|
89
|
+
// for code splitting. Prevents circular dependency issues where
|
|
90
|
+
// this Context needs to be present in the main chunk, but also
|
|
91
|
+
// imported by the background filters chunk.
|
|
92
|
+
ContextProvider: Context<BackgroundFiltersContextValue | undefined>;
|
|
93
|
+
},
|
|
267
94
|
) => {
|
|
268
95
|
const {
|
|
96
|
+
ContextProvider,
|
|
269
97
|
children,
|
|
270
98
|
backgroundImages = [],
|
|
271
99
|
backgroundFilter: bgFilterFromProps = undefined,
|
|
@@ -340,7 +168,7 @@ export const BackgroundFiltersProvider = (
|
|
|
340
168
|
const reasons: Array<PerformanceDegradationReason> = [];
|
|
341
169
|
|
|
342
170
|
if (showLowFpsWarning) {
|
|
343
|
-
reasons.push(
|
|
171
|
+
reasons.push('frame-drop');
|
|
344
172
|
}
|
|
345
173
|
|
|
346
174
|
const qualityLimitationReasons =
|
|
@@ -351,7 +179,7 @@ export const BackgroundFiltersProvider = (
|
|
|
351
179
|
qualityLimitationReasons &&
|
|
352
180
|
qualityLimitationReasons?.includes('cpu')
|
|
353
181
|
) {
|
|
354
|
-
reasons.push(
|
|
182
|
+
reasons.push('cpu-throttling');
|
|
355
183
|
}
|
|
356
184
|
|
|
357
185
|
return {
|
|
@@ -458,52 +286,54 @@ export const BackgroundFiltersProvider = (
|
|
|
458
286
|
);
|
|
459
287
|
|
|
460
288
|
const isReady = useLegacyFilter ? !!tfLite : !!mediaPipe;
|
|
289
|
+
const contextValue: BackgroundFiltersContextValue = {
|
|
290
|
+
isSupported,
|
|
291
|
+
performance,
|
|
292
|
+
isReady,
|
|
293
|
+
backgroundImage,
|
|
294
|
+
backgroundBlurLevel,
|
|
295
|
+
backgroundFilter,
|
|
296
|
+
disableBackgroundFilter,
|
|
297
|
+
applyBackgroundBlurFilter,
|
|
298
|
+
applyBackgroundImageFilter,
|
|
299
|
+
backgroundImages,
|
|
300
|
+
tfFilePath,
|
|
301
|
+
modelFilePath,
|
|
302
|
+
basePath,
|
|
303
|
+
onError: handleError,
|
|
304
|
+
};
|
|
461
305
|
return (
|
|
462
|
-
<
|
|
463
|
-
value={{
|
|
464
|
-
isSupported,
|
|
465
|
-
performance,
|
|
466
|
-
isReady,
|
|
467
|
-
backgroundImage,
|
|
468
|
-
backgroundBlurLevel,
|
|
469
|
-
backgroundFilter,
|
|
470
|
-
disableBackgroundFilter,
|
|
471
|
-
applyBackgroundBlurFilter,
|
|
472
|
-
applyBackgroundImageFilter,
|
|
473
|
-
backgroundImages,
|
|
474
|
-
tfFilePath,
|
|
475
|
-
modelFilePath,
|
|
476
|
-
basePath,
|
|
477
|
-
onError: handleError,
|
|
478
|
-
}}
|
|
479
|
-
>
|
|
306
|
+
<ContextProvider.Provider value={contextValue}>
|
|
480
307
|
{children}
|
|
481
308
|
{isReady && (
|
|
482
309
|
<BackgroundFilters
|
|
310
|
+
api={contextValue}
|
|
483
311
|
tfLite={tfLite}
|
|
484
312
|
engine={engine}
|
|
485
313
|
onStats={handleStats}
|
|
486
314
|
/>
|
|
487
315
|
)}
|
|
488
|
-
</
|
|
316
|
+
</ContextProvider.Provider>
|
|
489
317
|
);
|
|
490
318
|
};
|
|
491
319
|
|
|
492
320
|
const BackgroundFilters = (props: {
|
|
321
|
+
api: BackgroundFiltersContextValue;
|
|
493
322
|
tfLite?: TFLite;
|
|
494
323
|
engine: FilterEngine;
|
|
495
324
|
onStats: (stats: PerformanceStats) => void;
|
|
496
325
|
}) => {
|
|
497
326
|
const call = useCall();
|
|
498
|
-
const {
|
|
499
|
-
const {
|
|
327
|
+
const { engine, api, tfLite, onStats } = props;
|
|
328
|
+
const { children, start } = useRenderer(api, tfLite, call, engine);
|
|
329
|
+
const { onError, backgroundFilter } = api;
|
|
500
330
|
const handleErrorRef = useRef<((error: any) => void) | undefined>(undefined);
|
|
501
331
|
handleErrorRef.current = onError;
|
|
502
332
|
|
|
503
333
|
const handleStatsRef = useRef<
|
|
504
334
|
((stats: PerformanceStats) => void) | undefined
|
|
505
335
|
>(undefined);
|
|
506
|
-
handleStatsRef.current =
|
|
336
|
+
handleStatsRef.current = onStats;
|
|
507
337
|
|
|
508
338
|
useEffect(() => {
|
|
509
339
|
if (!call || !backgroundFilter) return;
|
|
@@ -524,6 +354,7 @@ const BackgroundFilters = (props: {
|
|
|
524
354
|
};
|
|
525
355
|
|
|
526
356
|
const useRenderer = (
|
|
357
|
+
api: BackgroundFiltersContextValue,
|
|
527
358
|
tfLite: TFLite | undefined,
|
|
528
359
|
call: Call | undefined,
|
|
529
360
|
engine: FilterEngine,
|
|
@@ -534,7 +365,7 @@ const useRenderer = (
|
|
|
534
365
|
backgroundImage,
|
|
535
366
|
modelFilePath,
|
|
536
367
|
basePath,
|
|
537
|
-
} =
|
|
368
|
+
} = api;
|
|
538
369
|
|
|
539
370
|
const videoRef = useRef<HTMLVideoElement>(null);
|
|
540
371
|
const canvasRef = useRef<HTMLCanvasElement>(null);
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createContext,
|
|
3
|
+
lazy,
|
|
4
|
+
PropsWithChildren,
|
|
5
|
+
ReactNode,
|
|
6
|
+
Suspense,
|
|
7
|
+
useContext,
|
|
8
|
+
} from 'react';
|
|
9
|
+
import type {
|
|
10
|
+
BackgroundFiltersProps,
|
|
11
|
+
BackgroundFiltersContextValue,
|
|
12
|
+
} from './types';
|
|
13
|
+
|
|
14
|
+
const BackgroundFiltersProviderImpl = lazy(() =>
|
|
15
|
+
import('./BackgroundFilters').then((m) => ({
|
|
16
|
+
default: m.BackgroundFiltersProvider,
|
|
17
|
+
})),
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The context for the background filters.
|
|
22
|
+
*/
|
|
23
|
+
const BackgroundFiltersContext = createContext<
|
|
24
|
+
BackgroundFiltersContextValue | undefined
|
|
25
|
+
>(undefined);
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* A hook to access the background filters context API.
|
|
29
|
+
*/
|
|
30
|
+
export const useBackgroundFilters = () => {
|
|
31
|
+
const context = useContext(BackgroundFiltersContext);
|
|
32
|
+
if (!context) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
'useBackgroundFilters must be used within a BackgroundFiltersProvider',
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
return context;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* A provider component that enables the use of background filters in your app.
|
|
42
|
+
*
|
|
43
|
+
* Please make sure you have the `@stream-io/video-filters-web` package installed
|
|
44
|
+
* in your project before using this component.
|
|
45
|
+
*/
|
|
46
|
+
export const BackgroundFiltersProvider = (
|
|
47
|
+
props: PropsWithChildren<BackgroundFiltersProps> & {
|
|
48
|
+
SuspenseFallback?: ReactNode;
|
|
49
|
+
},
|
|
50
|
+
) => {
|
|
51
|
+
const { SuspenseFallback = null, ...filterProps } = props;
|
|
52
|
+
return (
|
|
53
|
+
<Suspense fallback={SuspenseFallback}>
|
|
54
|
+
<BackgroundFiltersProviderImpl
|
|
55
|
+
{...filterProps}
|
|
56
|
+
ContextProvider={BackgroundFiltersContext}
|
|
57
|
+
/>
|
|
58
|
+
</Suspense>
|
|
59
|
+
);
|
|
60
|
+
};
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
BackgroundBlurLevel,
|
|
3
|
+
BackgroundFilter,
|
|
4
|
+
PlatformSupportFlags,
|
|
5
|
+
} from '@stream-io/video-filters-web';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Configuration for performance metric thresholds.
|
|
9
|
+
*/
|
|
10
|
+
export type BackgroundFiltersPerformanceThresholds = {
|
|
11
|
+
/**
|
|
12
|
+
* The lower FPS threshold for triggering a performance warning.
|
|
13
|
+
* When the EMA FPS falls below this value, a warning is shown.
|
|
14
|
+
* @default 23
|
|
15
|
+
*/
|
|
16
|
+
fpsWarningThresholdLower?: number;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The upper FPS threshold for clearing a performance warning.
|
|
20
|
+
* When the EMA FPS rises above this value, the warning is cleared.
|
|
21
|
+
* @default 25
|
|
22
|
+
*/
|
|
23
|
+
fpsWarningThresholdUpper?: number;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The default FPS value used as the initial value for the EMA (Exponential Moving Average)
|
|
27
|
+
* calculation and when stats are unavailable or when resetting the filter.
|
|
28
|
+
* @default 30
|
|
29
|
+
*/
|
|
30
|
+
defaultFps?: number;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type BackgroundFiltersProps = PlatformSupportFlags & {
|
|
34
|
+
/**
|
|
35
|
+
* A list of URLs to use as background images.
|
|
36
|
+
*/
|
|
37
|
+
backgroundImages?: string[];
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The background filter to apply to the video (by default).
|
|
41
|
+
* @default undefined no filter applied
|
|
42
|
+
*/
|
|
43
|
+
backgroundFilter?: BackgroundFilter;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The URL of the image to use as the background (by default).
|
|
47
|
+
*/
|
|
48
|
+
backgroundImage?: string;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The level of blur to apply to the background (by default).
|
|
52
|
+
* @default 'high'.
|
|
53
|
+
*/
|
|
54
|
+
backgroundBlurLevel?: BackgroundBlurLevel;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* The base path for the TensorFlow Lite files.
|
|
58
|
+
* @default 'https://unpkg.com/@stream-io/video-filters-web/mediapipe'.
|
|
59
|
+
*/
|
|
60
|
+
basePath?: string;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* The path to the TensorFlow Lite WebAssembly file.
|
|
64
|
+
*
|
|
65
|
+
* Override this prop to use a custom path to the TensorFlow Lite WebAssembly file
|
|
66
|
+
* (e.g., if you choose to host it yourself).
|
|
67
|
+
*/
|
|
68
|
+
tfFilePath?: string;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The path to the MediaPipe model file.
|
|
72
|
+
* Override this prop to use a custom path to the MediaPipe model file
|
|
73
|
+
* (e.g., if you choose to host it yourself).
|
|
74
|
+
*/
|
|
75
|
+
modelFilePath?: string;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* When true, the filter uses the legacy TensorFlow-based segmentation model.
|
|
79
|
+
* When false, it uses the default MediaPipe Tasks Vision model.
|
|
80
|
+
*
|
|
81
|
+
* Only enable this if you need to mimic the behavior of older SDK versions.
|
|
82
|
+
*/
|
|
83
|
+
useLegacyFilter?: boolean;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* When a started filter encounters an error, this callback will be executed.
|
|
87
|
+
* The default behavior (not overridable) is unregistering a failed filter.
|
|
88
|
+
* Use this callback to display UI error message, disable the corresponding stream,
|
|
89
|
+
* or to try registering the filter again.
|
|
90
|
+
*/
|
|
91
|
+
onError?: (error: any) => void;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Configuration for performance metric thresholds.
|
|
95
|
+
* Use this to customize when performance warnings are triggered.
|
|
96
|
+
*/
|
|
97
|
+
performanceThresholds?: BackgroundFiltersPerformanceThresholds;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Represents the possible reasons for background filter performance degradation.
|
|
102
|
+
*/
|
|
103
|
+
export type PerformanceDegradationReason = 'frame-drop' | 'cpu-throttling';
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Performance degradation information for background filters.
|
|
107
|
+
*
|
|
108
|
+
* Performance is calculated using an Exponential Moving Average (EMA) of FPS values
|
|
109
|
+
* to smooth out quick spikes and provide stable performance warnings.
|
|
110
|
+
*/
|
|
111
|
+
export type BackgroundFiltersPerformance = {
|
|
112
|
+
/**
|
|
113
|
+
* Whether performance is currently degraded.
|
|
114
|
+
*/
|
|
115
|
+
degraded: boolean;
|
|
116
|
+
/**
|
|
117
|
+
* Reasons for performance degradation.
|
|
118
|
+
*/
|
|
119
|
+
reason?: Array<PerformanceDegradationReason>;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export type BackgroundFiltersAPI = {
|
|
123
|
+
/**
|
|
124
|
+
* Whether the current platform supports the background filters.
|
|
125
|
+
*/
|
|
126
|
+
isSupported: boolean;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Indicates whether the background filters engine is loaded and ready.
|
|
130
|
+
*/
|
|
131
|
+
isReady: boolean;
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Performance information for background filters.
|
|
135
|
+
*/
|
|
136
|
+
performance: BackgroundFiltersPerformance;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Disables all background filters applied to the video.
|
|
140
|
+
*/
|
|
141
|
+
disableBackgroundFilter: () => void;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Applies a background blur filter to the video.
|
|
145
|
+
*
|
|
146
|
+
* @param blurLevel the level of blur to apply to the background.
|
|
147
|
+
*/
|
|
148
|
+
applyBackgroundBlurFilter: (blurLevel: BackgroundBlurLevel) => void;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Applies a background image filter to the video.
|
|
152
|
+
*
|
|
153
|
+
* @param imageUrl the URL of the image to use as the background.
|
|
154
|
+
*/
|
|
155
|
+
applyBackgroundImageFilter: (imageUrl: string) => void;
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* The context value for the background filters context.
|
|
160
|
+
*/
|
|
161
|
+
export type BackgroundFiltersContextValue = BackgroundFiltersProps &
|
|
162
|
+
BackgroundFiltersAPI;
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
} from '../ParticipantView';
|
|
11
11
|
import { IconButton } from '../../../components';
|
|
12
12
|
import {
|
|
13
|
+
useDragToScroll,
|
|
13
14
|
useHorizontalScrollPosition,
|
|
14
15
|
useVerticalScrollPosition,
|
|
15
16
|
} from '../../../hooks';
|
|
@@ -88,6 +89,12 @@ export type SpeakerLayoutProps = {
|
|
|
88
89
|
* Whether the layout is muted. Defaults to `false`.
|
|
89
90
|
*/
|
|
90
91
|
muted?: boolean;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Whether to enable drag-to-scroll functionality on the participants bar.
|
|
95
|
+
* @default false
|
|
96
|
+
*/
|
|
97
|
+
enableDragToScroll?: boolean;
|
|
91
98
|
} & Pick<
|
|
92
99
|
ParticipantViewProps,
|
|
93
100
|
'VideoPlaceholder' | 'PictureInPicturePlaceholder'
|
|
@@ -109,6 +116,7 @@ export const SpeakerLayout = ({
|
|
|
109
116
|
filterParticipants,
|
|
110
117
|
pageArrowsVisible = true,
|
|
111
118
|
muted,
|
|
119
|
+
enableDragToScroll = false,
|
|
112
120
|
}: SpeakerLayoutProps) => {
|
|
113
121
|
const call = useCall();
|
|
114
122
|
const { useParticipants } = useCallStateHooks();
|
|
@@ -146,6 +154,9 @@ export const SpeakerLayout = ({
|
|
|
146
154
|
|
|
147
155
|
const isOneOnOneCall = allParticipants.length === 2;
|
|
148
156
|
useSpeakerLayoutSortPreset(call, isOneOnOneCall);
|
|
157
|
+
useDragToScroll(participantsBarWrapperElement, {
|
|
158
|
+
enabled: enableDragToScroll,
|
|
159
|
+
});
|
|
149
160
|
|
|
150
161
|
let participantsWithAppliedLimit = otherParticipants;
|
|
151
162
|
|
package/src/hooks/index.ts
CHANGED