@stream-io/video-react-sdk 1.34.2 → 1.35.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 +13 -0
- package/dist/css/embedded.css +54 -0
- package/dist/css/embedded.css.map +1 -1
- package/dist/css/styles.css +54 -0
- package/dist/css/styles.css.map +1 -1
- package/dist/embedded.cjs.js +90 -3
- package/dist/embedded.cjs.js.map +1 -1
- package/dist/embedded.es.js +90 -3
- package/dist/embedded.es.js.map +1 -1
- package/dist/index.cjs.js +91 -4
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +91 -4
- package/dist/index.es.js.map +1 -1
- package/dist/src/components/DeviceSettings/DeviceAudioPreviewItem.d.ts +6 -0
- package/dist/src/components/DeviceSettings/DeviceSelector.d.ts +11 -2
- package/dist/src/components/DeviceSettings/DeviceSelectorAudio.d.ts +1 -1
- package/dist/src/components/DeviceSettings/DeviceSelectorVideo.d.ts +1 -1
- package/dist/src/components/DeviceSettings/DeviceVideoPreviewItem.d.ts +6 -0
- package/package.json +5 -5
- package/src/components/DeviceSettings/DeviceAudioPreviewItem.tsx +83 -0
- package/src/components/DeviceSettings/DeviceSelector.tsx +70 -5
- package/src/components/DeviceSettings/DeviceSelectorAudio.tsx +3 -1
- package/src/components/DeviceSettings/DeviceSelectorVideo.tsx +5 -2
- package/src/components/DeviceSettings/DeviceVideoPreviewItem.tsx +73 -0
package/dist/embedded.es.js
CHANGED
|
@@ -1034,6 +1034,41 @@ const AudioVolumeIndicator = () => {
|
|
|
1034
1034
|
return (jsxs("div", { className: "str-video__audio-volume-indicator", children: [jsx(Icon, { icon: isEnabled ? 'mic' : 'mic-off' }), jsx("div", { className: "str-video__audio-volume-indicator__bar", children: jsx("div", { className: "str-video__audio-volume-indicator__bar-value", style: { transform: `scaleX(${audioLevel / 100})` } }) })] }));
|
|
1035
1035
|
};
|
|
1036
1036
|
|
|
1037
|
+
const LEVEL_BARS = 5;
|
|
1038
|
+
const DeviceLevelIndicator = ({ deviceId }) => {
|
|
1039
|
+
const [audioLevel, setAudioLevel] = useState(0);
|
|
1040
|
+
useEffect(() => {
|
|
1041
|
+
let cancelled = false;
|
|
1042
|
+
let dispose;
|
|
1043
|
+
navigator.mediaDevices
|
|
1044
|
+
.getUserMedia({
|
|
1045
|
+
audio: { deviceId: { exact: deviceId } },
|
|
1046
|
+
video: false,
|
|
1047
|
+
})
|
|
1048
|
+
.then((mediaStream) => {
|
|
1049
|
+
if (cancelled) {
|
|
1050
|
+
mediaStream.getTracks().forEach((t) => t.stop());
|
|
1051
|
+
return;
|
|
1052
|
+
}
|
|
1053
|
+
dispose = createSoundDetector(mediaStream, ({ audioLevel: al }) => setAudioLevel(al), { detectionFrequencyInMs: 80 });
|
|
1054
|
+
})
|
|
1055
|
+
.catch(console.error);
|
|
1056
|
+
return () => {
|
|
1057
|
+
cancelled = true;
|
|
1058
|
+
dispose?.().catch(console.error);
|
|
1059
|
+
};
|
|
1060
|
+
}, [deviceId]);
|
|
1061
|
+
const activeBars = Math.round((audioLevel / 100) * LEVEL_BARS);
|
|
1062
|
+
return (jsx("div", { className: "str-video__device-level-indicator", "aria-label": "Audio level", children: Array.from({ length: LEVEL_BARS }, (_, i) => (jsx("div", { className: clsx('str-video__device-level-indicator__bar', {
|
|
1063
|
+
'str-video__device-level-indicator__bar--active': i < activeBars,
|
|
1064
|
+
}) }, i))) }));
|
|
1065
|
+
};
|
|
1066
|
+
const DeviceAudioPreviewItem = ({ device, onSelect, }) => {
|
|
1067
|
+
if (device.deviceId === 'default')
|
|
1068
|
+
return null;
|
|
1069
|
+
return (jsxs("label", { className: `str-video__device-settings__option${device.isSelected ? ' str-video__device-settings__option--selected' : ''}`, htmlFor: `audioinput--${device.deviceId}`, children: [jsx("input", { type: "radio", name: "audioinput", value: device.deviceId, id: `audioinput--${device.deviceId}`, checked: device.isSelected, onChange: (e) => onSelect(e.target.value) }), device.label, jsx(DeviceLevelIndicator, { deviceId: device.deviceId })] }));
|
|
1070
|
+
};
|
|
1071
|
+
|
|
1037
1072
|
const SelectContext = createContext({});
|
|
1038
1073
|
const Select = (props) => {
|
|
1039
1074
|
const { children, icon, defaultSelectedLabel, defaultSelectedIndex, handleSelect: handleSelectProp, } = props;
|
|
@@ -1125,6 +1160,18 @@ const DeviceSelectorList = (props) => {
|
|
|
1125
1160
|
}, name: type, selected: device.isSelected }, device.deviceId));
|
|
1126
1161
|
}), children] }));
|
|
1127
1162
|
};
|
|
1163
|
+
const DeviceSelectorPreview = (props) => {
|
|
1164
|
+
const { devices = [], selectedDeviceId, title, onChange, children, PreviewItem, } = props;
|
|
1165
|
+
const { close } = useMenuContext();
|
|
1166
|
+
const { deviceList } = useDeviceList(devices, selectedDeviceId);
|
|
1167
|
+
const onSelect = useCallback((deviceId) => {
|
|
1168
|
+
if (deviceId === 'default')
|
|
1169
|
+
return;
|
|
1170
|
+
onChange?.(deviceId);
|
|
1171
|
+
close?.();
|
|
1172
|
+
}, [onChange, close]);
|
|
1173
|
+
return (jsxs("div", { className: "str-video__device-settings__device-kind", children: [title && (jsx("div", { className: "str-video__device-settings__device-selector-title", children: title })), deviceList.map((device) => (jsx(PreviewItem, { device: device, onSelect: onSelect }, device.deviceId))), children] }));
|
|
1174
|
+
};
|
|
1128
1175
|
const DeviceSelectorDropdown = (props) => {
|
|
1129
1176
|
const { devices = [], selectedDeviceId, title, onChange, icon } = props;
|
|
1130
1177
|
const { deviceList, selectedDeviceInfo, selectedIndex } = useDeviceList(devices, selectedDeviceId);
|
|
@@ -1137,6 +1184,10 @@ const DeviceSelectorDropdown = (props) => {
|
|
|
1137
1184
|
return (jsxs("div", { className: "str-video__device-settings__device-kind", children: [jsx("div", { className: "str-video__device-settings__device-selector-title", children: title }), jsx(DropDownSelect, { icon: icon, defaultSelectedIndex: selectedIndex, defaultSelectedLabel: selectedDeviceInfo.label, handleSelect: handleSelect, children: deviceList.map((device) => (jsx(DropDownSelectOption, { icon: icon, label: device.label, selected: device.isSelected }, device.deviceId))) })] }));
|
|
1138
1185
|
};
|
|
1139
1186
|
const DeviceSelector = (props) => {
|
|
1187
|
+
if (props.visualType === 'preview') {
|
|
1188
|
+
const { PreviewItem, ...rest } = props;
|
|
1189
|
+
return jsx(DeviceSelectorPreview, { ...rest, PreviewItem: PreviewItem });
|
|
1190
|
+
}
|
|
1140
1191
|
const { visualType = 'list', icon, ...rest } = props;
|
|
1141
1192
|
if (visualType === 'list') {
|
|
1142
1193
|
return jsx(DeviceSelectorList, { ...rest });
|
|
@@ -1154,7 +1205,7 @@ const SpeakerTest = (props) => {
|
|
|
1154
1205
|
const audioElementRef = useRef(null);
|
|
1155
1206
|
const [isPlaying, setIsPlaying] = useState(false);
|
|
1156
1207
|
const { t } = useI18n();
|
|
1157
|
-
const { audioUrl = `https://unpkg.com/${"@stream-io/video-react-sdk"}@${"1.
|
|
1208
|
+
const { audioUrl = `https://unpkg.com/${"@stream-io/video-react-sdk"}@${"1.35.0"}/assets/piano.mp3`, } = props;
|
|
1158
1209
|
// Update audio output device when selection changes
|
|
1159
1210
|
useEffect(() => {
|
|
1160
1211
|
const audio = audioElementRef.current;
|
|
@@ -1197,7 +1248,7 @@ const DeviceSelectorAudioInput = ({ title, visualType, volumeIndicatorVisible =
|
|
|
1197
1248
|
const { microphone, selectedDevice, devices } = useMicrophoneState();
|
|
1198
1249
|
return (jsx(DeviceSelector, { devices: devices || [], selectedDeviceId: selectedDevice, type: "audioinput", onChange: async (deviceId) => {
|
|
1199
1250
|
await microphone.select(deviceId);
|
|
1200
|
-
}, title: title, visualType: visualType, icon: "mic", children: volumeIndicatorVisible && (jsxs(Fragment, { children: [jsx("hr", { className: "str-video__device-settings__separator" }), jsx(AudioVolumeIndicator, {})] })) }));
|
|
1251
|
+
}, title: title, visualType: visualType, icon: "mic", PreviewItem: DeviceAudioPreviewItem, children: volumeIndicatorVisible && (jsxs(Fragment, { children: [jsx("hr", { className: "str-video__device-settings__separator" }), jsx(AudioVolumeIndicator, {})] })) }));
|
|
1201
1252
|
};
|
|
1202
1253
|
const DeviceSelectorAudioOutput = ({ title, visualType, speakerTestVisible = true, speakerTestAudioUrl, }) => {
|
|
1203
1254
|
const { useSpeakerState } = useCallStateHooks();
|
|
@@ -1209,12 +1260,48 @@ const DeviceSelectorAudioOutput = ({ title, visualType, speakerTestVisible = tru
|
|
|
1209
1260
|
}, title: title, visualType: visualType, icon: "speaker", children: speakerTestVisible && (jsxs(Fragment, { children: [jsx("hr", { className: "str-video__device-settings__separator" }), jsx(SpeakerTest, { audioUrl: speakerTestAudioUrl })] })) }));
|
|
1210
1261
|
};
|
|
1211
1262
|
|
|
1263
|
+
const DeviceVideoPreview = ({ deviceId }) => {
|
|
1264
|
+
const videoRef = useRef(null);
|
|
1265
|
+
useEffect(() => {
|
|
1266
|
+
let cancelled = false;
|
|
1267
|
+
let stream;
|
|
1268
|
+
navigator.mediaDevices
|
|
1269
|
+
.getUserMedia({
|
|
1270
|
+
video: { deviceId: { exact: deviceId } },
|
|
1271
|
+
audio: false,
|
|
1272
|
+
})
|
|
1273
|
+
.then((mediaStream) => {
|
|
1274
|
+
if (cancelled) {
|
|
1275
|
+
mediaStream.getTracks().forEach((t) => t.stop());
|
|
1276
|
+
return;
|
|
1277
|
+
}
|
|
1278
|
+
stream = mediaStream;
|
|
1279
|
+
if (videoRef.current) {
|
|
1280
|
+
videoRef.current.srcObject = mediaStream;
|
|
1281
|
+
}
|
|
1282
|
+
})
|
|
1283
|
+
.catch(console.error);
|
|
1284
|
+
return () => {
|
|
1285
|
+
cancelled = true;
|
|
1286
|
+
stream?.getTracks().forEach((t) => t.stop());
|
|
1287
|
+
};
|
|
1288
|
+
}, [deviceId]);
|
|
1289
|
+
return (jsx("div", { className: "str-video__device-video-preview", children: jsx("video", { ref: videoRef, autoPlay: true, playsInline: true, muted: true, className: "str-video__device-video-preview__video" }) }));
|
|
1290
|
+
};
|
|
1291
|
+
const DeviceVideoPreviewItem = ({ device, onSelect, }) => {
|
|
1292
|
+
if (device.deviceId === 'default')
|
|
1293
|
+
return null;
|
|
1294
|
+
return (jsxs("button", { type: "button", className: clsx('str-video__device-preview', {
|
|
1295
|
+
'str-video__device-preview--selected': device.isSelected,
|
|
1296
|
+
}), onClick: () => onSelect(device.deviceId), "aria-pressed": device.isSelected, children: [jsx(DeviceVideoPreview, { deviceId: device.deviceId }), jsx("span", { className: "str-video__device-preview__label", children: device.label })] }));
|
|
1297
|
+
};
|
|
1298
|
+
|
|
1212
1299
|
const DeviceSelectorVideo = ({ title, visualType, }) => {
|
|
1213
1300
|
const { useCameraState } = useCallStateHooks();
|
|
1214
1301
|
const { camera, devices, selectedDevice } = useCameraState();
|
|
1215
1302
|
return (jsx(DeviceSelector, { devices: devices || [], type: "videoinput", selectedDeviceId: selectedDevice, onChange: async (deviceId) => {
|
|
1216
1303
|
await camera.select(deviceId);
|
|
1217
|
-
}, title: title, visualType: visualType, icon: "camera" }));
|
|
1304
|
+
}, title: title, visualType: visualType, icon: "camera", PreviewItem: DeviceVideoPreviewItem }));
|
|
1218
1305
|
};
|
|
1219
1306
|
|
|
1220
1307
|
forwardRef(function ToggleDeviceSettingsMenuButton({ menuShown }, ref) {
|