@stream-io/video-react-sdk 1.2.12 → 1.2.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 +13 -0
- package/dist/index.cjs.js +79 -89
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +80 -90
- package/dist/index.es.js.map +1 -1
- package/dist/src/components/BackgroundFilters/BackgroundFilters.d.ts +7 -0
- package/package.json +9 -6
- package/src/components/BackgroundFilters/BackgroundFilters.tsx +136 -129
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
|
|
4
4
|
|
|
5
|
+
### [1.2.13](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-react-sdk-1.2.12...@stream-io/video-react-sdk-1.2.13) (2024-07-02)
|
|
6
|
+
|
|
7
|
+
### Dependency Updates
|
|
8
|
+
|
|
9
|
+
* `@stream-io/video-client` updated to version `1.4.4`
|
|
10
|
+
* `@stream-io/video-filters-web` updated to version `0.1.3`
|
|
11
|
+
* `@stream-io/video-react-bindings` updated to version `0.4.48`
|
|
12
|
+
* `@stream-io/audio-filters-web` updated to version `0.2.1`
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
* refactor background filters ([#1415](https://github.com/GetStream/stream-video-js/issues/1415)) ([deb6da2](https://github.com/GetStream/stream-video-js/commit/deb6da238f541c733451e84b198434671da8dceb))
|
|
17
|
+
|
|
5
18
|
### [1.2.12](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-react-sdk-1.2.11...@stream-io/video-react-sdk-1.2.12) (2024-07-02)
|
|
6
19
|
|
|
7
20
|
|
package/dist/index.cjs.js
CHANGED
|
@@ -5,6 +5,7 @@ var videoReactBindings = require('@stream-io/video-react-bindings');
|
|
|
5
5
|
var jsxRuntime = require('react/jsx-runtime');
|
|
6
6
|
var react = require('react');
|
|
7
7
|
var clsx = require('clsx');
|
|
8
|
+
var reactDom = require('react-dom');
|
|
8
9
|
var videoFiltersWeb = require('@stream-io/video-filters-web');
|
|
9
10
|
var react$1 = require('@floating-ui/react');
|
|
10
11
|
var chart_js = require('chart.js');
|
|
@@ -74,7 +75,7 @@ const useBackgroundFilters = () => {
|
|
|
74
75
|
* in your project before using this component.
|
|
75
76
|
*/
|
|
76
77
|
const BackgroundFiltersProvider = (props) => {
|
|
77
|
-
const { children, backgroundImages = [], backgroundFilter: bgFilterFromProps = undefined, backgroundImage: bgImageFromProps = undefined, backgroundBlurLevel: bgBlurLevelFromProps = 'high', tfFilePath, modelFilePath, basePath, } = props;
|
|
78
|
+
const { children, backgroundImages = [], backgroundFilter: bgFilterFromProps = undefined, backgroundImage: bgImageFromProps = undefined, backgroundBlurLevel: bgBlurLevelFromProps = 'high', tfFilePath, modelFilePath, basePath, onError, } = props;
|
|
78
79
|
const [backgroundFilter, setBackgroundFilter] = react.useState(bgFilterFromProps);
|
|
79
80
|
const [backgroundImage, setBackgroundImage] = react.useState(bgImageFromProps);
|
|
80
81
|
const [backgroundBlurLevel, setBackgroundBlurLevel] = react.useState(bgBlurLevelFromProps);
|
|
@@ -104,6 +105,11 @@ const BackgroundFiltersProvider = (props) => {
|
|
|
104
105
|
.then(setTfLite)
|
|
105
106
|
.catch((err) => console.error('Failed to load TFLite', err));
|
|
106
107
|
}, [basePath, isSupported, modelFilePath, tfFilePath]);
|
|
108
|
+
const handleError = react.useCallback((error) => {
|
|
109
|
+
videoClient.getLogger(['filters'])('warn', 'Filter encountered an error and will be disabled');
|
|
110
|
+
disableBackgroundFilter();
|
|
111
|
+
onError?.(error);
|
|
112
|
+
}, [disableBackgroundFilter, onError]);
|
|
107
113
|
return (jsxRuntime.jsxs(BackgroundFiltersContext.Provider, { value: {
|
|
108
114
|
isSupported,
|
|
109
115
|
isReady: !!tfLite,
|
|
@@ -117,104 +123,88 @@ const BackgroundFiltersProvider = (props) => {
|
|
|
117
123
|
tfFilePath,
|
|
118
124
|
modelFilePath,
|
|
119
125
|
basePath,
|
|
120
|
-
|
|
126
|
+
onError: handleError,
|
|
127
|
+
}, children: [children, tfLite && jsxRuntime.jsx(BackgroundFilters, { tfLite: tfLite })] }));
|
|
121
128
|
};
|
|
122
129
|
const BackgroundFilters = (props) => {
|
|
123
|
-
const { tfLite } = props;
|
|
124
130
|
const call = videoReactBindings.useCall();
|
|
125
|
-
const {
|
|
126
|
-
const
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
const [width, setWidth] = react.useState(1920);
|
|
130
|
-
const [height, setHeight] = react.useState(1080);
|
|
131
|
-
// Holds a ref to the `resolve` function of the returned Promise as part
|
|
132
|
-
// of the `camera.registerFilter()` API. Once the filter is initialized,
|
|
133
|
-
// it should be called with the filtered MediaStream as an argument.
|
|
134
|
-
const signalFilterReadyRef = react.useRef();
|
|
135
|
-
const [mediaStream, setMediaStream] = react.useState();
|
|
136
|
-
const unregister = react.useRef();
|
|
131
|
+
const { children, start } = useRenderer(props.tfLite);
|
|
132
|
+
const { backgroundFilter, onError } = useBackgroundFilters();
|
|
133
|
+
const handleErrorRef = react.useRef(undefined);
|
|
134
|
+
handleErrorRef.current = onError;
|
|
137
135
|
react.useEffect(() => {
|
|
138
136
|
if (!call || !backgroundFilter)
|
|
139
137
|
return;
|
|
140
|
-
const
|
|
141
|
-
return new Promise((resolve) => {
|
|
142
|
-
signalFilterReadyRef.current = resolve;
|
|
143
|
-
setMediaStream(ms);
|
|
144
|
-
});
|
|
145
|
-
}));
|
|
138
|
+
const { unregister } = call.camera.registerFilter((ms) => start(ms, (error) => handleErrorRef.current?.(error)));
|
|
146
139
|
return () => {
|
|
147
|
-
unregister
|
|
148
|
-
.then((unregisterFilter) => unregisterFilter())
|
|
149
|
-
.then(() => (signalFilterReadyRef.current = undefined))
|
|
150
|
-
.then(() => setMediaStream(undefined))
|
|
151
|
-
.catch((err) => console.error('Failed to unregister filter', err));
|
|
140
|
+
unregister();
|
|
152
141
|
};
|
|
153
|
-
}, [backgroundFilter, call]);
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
142
|
+
}, [backgroundFilter, call, start]);
|
|
143
|
+
return children;
|
|
144
|
+
};
|
|
145
|
+
const useRenderer = (tfLite) => {
|
|
146
|
+
const { backgroundFilter, backgroundBlurLevel, backgroundImage } = useBackgroundFilters();
|
|
147
|
+
const videoRef = react.useRef(null);
|
|
148
|
+
const canvasRef = react.useRef(null);
|
|
149
|
+
const bgImageRef = react.useRef(null);
|
|
150
|
+
const [videoSize, setVideoSize] = react.useState({
|
|
151
|
+
width: 1920,
|
|
152
|
+
height: 1080,
|
|
153
|
+
});
|
|
154
|
+
const start = react.useCallback((ms, onError) => {
|
|
155
|
+
let outputStream;
|
|
156
|
+
let renderer;
|
|
157
|
+
const output = new Promise((resolve, reject) => {
|
|
158
|
+
if (!backgroundFilter) {
|
|
159
|
+
reject(new Error('No filter specified'));
|
|
161
160
|
return;
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
};
|
|
193
|
-
const RenderPipeline = (props) => {
|
|
194
|
-
const { tfLite, videoRef, canvasRef, backgroundImageRef } = props;
|
|
195
|
-
const { backgroundFilter, backgroundBlurLevel } = useBackgroundFilters();
|
|
196
|
-
react.useEffect(() => {
|
|
197
|
-
if (!videoRef || !canvasRef || !backgroundFilter)
|
|
198
|
-
return;
|
|
199
|
-
if (backgroundFilter === 'image' && !backgroundImageRef)
|
|
200
|
-
return;
|
|
201
|
-
const renderer = videoFiltersWeb.createRenderer(tfLite, videoRef, canvasRef, {
|
|
202
|
-
backgroundFilter,
|
|
203
|
-
backgroundImage: backgroundImageRef ?? undefined,
|
|
204
|
-
backgroundBlurLevel,
|
|
161
|
+
}
|
|
162
|
+
const videoEl = videoRef.current;
|
|
163
|
+
const canvasEl = canvasRef.current;
|
|
164
|
+
const bgImageEl = bgImageRef.current;
|
|
165
|
+
if (!videoEl || !canvasEl || (backgroundImage && !bgImageEl)) {
|
|
166
|
+
// You should start renderer in effect or event handlers
|
|
167
|
+
reject(new Error('Renderer started before elements are ready'));
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
videoEl.srcObject = ms;
|
|
171
|
+
videoEl.play().then(() => {
|
|
172
|
+
const [track] = ms.getVideoTracks();
|
|
173
|
+
if (!track) {
|
|
174
|
+
reject(new Error('No video tracks in input media stream'));
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const trackSettings = track.getSettings();
|
|
178
|
+
reactDom.flushSync(() => setVideoSize({
|
|
179
|
+
width: trackSettings.width ?? 0,
|
|
180
|
+
height: trackSettings.height ?? 0,
|
|
181
|
+
}));
|
|
182
|
+
renderer = videoFiltersWeb.createRenderer(tfLite, videoEl, canvasEl, {
|
|
183
|
+
backgroundFilter,
|
|
184
|
+
backgroundBlurLevel,
|
|
185
|
+
backgroundImage: bgImageEl ?? undefined,
|
|
186
|
+
}, onError);
|
|
187
|
+
outputStream = canvasEl.captureStream();
|
|
188
|
+
resolve(outputStream);
|
|
189
|
+
}, () => {
|
|
190
|
+
reject(new Error('Could not play the source video stream'));
|
|
191
|
+
});
|
|
205
192
|
});
|
|
206
|
-
return
|
|
207
|
-
|
|
193
|
+
return {
|
|
194
|
+
output,
|
|
195
|
+
stop: () => {
|
|
196
|
+
renderer?.dispose();
|
|
197
|
+
videoRef.current && (videoRef.current.srcObject = null);
|
|
198
|
+
outputStream && videoClient.disposeOfMediaStream(outputStream);
|
|
199
|
+
},
|
|
208
200
|
};
|
|
209
|
-
}, [
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
]);
|
|
217
|
-
return null;
|
|
201
|
+
}, [backgroundBlurLevel, backgroundFilter, backgroundImage, tfLite]);
|
|
202
|
+
const children = (jsxRuntime.jsxs("div", { className: "str-video__background-filters", children: [jsxRuntime.jsx("video", { className: clsx('str-video__background-filters__video', videoSize.height > videoSize.width &&
|
|
203
|
+
'str-video__background-filters__video--tall'), ref: videoRef, playsInline: true, muted: true, controls: false, ...videoSize }), backgroundImage && (jsxRuntime.jsx("img", { className: "str-video__background-filters__background-image", alt: "Background", ref: bgImageRef, src: backgroundImage, ...videoSize })), jsxRuntime.jsx("canvas", { className: "str-video__background-filters__target-canvas", ...videoSize, ref: canvasRef })] }));
|
|
204
|
+
return {
|
|
205
|
+
start,
|
|
206
|
+
children,
|
|
207
|
+
};
|
|
218
208
|
};
|
|
219
209
|
|
|
220
210
|
const useFloatingUIPreset = ({ middleware = [], placement, strategy, offset: offsetInPx = 10, }) => {
|
|
@@ -2622,7 +2612,7 @@ const LivestreamPlayer = (props) => {
|
|
|
2622
2612
|
return (jsxRuntime.jsx(StreamCall, { call: call, children: jsxRuntime.jsx(LivestreamLayout, { ...layoutProps }) }));
|
|
2623
2613
|
};
|
|
2624
2614
|
|
|
2625
|
-
const [major, minor, patch] = ("1.2.
|
|
2615
|
+
const [major, minor, patch] = ("1.2.13" ).split('.');
|
|
2626
2616
|
videoClient.setSdkInfo({
|
|
2627
2617
|
type: videoClient.SfuModels.SdkType.REACT,
|
|
2628
2618
|
major,
|