@stream-io/video-react-sdk 1.17.1 → 1.18.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 +16 -0
- package/dist/css/styles.css +16 -0
- package/dist/css/styles.css.map +1 -1
- package/dist/index.cjs.js +255 -56
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +255 -57
- package/dist/index.es.js.map +1 -1
- package/dist/src/core/components/CallLayout/LivestreamLayout.d.ts +14 -0
- package/dist/src/hooks/useEffectEvent.d.ts +1 -0
- package/dist/src/translations/index.d.ts +4 -0
- package/dist/src/wrappers/LivestreamPlayer/LivestreamPlayer.d.ts +21 -1
- package/package.json +4 -4
- package/src/core/components/CallLayout/LivestreamLayout.tsx +48 -6
- package/src/hooks/useEffectEvent.ts +16 -0
- package/src/hooks/usePersistedDevicePreferences.ts +181 -72
- package/src/translations/en.json +4 -0
- package/src/wrappers/LivestreamPlayer/LivestreamPlayer.tsx +119 -8
package/dist/index.es.js
CHANGED
|
@@ -80,75 +80,189 @@ const defaultDevice = 'default';
|
|
|
80
80
|
* @param key the key to use for local storage.
|
|
81
81
|
*/
|
|
82
82
|
const usePersistedDevicePreferences = (key = '@stream-io/device-preferences') => {
|
|
83
|
-
const { useCallSettings,
|
|
83
|
+
const { useCallSettings, useCallCallingState, useMicrophoneState, useCameraState, useSpeakerState, } = useCallStateHooks();
|
|
84
84
|
const settings = useCallSettings();
|
|
85
|
-
usePersistedDevicePreference(key, 'camera', useCameraState(), settings ? !settings.video.camera_default_on : undefined);
|
|
86
|
-
usePersistedDevicePreference(key, 'microphone', useMicrophoneState(), settings ? !settings.audio.mic_default_on : undefined);
|
|
87
|
-
usePersistedDevicePreference(key, 'speaker', useSpeakerState(), false);
|
|
88
|
-
};
|
|
89
|
-
const usePersistedDevicePreference = (key, deviceKey, state, defaultMuted) => {
|
|
90
|
-
const { useCallCallingState } = useCallStateHooks();
|
|
91
85
|
const callingState = useCallCallingState();
|
|
86
|
+
const microphoneState = useMicrophoneState();
|
|
87
|
+
const cameraState = useCameraState();
|
|
88
|
+
const speakerState = useSpeakerState();
|
|
92
89
|
const [applyingState, setApplyingState] = useState('idle');
|
|
93
|
-
const manager = state[deviceKey];
|
|
94
90
|
useEffect(function apply() {
|
|
95
91
|
if (callingState === CallingState.LEFT ||
|
|
96
|
-
!
|
|
97
|
-
|
|
92
|
+
!microphoneState.devices.length ||
|
|
93
|
+
!cameraState.devices.length ||
|
|
94
|
+
!speakerState.devices ||
|
|
95
|
+
!settings ||
|
|
98
96
|
applyingState !== 'idle') {
|
|
99
97
|
return;
|
|
100
98
|
}
|
|
101
|
-
const preferences = parseLocalDevicePreferences(key);
|
|
102
|
-
const preference = preferences[deviceKey];
|
|
103
99
|
setApplyingState('applying');
|
|
104
|
-
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
100
|
+
(async () => {
|
|
101
|
+
for (const [deviceKey, state, defaultMuted] of [
|
|
102
|
+
['microphone', microphoneState, !settings.audio.mic_default_on],
|
|
103
|
+
['camera', cameraState, !settings.video.camera_default_on],
|
|
104
|
+
['speaker', speakerState, false],
|
|
105
|
+
]) {
|
|
106
|
+
const preferences = parseLocalDevicePreferences(key);
|
|
107
|
+
const preference = preferences[deviceKey];
|
|
108
|
+
const manager = state[deviceKey];
|
|
109
|
+
if (!manager.state.selectedDevice) {
|
|
110
|
+
const applyPromise = preference
|
|
111
|
+
? applyLocalDevicePreference(manager, [preference].flat(), state.devices)
|
|
112
|
+
: applyMutedState(manager, defaultMuted);
|
|
113
|
+
await applyPromise.catch((err) => {
|
|
114
|
+
console.warn(`Failed to apply ${deviceKey} device preferences`, err);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
})().finally(() => setApplyingState((state) => (state === 'applying' ? 'applied' : state)));
|
|
117
119
|
}, [
|
|
118
120
|
applyingState,
|
|
119
121
|
callingState,
|
|
120
|
-
|
|
121
|
-
|
|
122
|
+
cameraState,
|
|
123
|
+
cameraState.devices,
|
|
122
124
|
key,
|
|
123
|
-
|
|
124
|
-
|
|
125
|
+
microphoneState,
|
|
126
|
+
microphoneState.devices,
|
|
127
|
+
settings,
|
|
128
|
+
speakerState,
|
|
129
|
+
speakerState.devices,
|
|
125
130
|
]);
|
|
126
131
|
useEffect(function persist() {
|
|
127
|
-
if (callingState === CallingState.LEFT ||
|
|
128
|
-
!state.devices?.length ||
|
|
129
|
-
applyingState !== 'applied') {
|
|
132
|
+
if (callingState === CallingState.LEFT || applyingState !== 'applied') {
|
|
130
133
|
return;
|
|
131
134
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
135
|
+
for (const [deviceKey, devices, selectedDevice, isMute] of [
|
|
136
|
+
[
|
|
137
|
+
'camera',
|
|
138
|
+
cameraState.devices,
|
|
139
|
+
cameraState.selectedDevice,
|
|
140
|
+
cameraState.isMute,
|
|
141
|
+
],
|
|
142
|
+
[
|
|
143
|
+
'microphone',
|
|
144
|
+
microphoneState.devices,
|
|
145
|
+
microphoneState.selectedDevice,
|
|
146
|
+
microphoneState.isMute,
|
|
147
|
+
],
|
|
148
|
+
[
|
|
149
|
+
'speaker',
|
|
150
|
+
speakerState.devices,
|
|
151
|
+
speakerState.selectedDevice,
|
|
152
|
+
speakerState.isMute,
|
|
153
|
+
],
|
|
154
|
+
]) {
|
|
155
|
+
try {
|
|
156
|
+
patchLocalDevicePreference(key, deviceKey, {
|
|
157
|
+
devices,
|
|
158
|
+
selectedDevice,
|
|
159
|
+
isMute,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
catch (err) {
|
|
163
|
+
console.warn(`Failed to save ${deviceKey} device preferences`, err);
|
|
164
|
+
}
|
|
141
165
|
}
|
|
142
166
|
}, [
|
|
143
167
|
applyingState,
|
|
144
168
|
callingState,
|
|
145
|
-
|
|
169
|
+
cameraState.devices,
|
|
170
|
+
cameraState.isMute,
|
|
171
|
+
cameraState.selectedDevice,
|
|
146
172
|
key,
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
173
|
+
microphoneState.devices,
|
|
174
|
+
microphoneState.isMute,
|
|
175
|
+
microphoneState.selectedDevice,
|
|
176
|
+
speakerState.devices,
|
|
177
|
+
speakerState.isMute,
|
|
178
|
+
speakerState.selectedDevice,
|
|
150
179
|
]);
|
|
151
180
|
};
|
|
181
|
+
// const usePersistedDevicePreference = <K extends DeviceKey>(
|
|
182
|
+
// key: string,
|
|
183
|
+
// deviceKey: K,
|
|
184
|
+
// state: DeviceState<K>,
|
|
185
|
+
// defaultMuted?: boolean,
|
|
186
|
+
// ): void => {
|
|
187
|
+
// const { useCallCallingState } = useCallStateHooks();
|
|
188
|
+
// const callingState = useCallCallingState();
|
|
189
|
+
// const [applyingState, setApplyingState] = useState<
|
|
190
|
+
// 'idle' | 'applying' | 'applied'
|
|
191
|
+
// >('idle');
|
|
192
|
+
// const manager = state[deviceKey];
|
|
193
|
+
// useEffect(
|
|
194
|
+
// function apply() {
|
|
195
|
+
// if (
|
|
196
|
+
// callingState === CallingState.LEFT ||
|
|
197
|
+
// !state.devices?.length ||
|
|
198
|
+
// typeof defaultMuted !== 'boolean' ||
|
|
199
|
+
// applyingState !== 'idle'
|
|
200
|
+
// ) {
|
|
201
|
+
// return;
|
|
202
|
+
// }
|
|
203
|
+
// const preferences = parseLocalDevicePreferences(key);
|
|
204
|
+
// const preference = preferences[deviceKey];
|
|
205
|
+
// setApplyingState('applying');
|
|
206
|
+
// if (!manager.state.selectedDevice) {
|
|
207
|
+
// const applyPromise = preference
|
|
208
|
+
// ? applyLocalDevicePreference(
|
|
209
|
+
// manager,
|
|
210
|
+
// [preference].flat(),
|
|
211
|
+
// state.devices,
|
|
212
|
+
// )
|
|
213
|
+
// : applyMutedState(manager, defaultMuted);
|
|
214
|
+
// applyPromise
|
|
215
|
+
// .catch((err) => {
|
|
216
|
+
// console.warn(
|
|
217
|
+
// `Failed to apply ${deviceKey} device preferences`,
|
|
218
|
+
// err,
|
|
219
|
+
// );
|
|
220
|
+
// })
|
|
221
|
+
// .finally(() => setApplyingState('applied'));
|
|
222
|
+
// } else {
|
|
223
|
+
// setApplyingState('applied');
|
|
224
|
+
// }
|
|
225
|
+
// },
|
|
226
|
+
// [
|
|
227
|
+
// applyingState,
|
|
228
|
+
// callingState,
|
|
229
|
+
// defaultMuted,
|
|
230
|
+
// deviceKey,
|
|
231
|
+
// key,
|
|
232
|
+
// manager,
|
|
233
|
+
// state.devices,
|
|
234
|
+
// ],
|
|
235
|
+
// );
|
|
236
|
+
// useEffect(
|
|
237
|
+
// function persist() {
|
|
238
|
+
// if (
|
|
239
|
+
// callingState === CallingState.LEFT ||
|
|
240
|
+
// !state.devices?.length ||
|
|
241
|
+
// applyingState !== 'applied'
|
|
242
|
+
// ) {
|
|
243
|
+
// return;
|
|
244
|
+
// }
|
|
245
|
+
// try {
|
|
246
|
+
// patchLocalDevicePreference(key, deviceKey, {
|
|
247
|
+
// devices: state.devices,
|
|
248
|
+
// selectedDevice: state.selectedDevice,
|
|
249
|
+
// isMute: state.isMute,
|
|
250
|
+
// });
|
|
251
|
+
// } catch (err) {
|
|
252
|
+
// console.warn(`Failed to save ${deviceKey} device preferences`, err);
|
|
253
|
+
// }
|
|
254
|
+
// },
|
|
255
|
+
// [
|
|
256
|
+
// applyingState,
|
|
257
|
+
// callingState,
|
|
258
|
+
// deviceKey,
|
|
259
|
+
// key,
|
|
260
|
+
// state.devices,
|
|
261
|
+
// state.isMute,
|
|
262
|
+
// state.selectedDevice,
|
|
263
|
+
// ],
|
|
264
|
+
// );
|
|
265
|
+
// };
|
|
152
266
|
const parseLocalDevicePreferences = (key) => {
|
|
153
267
|
const preferencesStr = window.localStorage.getItem(key);
|
|
154
268
|
let preferences = {};
|
|
@@ -2228,6 +2342,10 @@ var en = {
|
|
|
2228
2342
|
Video: Video,
|
|
2229
2343
|
"You are muted. Unmute to speak.": "You are muted. Unmute to speak.",
|
|
2230
2344
|
Live: Live,
|
|
2345
|
+
"Livestream starts soon": "Livestream starts soon",
|
|
2346
|
+
"Livestream starts at {{ startsAt }}": "Livestream starts at {{ startsAt, datetime }}",
|
|
2347
|
+
"{{ count }} participants joined early_one": "{{ count }} participant joined early",
|
|
2348
|
+
"{{ count }} participants joined early_other": "{{ count }} participants joined early",
|
|
2231
2349
|
"You can now speak.": "You can now speak.",
|
|
2232
2350
|
"Awaiting for an approval to speak.": "Awaiting for an approval to speak.",
|
|
2233
2351
|
"You can no longer speak.": "You can no longer speak.",
|
|
@@ -2445,18 +2563,32 @@ const LivestreamLayout = (props) => {
|
|
|
2445
2563
|
? participants.find(hasScreenShare)
|
|
2446
2564
|
: undefined;
|
|
2447
2565
|
usePaginatedLayoutSortPreset(call);
|
|
2448
|
-
const
|
|
2566
|
+
const overlay = (jsx(ParticipantOverlay, { showParticipantCount: props.showParticipantCount, showDuration: props.showDuration, showLiveBadge: props.showLiveBadge, showSpeakerName: props.showSpeakerName }));
|
|
2449
2567
|
const { floatingParticipantProps, muted } = props;
|
|
2450
|
-
const
|
|
2568
|
+
const floatingParticipantOverlay = hasOngoingScreenShare && (jsx(ParticipantOverlay
|
|
2451
2569
|
// these elements aren't needed for the video feed
|
|
2452
2570
|
, {
|
|
2453
2571
|
// these elements aren't needed for the video feed
|
|
2454
2572
|
showParticipantCount: floatingParticipantProps?.showParticipantCount ?? false, showDuration: floatingParticipantProps?.showDuration ?? false, showLiveBadge: floatingParticipantProps?.showLiveBadge ?? false, showSpeakerName: floatingParticipantProps?.showSpeakerName ?? true }));
|
|
2455
|
-
return (jsxs("div", { className: "str-video__livestream-layout__wrapper", children: [!muted && jsx(ParticipantsAudio, { participants: remoteParticipants }), hasOngoingScreenShare && presenter && (jsx(ParticipantView, { className: "str-video__livestream-layout__screen-share", participant: presenter, ParticipantViewUI:
|
|
2573
|
+
return (jsxs("div", { className: "str-video__livestream-layout__wrapper", children: [!muted && jsx(ParticipantsAudio, { participants: remoteParticipants }), hasOngoingScreenShare && presenter && (jsx(ParticipantView, { className: "str-video__livestream-layout__screen-share", participant: presenter, ParticipantViewUI: overlay, trackType: "screenShareTrack", muteAudio // audio is rendered by ParticipantsAudio
|
|
2456
2574
|
: true })), currentSpeaker && (jsx(ParticipantView, { className: clsx(hasOngoingScreenShare &&
|
|
2457
|
-
clsx('str-video__livestream-layout__floating-participant', `str-video__livestream-layout__floating-participant--${floatingParticipantProps?.position ?? 'top-right'}`)), participant: currentSpeaker, ParticipantViewUI:
|
|
2575
|
+
clsx('str-video__livestream-layout__floating-participant', `str-video__livestream-layout__floating-participant--${floatingParticipantProps?.position ?? 'top-right'}`)), participant: currentSpeaker, ParticipantViewUI: floatingParticipantOverlay || overlay, mirror: props.mirrorLocalParticipantVideo !== false ? undefined : false, muteAudio // audio is rendered by ParticipantsAudio
|
|
2458
2576
|
: true }))] }));
|
|
2459
2577
|
};
|
|
2578
|
+
LivestreamLayout.displayName = 'LivestreamLayout';
|
|
2579
|
+
const BackstageLayout = (props) => {
|
|
2580
|
+
const { showEarlyParticipantCount = true } = props;
|
|
2581
|
+
const { useParticipantCount, useCallStartsAt } = useCallStateHooks();
|
|
2582
|
+
const participantCount = useParticipantCount();
|
|
2583
|
+
const startsAt = useCallStartsAt();
|
|
2584
|
+
const { t } = useI18n();
|
|
2585
|
+
return (jsx("div", { className: "str-video__livestream-layout__wrapper", children: jsxs("div", { className: "str-video__livestream-layout__backstage", children: [startsAt && (jsx("span", { className: "str-video__livestream-layout__starts-at", children: startsAt.getTime() < Date.now()
|
|
2586
|
+
? t('Livestream starts soon')
|
|
2587
|
+
: t('Livestream starts at {{ startsAt }}', { startsAt }) })), showEarlyParticipantCount && (jsx("span", { className: "str-video__livestream-layout__early-viewers-count", children: t('{{ count }} participants joined early', {
|
|
2588
|
+
count: participantCount,
|
|
2589
|
+
}) }))] }) }));
|
|
2590
|
+
};
|
|
2591
|
+
BackstageLayout.displayName = 'BackstageLayout';
|
|
2460
2592
|
const ParticipantOverlay = (props) => {
|
|
2461
2593
|
const { enableFullScreen = true, showParticipantCount = true, showDuration = true, showLiveBadge = true, showSpeakerName = false, } = props;
|
|
2462
2594
|
const { participant } = useParticipantViewContext();
|
|
@@ -2467,7 +2599,6 @@ const ParticipantOverlay = (props) => {
|
|
|
2467
2599
|
const { t } = useI18n();
|
|
2468
2600
|
return (jsx("div", { className: "str-video__livestream-layout__overlay", children: jsxs("div", { className: "str-video__livestream-layout__overlay__bar", children: [showLiveBadge && (jsx("span", { className: "str-video__livestream-layout__live-badge", children: t('Live') })), showParticipantCount && (jsx("span", { className: "str-video__livestream-layout__viewers-count", children: participantCount })), showSpeakerName && (jsx("span", { className: "str-video__livestream-layout__speaker-name", title: participant.name || participant.userId || '', children: participant.name || participant.userId || '' })), showDuration && (jsx("span", { className: "str-video__livestream-layout__duration", children: formatDuration(duration) })), enableFullScreen && (jsx("span", { className: "str-video__livestream-layout__go-fullscreen", onClick: toggleFullScreen }))] }) }));
|
|
2469
2601
|
};
|
|
2470
|
-
LivestreamLayout.displayName = 'LivestreamLayout';
|
|
2471
2602
|
const useUpdateCallDuration = () => {
|
|
2472
2603
|
const { useIsCallLive, useCallSession } = useCallStateHooks();
|
|
2473
2604
|
const isCallLive = useIsCallLive();
|
|
@@ -2709,17 +2840,30 @@ const Host = () => {
|
|
|
2709
2840
|
Host.displayName = 'PipLayout.Host';
|
|
2710
2841
|
const PipLayout = { Pip, Host };
|
|
2711
2842
|
|
|
2843
|
+
function useEffectEvent(cb) {
|
|
2844
|
+
const cbRef = useRef(undefined);
|
|
2845
|
+
useLayoutEffect(() => {
|
|
2846
|
+
cbRef.current = cb;
|
|
2847
|
+
}, [cb]);
|
|
2848
|
+
return useCallback((...args) => {
|
|
2849
|
+
const callback = cbRef.current;
|
|
2850
|
+
callback?.(...args);
|
|
2851
|
+
}, []);
|
|
2852
|
+
}
|
|
2853
|
+
|
|
2712
2854
|
const LivestreamPlayer = (props) => {
|
|
2713
|
-
const { callType, callId,
|
|
2855
|
+
const { callType, callId, ...restProps } = props;
|
|
2714
2856
|
const client = useStreamVideoClient();
|
|
2715
2857
|
const [call, setCall] = useState();
|
|
2858
|
+
const onError = useEffectEvent(props.onError);
|
|
2716
2859
|
useEffect(() => {
|
|
2717
2860
|
if (!client)
|
|
2718
2861
|
return;
|
|
2719
2862
|
const myCall = client.call(callType, callId);
|
|
2720
2863
|
setCall(myCall);
|
|
2721
|
-
myCall.
|
|
2722
|
-
console.error('Failed to
|
|
2864
|
+
myCall.get().catch((e) => {
|
|
2865
|
+
console.error('Failed to fetch call', e);
|
|
2866
|
+
onError(e);
|
|
2723
2867
|
});
|
|
2724
2868
|
return () => {
|
|
2725
2869
|
myCall.leave().catch((e) => {
|
|
@@ -2727,13 +2871,67 @@ const LivestreamPlayer = (props) => {
|
|
|
2727
2871
|
});
|
|
2728
2872
|
setCall(undefined);
|
|
2729
2873
|
};
|
|
2730
|
-
}, [callId, callType, client]);
|
|
2874
|
+
}, [callId, callType, client, onError]);
|
|
2875
|
+
if (!call) {
|
|
2876
|
+
return null;
|
|
2877
|
+
}
|
|
2878
|
+
return (jsx(StreamCall, { call: call, children: jsx(LivestreamCall, { ...restProps }) }));
|
|
2879
|
+
};
|
|
2880
|
+
const LivestreamCall = (props) => {
|
|
2881
|
+
const call = useLivestreamCall(props);
|
|
2882
|
+
const { useIsCallLive } = useCallStateHooks();
|
|
2883
|
+
const isLive = useIsCallLive();
|
|
2731
2884
|
if (!call)
|
|
2732
2885
|
return null;
|
|
2733
|
-
|
|
2886
|
+
if (isLive) {
|
|
2887
|
+
return jsx(LivestreamLayout, { ...props.layoutProps });
|
|
2888
|
+
}
|
|
2889
|
+
return jsx(BackstageLayout, { ...props.backstageProps });
|
|
2890
|
+
};
|
|
2891
|
+
const useLivestreamCall = (props) => {
|
|
2892
|
+
const call = useCall();
|
|
2893
|
+
const { useIsCallLive, useOwnCapabilities } = useCallStateHooks();
|
|
2894
|
+
const canJoinLive = useIsCallLive();
|
|
2895
|
+
const canJoinEarly = useCanJoinEearly();
|
|
2896
|
+
const canJoinBackstage = useOwnCapabilities()?.includes('join-backstage') ?? false;
|
|
2897
|
+
const canJoinAsap = canJoinLive || canJoinEarly || canJoinBackstage;
|
|
2898
|
+
const joinBehavior = props.joinBehavior ?? 'asap';
|
|
2899
|
+
const canJoin = (joinBehavior === 'asap' && canJoinAsap) ||
|
|
2900
|
+
(joinBehavior === 'live' && canJoinLive);
|
|
2901
|
+
const onError = useEffectEvent(props.onError);
|
|
2902
|
+
useEffect(() => {
|
|
2903
|
+
if (call && call.state.callingState === CallingState.IDLE && canJoin) {
|
|
2904
|
+
call.join().catch((e) => {
|
|
2905
|
+
console.error('Failed to join call', e);
|
|
2906
|
+
onError(e);
|
|
2907
|
+
});
|
|
2908
|
+
}
|
|
2909
|
+
}, [call, canJoin, onError]);
|
|
2910
|
+
return call;
|
|
2911
|
+
};
|
|
2912
|
+
const useCanJoinEearly = () => {
|
|
2913
|
+
const { useCallStartsAt, useCallSettings } = useCallStateHooks();
|
|
2914
|
+
const startsAt = useCallStartsAt();
|
|
2915
|
+
const settings = useCallSettings();
|
|
2916
|
+
const joinAheadTimeSeconds = settings?.backstage.join_ahead_time_seconds;
|
|
2917
|
+
const [canJoinEarly, setCanJoinEearly] = useState(() => checkCanJoinEarly(startsAt, joinAheadTimeSeconds));
|
|
2918
|
+
useEffect(() => {
|
|
2919
|
+
if (!canJoinEarly) {
|
|
2920
|
+
const handle = setInterval(() => {
|
|
2921
|
+
setCanJoinEearly(checkCanJoinEarly(startsAt, joinAheadTimeSeconds));
|
|
2922
|
+
}, 1000);
|
|
2923
|
+
return () => clearInterval(handle);
|
|
2924
|
+
}
|
|
2925
|
+
}, [canJoinEarly, startsAt, joinAheadTimeSeconds]);
|
|
2926
|
+
};
|
|
2927
|
+
const checkCanJoinEarly = (startsAt, joinAheadTimeSeconds) => {
|
|
2928
|
+
if (!startsAt) {
|
|
2929
|
+
return false;
|
|
2930
|
+
}
|
|
2931
|
+
return Date.now() >= +startsAt - (joinAheadTimeSeconds ?? 0) * 1000;
|
|
2734
2932
|
};
|
|
2735
2933
|
|
|
2736
|
-
const [major, minor, patch] = ("1.
|
|
2934
|
+
const [major, minor, patch] = ("1.18.0").split('.');
|
|
2737
2935
|
setSdkInfo({
|
|
2738
2936
|
type: SfuModels.SdkType.REACT,
|
|
2739
2937
|
major,
|
|
@@ -2741,5 +2939,5 @@ setSdkInfo({
|
|
|
2741
2939
|
patch,
|
|
2742
2940
|
});
|
|
2743
2941
|
|
|
2744
|
-
export { AcceptCallButton, Audio, Avatar, AvatarFallback, BackgroundFiltersProvider, BaseVideo, CallControls, CallParticipantListing, CallParticipantListingItem, CallParticipantsList, CallPreview, CallRecordingList, CallRecordingListHeader, CallRecordingListItem, CallStats, CallStatsButton, CancelCallButton, CancelCallConfirmButton, CompositeButton, DefaultParticipantViewUI, DefaultReactionsMenu, DefaultScreenShareOverlay, DefaultVideoPlaceholder, DeviceSelector, DeviceSelectorAudioInput, DeviceSelectorAudioOutput, DeviceSelectorVideo, DeviceSettings, DropDownSelect, DropDownSelectOption, EmptyCallRecordingListing, GenericMenu, GenericMenuButtonItem, Icon, IconButton, LivestreamLayout, LivestreamPlayer, LoadingCallRecordingListing, LoadingIndicator, MenuToggle, MenuVisualType, NoiseCancellationProvider, Notification, PaginatedGridLayout, ParticipantActionsContextMenu, ParticipantDetails, ParticipantView, ParticipantViewContext, ParticipantsAudio, PermissionNotification, PermissionRequestList, PermissionRequests, PipLayout, ReactionsButton, RecordCallButton, RecordCallConfirmationButton, RecordingInProgressNotification, RingingCall, RingingCallControls, ScreenShareButton, SearchInput, SearchResults, SpeakerLayout, SpeakingWhileMutedNotification, SpeechIndicator, StatCard, StreamCall, StreamTheme, StreamVideo, TextButton, ToggleAudioOutputButton, ToggleAudioPreviewButton, ToggleAudioPublishingButton, ToggleVideoPreviewButton, ToggleVideoPublishingButton, Tooltip, Video$1 as Video, VideoPreview, WithTooltip, defaultReactions, translations, useBackgroundFilters, useDeviceList, useFilteredParticipants, useHorizontalScrollPosition, useMenuContext, useNoiseCancellation, useParticipantViewContext, usePersistedDevicePreferences, useRequestPermission, useTrackElementVisibility, useVerticalScrollPosition };
|
|
2942
|
+
export { AcceptCallButton, Audio, Avatar, AvatarFallback, BackgroundFiltersProvider, BackstageLayout, BaseVideo, CallControls, CallParticipantListing, CallParticipantListingItem, CallParticipantsList, CallPreview, CallRecordingList, CallRecordingListHeader, CallRecordingListItem, CallStats, CallStatsButton, CancelCallButton, CancelCallConfirmButton, CompositeButton, DefaultParticipantViewUI, DefaultReactionsMenu, DefaultScreenShareOverlay, DefaultVideoPlaceholder, DeviceSelector, DeviceSelectorAudioInput, DeviceSelectorAudioOutput, DeviceSelectorVideo, DeviceSettings, DropDownSelect, DropDownSelectOption, EmptyCallRecordingListing, GenericMenu, GenericMenuButtonItem, Icon, IconButton, LivestreamLayout, LivestreamPlayer, LoadingCallRecordingListing, LoadingIndicator, MenuToggle, MenuVisualType, NoiseCancellationProvider, Notification, PaginatedGridLayout, ParticipantActionsContextMenu, ParticipantDetails, ParticipantView, ParticipantViewContext, ParticipantsAudio, PermissionNotification, PermissionRequestList, PermissionRequests, PipLayout, ReactionsButton, RecordCallButton, RecordCallConfirmationButton, RecordingInProgressNotification, RingingCall, RingingCallControls, ScreenShareButton, SearchInput, SearchResults, SpeakerLayout, SpeakingWhileMutedNotification, SpeechIndicator, StatCard, StreamCall, StreamTheme, StreamVideo, TextButton, ToggleAudioOutputButton, ToggleAudioPreviewButton, ToggleAudioPublishingButton, ToggleVideoPreviewButton, ToggleVideoPublishingButton, Tooltip, Video$1 as Video, VideoPreview, WithTooltip, defaultReactions, translations, useBackgroundFilters, useDeviceList, useFilteredParticipants, useHorizontalScrollPosition, useMenuContext, useNoiseCancellation, useParticipantViewContext, usePersistedDevicePreferences, useRequestPermission, useTrackElementVisibility, useVerticalScrollPosition };
|
|
2745
2943
|
//# sourceMappingURL=index.es.js.map
|