@stream-io/video-react-sdk 1.28.0 → 1.28.2
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 +18 -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 +7 -341
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +9 -343
- 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/package.json +3 -3
- 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/dist/index.cjs.js
CHANGED
|
@@ -6,8 +6,6 @@ var jsxRuntime = require('react/jsx-runtime');
|
|
|
6
6
|
var react = require('react');
|
|
7
7
|
var react$1 = require('@floating-ui/react');
|
|
8
8
|
var clsx = require('clsx');
|
|
9
|
-
var reactDom = require('react-dom');
|
|
10
|
-
var videoFiltersWeb = require('@stream-io/video-filters-web');
|
|
11
9
|
|
|
12
10
|
const Audio = ({ participant, trackType = 'audioTrack', ...rest }) => {
|
|
13
11
|
const call = videoReactBindings.useCall();
|
|
@@ -957,34 +955,9 @@ const AvatarFallback = ({ className, names, style, }) => {
|
|
|
957
955
|
return (jsxRuntime.jsx("div", { className: clsx('str-video__avatar--initials-fallback', className), style: style, children: jsxRuntime.jsxs("div", { children: [names[0][0], names[1]?.[0]] }) }));
|
|
958
956
|
};
|
|
959
957
|
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
* and uses two thresholds to avoid flickering near the limit.
|
|
964
|
-
*/
|
|
965
|
-
const ALPHA = 0.2;
|
|
966
|
-
const FPS_WARNING_THRESHOLD_LOWER = 23;
|
|
967
|
-
const FPS_WARNING_THRESHOLD_UPPER = 25;
|
|
968
|
-
const DEFAULT_FPS = 30;
|
|
969
|
-
const DEVIATION_LIMIT = 0.5;
|
|
970
|
-
const OUTLIER_PERSISTENCE = 5;
|
|
971
|
-
/**
|
|
972
|
-
* Represents the available background filter processing engines.
|
|
973
|
-
*/
|
|
974
|
-
var FilterEngine;
|
|
975
|
-
(function (FilterEngine) {
|
|
976
|
-
FilterEngine[FilterEngine["TF"] = 0] = "TF";
|
|
977
|
-
FilterEngine[FilterEngine["MEDIA_PIPE"] = 1] = "MEDIA_PIPE";
|
|
978
|
-
FilterEngine[FilterEngine["NONE"] = 2] = "NONE";
|
|
979
|
-
})(FilterEngine || (FilterEngine = {}));
|
|
980
|
-
/**
|
|
981
|
-
* Represents the possible reasons for background filter performance degradation.
|
|
982
|
-
*/
|
|
983
|
-
exports.PerformanceDegradationReason = void 0;
|
|
984
|
-
(function (PerformanceDegradationReason) {
|
|
985
|
-
PerformanceDegradationReason["FRAME_DROP"] = "frame-drop";
|
|
986
|
-
PerformanceDegradationReason["CPU_THROTTLING"] = "cpu-throttling";
|
|
987
|
-
})(exports.PerformanceDegradationReason || (exports.PerformanceDegradationReason = {}));
|
|
958
|
+
const BackgroundFiltersProviderImpl = react.lazy(() => Promise.resolve().then(function () { return require('./background-filters-89nRJ8Uk.cjs.js'); }).then((m) => ({
|
|
959
|
+
default: m.BackgroundFiltersProvider,
|
|
960
|
+
})));
|
|
988
961
|
/**
|
|
989
962
|
* The context for the background filters.
|
|
990
963
|
*/
|
|
@@ -999,26 +972,6 @@ const useBackgroundFilters = () => {
|
|
|
999
972
|
}
|
|
1000
973
|
return context;
|
|
1001
974
|
};
|
|
1002
|
-
/**
|
|
1003
|
-
* Determines which filter engine is available.
|
|
1004
|
-
* MEDIA_PIPE is the default unless legacy filters are requested or MediaPipe is unsupported.
|
|
1005
|
-
*
|
|
1006
|
-
* Returns NONE if neither is supported.
|
|
1007
|
-
*/
|
|
1008
|
-
const determineEngine = async (useLegacyFilter, forceSafariSupport, forceMobileSupport) => {
|
|
1009
|
-
const isTfPlatformSupported = await videoFiltersWeb.isPlatformSupported({
|
|
1010
|
-
forceSafariSupport,
|
|
1011
|
-
forceMobileSupport,
|
|
1012
|
-
});
|
|
1013
|
-
if (useLegacyFilter) {
|
|
1014
|
-
return isTfPlatformSupported ? FilterEngine.TF : FilterEngine.NONE;
|
|
1015
|
-
}
|
|
1016
|
-
const isMediaPipeSupported = await videoFiltersWeb.isMediaPipePlatformSupported({
|
|
1017
|
-
forceSafariSupport,
|
|
1018
|
-
forceMobileSupport,
|
|
1019
|
-
});
|
|
1020
|
-
return isMediaPipeSupported ? FilterEngine.MEDIA_PIPE : FilterEngine.NONE;
|
|
1021
|
-
};
|
|
1022
975
|
/**
|
|
1023
976
|
* A provider component that enables the use of background filters in your app.
|
|
1024
977
|
*
|
|
@@ -1026,295 +979,8 @@ const determineEngine = async (useLegacyFilter, forceSafariSupport, forceMobileS
|
|
|
1026
979
|
* in your project before using this component.
|
|
1027
980
|
*/
|
|
1028
981
|
const BackgroundFiltersProvider = (props) => {
|
|
1029
|
-
const {
|
|
1030
|
-
|
|
1031
|
-
const { useCallStatsReport } = videoReactBindings.useCallStateHooks();
|
|
1032
|
-
const callStatsReport = useCallStatsReport();
|
|
1033
|
-
const [backgroundFilter, setBackgroundFilter] = react.useState(bgFilterFromProps);
|
|
1034
|
-
const [backgroundImage, setBackgroundImage] = react.useState(bgImageFromProps);
|
|
1035
|
-
const [backgroundBlurLevel, setBackgroundBlurLevel] = react.useState(bgBlurLevelFromProps);
|
|
1036
|
-
const [showLowFpsWarning, setShowLowFpsWarning] = react.useState(false);
|
|
1037
|
-
const fpsWarningThresholdLower = performanceThresholds?.fpsWarningThresholdLower ??
|
|
1038
|
-
FPS_WARNING_THRESHOLD_LOWER;
|
|
1039
|
-
const fpsWarningThresholdUpper = performanceThresholds?.fpsWarningThresholdUpper ??
|
|
1040
|
-
FPS_WARNING_THRESHOLD_UPPER;
|
|
1041
|
-
const defaultFps = performanceThresholds?.defaultFps ?? DEFAULT_FPS;
|
|
1042
|
-
const emaRef = react.useRef(defaultFps);
|
|
1043
|
-
const outlierStreakRef = react.useRef(0);
|
|
1044
|
-
const handleStats = react.useCallback((stats) => {
|
|
1045
|
-
const fps = stats?.fps;
|
|
1046
|
-
if (fps === undefined || fps === null) {
|
|
1047
|
-
emaRef.current = defaultFps;
|
|
1048
|
-
outlierStreakRef.current = 0;
|
|
1049
|
-
setShowLowFpsWarning(false);
|
|
1050
|
-
return;
|
|
1051
|
-
}
|
|
1052
|
-
const prevEma = emaRef.current;
|
|
1053
|
-
const deviation = Math.abs(fps - prevEma) / prevEma;
|
|
1054
|
-
const isOutlier = fps < prevEma && deviation > DEVIATION_LIMIT;
|
|
1055
|
-
outlierStreakRef.current = isOutlier ? outlierStreakRef.current + 1 : 0;
|
|
1056
|
-
if (isOutlier && outlierStreakRef.current < OUTLIER_PERSISTENCE)
|
|
1057
|
-
return;
|
|
1058
|
-
emaRef.current = ALPHA * fps + (1 - ALPHA) * prevEma;
|
|
1059
|
-
setShowLowFpsWarning((prev) => {
|
|
1060
|
-
if (prev && emaRef.current > fpsWarningThresholdUpper)
|
|
1061
|
-
return false;
|
|
1062
|
-
if (!prev && emaRef.current < fpsWarningThresholdLower)
|
|
1063
|
-
return true;
|
|
1064
|
-
return prev;
|
|
1065
|
-
});
|
|
1066
|
-
}, [fpsWarningThresholdLower, fpsWarningThresholdUpper, defaultFps]);
|
|
1067
|
-
const performance = react.useMemo(() => {
|
|
1068
|
-
if (!backgroundFilter) {
|
|
1069
|
-
return { degraded: false };
|
|
1070
|
-
}
|
|
1071
|
-
const reasons = [];
|
|
1072
|
-
if (showLowFpsWarning) {
|
|
1073
|
-
reasons.push(exports.PerformanceDegradationReason.FRAME_DROP);
|
|
1074
|
-
}
|
|
1075
|
-
const qualityLimitationReasons = callStatsReport?.publisherStats?.qualityLimitationReasons;
|
|
1076
|
-
if (showLowFpsWarning &&
|
|
1077
|
-
qualityLimitationReasons &&
|
|
1078
|
-
qualityLimitationReasons?.includes('cpu')) {
|
|
1079
|
-
reasons.push(exports.PerformanceDegradationReason.CPU_THROTTLING);
|
|
1080
|
-
}
|
|
1081
|
-
return {
|
|
1082
|
-
degraded: reasons.length > 0,
|
|
1083
|
-
reason: reasons.length > 0 ? reasons : undefined,
|
|
1084
|
-
};
|
|
1085
|
-
}, [
|
|
1086
|
-
showLowFpsWarning,
|
|
1087
|
-
callStatsReport?.publisherStats?.qualityLimitationReasons,
|
|
1088
|
-
backgroundFilter,
|
|
1089
|
-
]);
|
|
1090
|
-
const prevDegradedRef = react.useRef(undefined);
|
|
1091
|
-
react.useEffect(() => {
|
|
1092
|
-
const currentDegraded = performance.degraded;
|
|
1093
|
-
const prevDegraded = prevDegradedRef.current;
|
|
1094
|
-
if (!!backgroundFilter &&
|
|
1095
|
-
prevDegraded !== undefined &&
|
|
1096
|
-
prevDegraded !== currentDegraded) {
|
|
1097
|
-
call?.tracer.trace('backgroundFilters.performance', {
|
|
1098
|
-
degraded: currentDegraded,
|
|
1099
|
-
reason: performance?.reason,
|
|
1100
|
-
fps: emaRef.current,
|
|
1101
|
-
});
|
|
1102
|
-
}
|
|
1103
|
-
prevDegradedRef.current = currentDegraded;
|
|
1104
|
-
}, [
|
|
1105
|
-
performanceThresholds,
|
|
1106
|
-
performance.degraded,
|
|
1107
|
-
performance.reason,
|
|
1108
|
-
backgroundFilter,
|
|
1109
|
-
call?.tracer,
|
|
1110
|
-
]);
|
|
1111
|
-
const applyBackgroundImageFilter = react.useCallback((imageUrl) => {
|
|
1112
|
-
setBackgroundFilter('image');
|
|
1113
|
-
setBackgroundImage(imageUrl);
|
|
1114
|
-
}, []);
|
|
1115
|
-
const applyBackgroundBlurFilter = react.useCallback((blurLevel = 'high') => {
|
|
1116
|
-
setBackgroundFilter('blur');
|
|
1117
|
-
setBackgroundBlurLevel(blurLevel);
|
|
1118
|
-
}, []);
|
|
1119
|
-
const disableBackgroundFilter = react.useCallback(() => {
|
|
1120
|
-
setBackgroundFilter(undefined);
|
|
1121
|
-
setBackgroundImage(undefined);
|
|
1122
|
-
setBackgroundBlurLevel(undefined);
|
|
1123
|
-
emaRef.current = defaultFps;
|
|
1124
|
-
outlierStreakRef.current = 0;
|
|
1125
|
-
setShowLowFpsWarning(false);
|
|
1126
|
-
}, [defaultFps]);
|
|
1127
|
-
const [engine, setEngine] = react.useState(FilterEngine.NONE);
|
|
1128
|
-
const [isSupported, setIsSupported] = react.useState(false);
|
|
1129
|
-
react.useEffect(() => {
|
|
1130
|
-
determineEngine(useLegacyFilter, forceSafariSupport, forceMobileSupport).then((determinedEngine) => {
|
|
1131
|
-
setEngine(determinedEngine);
|
|
1132
|
-
setIsSupported(determinedEngine !== FilterEngine.NONE);
|
|
1133
|
-
});
|
|
1134
|
-
}, [forceMobileSupport, forceSafariSupport, useLegacyFilter]);
|
|
1135
|
-
const [tfLite, setTfLite] = react.useState();
|
|
1136
|
-
react.useEffect(() => {
|
|
1137
|
-
if (engine !== FilterEngine.TF)
|
|
1138
|
-
return;
|
|
1139
|
-
videoFiltersWeb.loadTFLite({ basePath, modelFilePath, tfFilePath })
|
|
1140
|
-
.then(setTfLite)
|
|
1141
|
-
.catch((err) => console.error('Failed to load TFLite', err));
|
|
1142
|
-
}, [basePath, engine, modelFilePath, tfFilePath]);
|
|
1143
|
-
const [mediaPipe, setMediaPipe] = react.useState();
|
|
1144
|
-
react.useEffect(() => {
|
|
1145
|
-
if (engine !== FilterEngine.MEDIA_PIPE)
|
|
1146
|
-
return;
|
|
1147
|
-
videoFiltersWeb.loadMediaPipe({
|
|
1148
|
-
basePath: basePath,
|
|
1149
|
-
modelPath: modelFilePath,
|
|
1150
|
-
})
|
|
1151
|
-
.then(setMediaPipe)
|
|
1152
|
-
.catch((err) => console.error('Failed to preload MediaPipe', err));
|
|
1153
|
-
}, [engine, modelFilePath, basePath]);
|
|
1154
|
-
const handleError = react.useCallback((error) => {
|
|
1155
|
-
console.warn('[filters] Filter encountered an error and will be disabled');
|
|
1156
|
-
disableBackgroundFilter();
|
|
1157
|
-
onError?.(error);
|
|
1158
|
-
}, [disableBackgroundFilter, onError]);
|
|
1159
|
-
const isReady = useLegacyFilter ? !!tfLite : !!mediaPipe;
|
|
1160
|
-
return (jsxRuntime.jsxs(BackgroundFiltersContext.Provider, { value: {
|
|
1161
|
-
isSupported,
|
|
1162
|
-
performance,
|
|
1163
|
-
isReady,
|
|
1164
|
-
backgroundImage,
|
|
1165
|
-
backgroundBlurLevel,
|
|
1166
|
-
backgroundFilter,
|
|
1167
|
-
disableBackgroundFilter,
|
|
1168
|
-
applyBackgroundBlurFilter,
|
|
1169
|
-
applyBackgroundImageFilter,
|
|
1170
|
-
backgroundImages,
|
|
1171
|
-
tfFilePath,
|
|
1172
|
-
modelFilePath,
|
|
1173
|
-
basePath,
|
|
1174
|
-
onError: handleError,
|
|
1175
|
-
}, children: [children, isReady && (jsxRuntime.jsx(BackgroundFilters, { tfLite: tfLite, engine: engine, onStats: handleStats }))] }));
|
|
1176
|
-
};
|
|
1177
|
-
const BackgroundFilters = (props) => {
|
|
1178
|
-
const call = videoReactBindings.useCall();
|
|
1179
|
-
const { children, start } = useRenderer(props.tfLite, call, props.engine);
|
|
1180
|
-
const { onError, backgroundFilter } = useBackgroundFilters();
|
|
1181
|
-
const handleErrorRef = react.useRef(undefined);
|
|
1182
|
-
handleErrorRef.current = onError;
|
|
1183
|
-
const handleStatsRef = react.useRef(undefined);
|
|
1184
|
-
handleStatsRef.current = props.onStats;
|
|
1185
|
-
react.useEffect(() => {
|
|
1186
|
-
if (!call || !backgroundFilter)
|
|
1187
|
-
return;
|
|
1188
|
-
const { unregister } = call.camera.registerFilter((ms) => {
|
|
1189
|
-
return start(ms, (error) => handleErrorRef.current?.(error), (stats) => handleStatsRef.current?.(stats));
|
|
1190
|
-
});
|
|
1191
|
-
return () => {
|
|
1192
|
-
unregister().catch((err) => console.warn(`Can't unregister filter`, err));
|
|
1193
|
-
};
|
|
1194
|
-
}, [call, start, backgroundFilter]);
|
|
1195
|
-
return children;
|
|
1196
|
-
};
|
|
1197
|
-
const useRenderer = (tfLite, call, engine) => {
|
|
1198
|
-
const { backgroundFilter, backgroundBlurLevel, backgroundImage, modelFilePath, basePath, } = useBackgroundFilters();
|
|
1199
|
-
const videoRef = react.useRef(null);
|
|
1200
|
-
const canvasRef = react.useRef(null);
|
|
1201
|
-
const bgImageRef = react.useRef(null);
|
|
1202
|
-
const [videoSize, setVideoSize] = react.useState({
|
|
1203
|
-
width: 1920,
|
|
1204
|
-
height: 1080,
|
|
1205
|
-
});
|
|
1206
|
-
const start = react.useCallback((ms, onError, onStats) => {
|
|
1207
|
-
let outputStream;
|
|
1208
|
-
let processor;
|
|
1209
|
-
let renderer;
|
|
1210
|
-
const output = new Promise((resolve, reject) => {
|
|
1211
|
-
if (!backgroundFilter) {
|
|
1212
|
-
reject(new Error('No filter specified'));
|
|
1213
|
-
return;
|
|
1214
|
-
}
|
|
1215
|
-
const videoEl = videoRef.current;
|
|
1216
|
-
const canvasEl = canvasRef.current;
|
|
1217
|
-
const bgImageEl = bgImageRef.current;
|
|
1218
|
-
const [track] = ms.getVideoTracks();
|
|
1219
|
-
if (!track) {
|
|
1220
|
-
reject(new Error('No video tracks in input media stream'));
|
|
1221
|
-
return;
|
|
1222
|
-
}
|
|
1223
|
-
if (engine === FilterEngine.MEDIA_PIPE) {
|
|
1224
|
-
call?.tracer.trace('backgroundFilters.enable', {
|
|
1225
|
-
backgroundFilter,
|
|
1226
|
-
backgroundBlurLevel,
|
|
1227
|
-
backgroundImage,
|
|
1228
|
-
engine,
|
|
1229
|
-
});
|
|
1230
|
-
if (!videoEl) {
|
|
1231
|
-
reject(new Error('Renderer started before elements are ready'));
|
|
1232
|
-
return;
|
|
1233
|
-
}
|
|
1234
|
-
const trackSettings = track.getSettings();
|
|
1235
|
-
reactDom.flushSync(() => setVideoSize({
|
|
1236
|
-
width: trackSettings.width ?? 0,
|
|
1237
|
-
height: trackSettings.height ?? 0,
|
|
1238
|
-
}));
|
|
1239
|
-
processor = new videoFiltersWeb.VirtualBackground(track, {
|
|
1240
|
-
basePath: basePath,
|
|
1241
|
-
modelPath: modelFilePath,
|
|
1242
|
-
backgroundBlurLevel,
|
|
1243
|
-
backgroundImage,
|
|
1244
|
-
backgroundFilter,
|
|
1245
|
-
}, { onError, onStats });
|
|
1246
|
-
processor
|
|
1247
|
-
.start()
|
|
1248
|
-
.then((processedTrack) => {
|
|
1249
|
-
outputStream = new MediaStream([processedTrack]);
|
|
1250
|
-
resolve(outputStream);
|
|
1251
|
-
})
|
|
1252
|
-
.catch((error) => {
|
|
1253
|
-
reject(error);
|
|
1254
|
-
});
|
|
1255
|
-
return;
|
|
1256
|
-
}
|
|
1257
|
-
if (engine === FilterEngine.TF) {
|
|
1258
|
-
if (!videoEl || !canvasEl || (backgroundImage && !bgImageEl)) {
|
|
1259
|
-
reject(new Error('Renderer started before elements are ready'));
|
|
1260
|
-
return;
|
|
1261
|
-
}
|
|
1262
|
-
videoEl.srcObject = ms;
|
|
1263
|
-
videoEl.play().then(() => {
|
|
1264
|
-
const trackSettings = track.getSettings();
|
|
1265
|
-
reactDom.flushSync(() => setVideoSize({
|
|
1266
|
-
width: trackSettings.width ?? 0,
|
|
1267
|
-
height: trackSettings.height ?? 0,
|
|
1268
|
-
}));
|
|
1269
|
-
call?.tracer.trace('backgroundFilters.enable', {
|
|
1270
|
-
backgroundFilter,
|
|
1271
|
-
backgroundBlurLevel,
|
|
1272
|
-
backgroundImage,
|
|
1273
|
-
engine,
|
|
1274
|
-
});
|
|
1275
|
-
if (!tfLite) {
|
|
1276
|
-
reject(new Error('TensorFlow Lite not loaded'));
|
|
1277
|
-
return;
|
|
1278
|
-
}
|
|
1279
|
-
renderer = videoFiltersWeb.createRenderer(tfLite, videoEl, canvasEl, {
|
|
1280
|
-
backgroundFilter,
|
|
1281
|
-
backgroundBlurLevel,
|
|
1282
|
-
backgroundImage: bgImageEl ?? undefined,
|
|
1283
|
-
}, onError);
|
|
1284
|
-
outputStream = canvasEl.captureStream();
|
|
1285
|
-
resolve(outputStream);
|
|
1286
|
-
}, () => {
|
|
1287
|
-
reject(new Error('Could not play the source video stream'));
|
|
1288
|
-
});
|
|
1289
|
-
return;
|
|
1290
|
-
}
|
|
1291
|
-
reject(new Error('No supported engine available'));
|
|
1292
|
-
});
|
|
1293
|
-
return {
|
|
1294
|
-
output,
|
|
1295
|
-
stop: () => {
|
|
1296
|
-
call?.tracer.trace('backgroundFilters.disable', null);
|
|
1297
|
-
processor?.stop();
|
|
1298
|
-
renderer?.dispose();
|
|
1299
|
-
if (videoRef.current)
|
|
1300
|
-
videoRef.current.srcObject = null;
|
|
1301
|
-
if (outputStream)
|
|
1302
|
-
videoClient.disposeOfMediaStream(outputStream);
|
|
1303
|
-
},
|
|
1304
|
-
};
|
|
1305
|
-
}, [
|
|
1306
|
-
backgroundBlurLevel,
|
|
1307
|
-
backgroundFilter,
|
|
1308
|
-
backgroundImage,
|
|
1309
|
-
call?.tracer,
|
|
1310
|
-
tfLite,
|
|
1311
|
-
engine,
|
|
1312
|
-
modelFilePath,
|
|
1313
|
-
basePath,
|
|
1314
|
-
]);
|
|
1315
|
-
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 &&
|
|
1316
|
-
'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, crossOrigin: "anonymous", src: backgroundImage, ...videoSize })), jsxRuntime.jsx("canvas", { className: "str-video__background-filters__target-canvas", ...videoSize, ref: canvasRef })] }));
|
|
1317
|
-
return { start, children };
|
|
982
|
+
const { SuspenseFallback = null, ...filterProps } = props;
|
|
983
|
+
return (jsxRuntime.jsx(react.Suspense, { fallback: SuspenseFallback, children: jsxRuntime.jsx(BackgroundFiltersProviderImpl, { ...filterProps, ContextProvider: BackgroundFiltersContext }) }));
|
|
1318
984
|
};
|
|
1319
985
|
|
|
1320
986
|
const IconButton = react.forwardRef(function IconButton(props, ref) {
|
|
@@ -1786,7 +1452,7 @@ const SpeakerTest = (props) => {
|
|
|
1786
1452
|
const audioElementRef = react.useRef(null);
|
|
1787
1453
|
const [isPlaying, setIsPlaying] = react.useState(false);
|
|
1788
1454
|
const { t } = videoReactBindings.useI18n();
|
|
1789
|
-
const { audioUrl = `https://unpkg.com/${"@stream-io/video-react-sdk"}@${"1.28.
|
|
1455
|
+
const { audioUrl = `https://unpkg.com/${"@stream-io/video-react-sdk"}@${"1.28.2"}/assets/piano.mp3`, } = props;
|
|
1790
1456
|
// Update audio output device when selection changes
|
|
1791
1457
|
react.useEffect(() => {
|
|
1792
1458
|
const audio = audioElementRef.current;
|
|
@@ -3452,7 +3118,7 @@ const checkCanJoinEarly = (startsAt, joinAheadTimeSeconds) => {
|
|
|
3452
3118
|
return Date.now() >= +startsAt - (joinAheadTimeSeconds ?? 0) * 1000;
|
|
3453
3119
|
};
|
|
3454
3120
|
|
|
3455
|
-
const [major, minor, patch] = ("1.28.
|
|
3121
|
+
const [major, minor, patch] = ("1.28.2").split('.');
|
|
3456
3122
|
videoClient.setSdkInfo({
|
|
3457
3123
|
type: videoClient.SfuModels.SdkType.REACT,
|
|
3458
3124
|
major,
|