@100mslive/roomkit-react 0.1.9 → 0.1.10
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/dist/{HLSView-VGJ2XUDT.js → HLSView-7WXNI2WP.js} +14 -10
- package/dist/HLSView-7WXNI2WP.js.map +7 -0
- package/dist/Modal/Dialog.d.ts +878 -9
- package/dist/Modal/DialogContent.d.ts +2 -2
- package/dist/Prebuilt/components/Leave/DesktopLeaveRoom.d.ts +4 -4
- package/dist/Prebuilt/components/Leave/EndSessionContent.d.ts +3 -3
- package/dist/Prebuilt/components/Leave/LeaveSessionContent.d.ts +3 -3
- package/dist/Prebuilt/components/Leave/MwebLeaveRoom.d.ts +4 -4
- package/dist/Prebuilt/components/VirtualBackground/VBCollection.d.ts +13 -0
- package/dist/Prebuilt/components/VirtualBackground/VBOption.d.ts +15 -0
- package/dist/Prebuilt/components/VirtualBackground/constants.d.ts +9 -0
- package/dist/Prebuilt/layouts/SidePane.d.ts +2 -2
- package/dist/{chunk-EDGWHFCM.js → chunk-N5HPVHTK.js} +6091 -4897
- package/dist/chunk-N5HPVHTK.js.map +7 -0
- package/dist/index.cjs.js +5217 -5060
- package/dist/index.cjs.js.map +4 -4
- package/dist/index.js +11 -13
- package/dist/meta.cjs.json +1567 -1385
- package/dist/meta.esbuild.json +1657 -1551
- package/package.json +6 -6
- package/src/Modal/Dialog.tsx +3 -11
- package/src/Modal/DialogContent.tsx +4 -4
- package/src/Prebuilt/common/constants.js +3 -0
- package/src/Prebuilt/components/AppData/AppData.jsx +4 -11
- package/src/Prebuilt/components/AppData/useSidepane.js +1 -1
- package/src/Prebuilt/components/Connection/ConnectionIndicator.tsx +2 -2
- package/src/Prebuilt/components/Footer/Footer.tsx +4 -8
- package/src/Prebuilt/components/Footer/ParticipantList.jsx +1 -6
- package/src/Prebuilt/components/Header/Header.tsx +2 -2
- package/src/Prebuilt/components/Header/common.jsx +46 -23
- package/src/Prebuilt/components/Leave/DesktopLeaveRoom.tsx +5 -5
- package/src/Prebuilt/components/Leave/EndSessionContent.tsx +2 -2
- package/src/Prebuilt/components/Leave/LeaveRoom.tsx +6 -5
- package/src/Prebuilt/components/Leave/LeaveSessionContent.tsx +2 -2
- package/src/Prebuilt/components/Leave/MwebLeaveRoom.tsx +3 -3
- package/src/Prebuilt/components/Notifications/HLSFailureModal.tsx +1 -4
- package/src/Prebuilt/components/Preview/PreviewForm.tsx +7 -2
- package/src/Prebuilt/components/Preview/PreviewJoin.tsx +62 -57
- package/src/Prebuilt/components/RoleChangeRequest/RequestPrompt.tsx +2 -3
- package/src/Prebuilt/components/Settings/DeviceSettings.jsx +11 -0
- package/src/Prebuilt/components/VirtualBackground/VBCollection.tsx +50 -0
- package/src/Prebuilt/components/VirtualBackground/VBOption.tsx +50 -0
- package/src/Prebuilt/components/VirtualBackground/VBPicker.jsx +165 -0
- package/src/Prebuilt/components/VirtualBackground/VBToggle.jsx +25 -0
- package/src/Prebuilt/components/VirtualBackground/constants.ts +26 -0
- package/src/Prebuilt/components/hooks/useAutoStartStreaming.tsx +4 -7
- package/src/Prebuilt/layouts/HLSView.jsx +7 -1
- package/src/Prebuilt/layouts/SidePane.tsx +21 -5
- package/dist/HLSView-VGJ2XUDT.js.map +0 -7
- package/dist/VirtualBackground-2VZVBRIC.js +0 -175
- package/dist/VirtualBackground-2VZVBRIC.js.map +0 -7
- package/dist/chunk-EDGWHFCM.js.map +0 -7
- package/dist/chunk-SONHO3VM.js +0 -962
- package/dist/chunk-SONHO3VM.js.map +0 -7
@@ -1,4 +1,4 @@
|
|
1
|
-
import React, { Fragment,
|
1
|
+
import React, { Fragment, useCallback, useEffect, useMemo, useState } from 'react';
|
2
2
|
import { useMeasure, useMedia } from 'react-use';
|
3
3
|
import {
|
4
4
|
HMSRoomState,
|
@@ -18,6 +18,7 @@ import { AudioLevel } from '../../../AudioLevel';
|
|
18
18
|
import { useHMSPrebuiltContext } from '../../AppContext';
|
19
19
|
// @ts-ignore: No implicit Any
|
20
20
|
import IconButton from '../../IconButton';
|
21
|
+
import SidePane from '../../layouts/SidePane';
|
21
22
|
import { useRoomLayout } from '../../provider/roomLayoutProvider';
|
22
23
|
// @ts-ignore: No implicit Any
|
23
24
|
import { AudioVideoToggle } from '../AudioVideoToggle';
|
@@ -32,6 +33,8 @@ import { Logo } from '../Header/HeaderComponents';
|
|
32
33
|
// @ts-ignore: No implicit Any
|
33
34
|
import SettingsModal from '../Settings/SettingsModal';
|
34
35
|
// @ts-ignore: No implicit Any
|
36
|
+
import { VBToggle } from '../VirtualBackground/VBToggle';
|
37
|
+
// @ts-ignore: No implicit Any
|
35
38
|
import PreviewForm from './PreviewForm';
|
36
39
|
// @ts-ignore: No implicit Any
|
37
40
|
import { useAuthToken, useUISettings } from '../AppData/useUISettings';
|
@@ -42,9 +45,6 @@ import { calculateAvatarAndAttribBoxSize, getFormattedCount } from '../../common
|
|
42
45
|
// @ts-ignore: No implicit Any
|
43
46
|
import { UI_SETTINGS } from '../../common/constants';
|
44
47
|
|
45
|
-
// @ts-ignore: No implicit Any
|
46
|
-
const VirtualBackground = React.lazy(() => import('../../plugins/VirtualBackground/VirtualBackground'));
|
47
|
-
|
48
48
|
const getParticipantChipContent = (peerCount = 0) => {
|
49
49
|
if (peerCount === 0) {
|
50
50
|
return 'You are the first to join';
|
@@ -133,60 +133,65 @@ const PreviewJoin = ({
|
|
133
133
|
}, [initialName]);
|
134
134
|
|
135
135
|
return roomState === HMSRoomState.Preview ? (
|
136
|
-
<
|
137
|
-
{
|
138
|
-
|
139
|
-
<
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
{
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
136
|
+
<Flex justify="center" css={{ size: '100%', position: 'relative' }}>
|
137
|
+
<Container css={{ h: '100%', pt: '$10', '@md': { justifyContent: 'space-between' } }}>
|
138
|
+
{toggleVideo ? null : <Box />}
|
139
|
+
<Flex direction="column" justify="center" css={{ w: '100%', maxWidth: '640px' }}>
|
140
|
+
<Logo />
|
141
|
+
<Text
|
142
|
+
variant="h4"
|
143
|
+
css={{ wordBreak: 'break-word', textAlign: 'center', mt: '$14', mb: '$4', '@md': { mt: '$8', mb: '$2' } }}
|
144
|
+
>
|
145
|
+
{previewHeader.title}
|
146
|
+
</Text>
|
147
|
+
<Text
|
148
|
+
css={{ c: '$on_surface_medium', my: '0', textAlign: 'center', maxWidth: '100%', wordWrap: 'break-word' }}
|
149
|
+
variant="sm"
|
150
|
+
>
|
151
|
+
{previewHeader.sub_title}
|
152
|
+
</Text>
|
153
|
+
<Flex justify="center" css={{ mt: '$14', '@md': { mt: '$8', mb: '0' }, gap: '$4' }}>
|
154
|
+
{isStreamingOn ? (
|
155
|
+
<Chip
|
156
|
+
content="LIVE"
|
157
|
+
backgroundColor="$alert_error_default"
|
158
|
+
textColor="#FFF"
|
159
|
+
icon={<Box css={{ h: '$sm', w: '$sm', backgroundColor: '$on_primary_high', borderRadius: '$round' }} />}
|
160
|
+
/>
|
161
|
+
) : null}
|
162
|
+
<Chip content={getParticipantChipContent(peerCount)} hideIfNoContent />
|
163
|
+
</Flex>
|
162
164
|
</Flex>
|
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
|
-
|
165
|
+
{toggleVideo ? (
|
166
|
+
<Flex
|
167
|
+
align="center"
|
168
|
+
justify="center"
|
169
|
+
css={{
|
170
|
+
mt: '$14',
|
171
|
+
'@md': { mt: 0 },
|
172
|
+
'@sm': { width: '100%' },
|
173
|
+
flexDirection: 'column',
|
174
|
+
}}
|
175
|
+
>
|
176
|
+
<PreviewTile name={name} error={previewError} />
|
177
|
+
</Flex>
|
178
|
+
) : null}
|
179
|
+
<Box css={{ w: '100%', maxWidth: `${Math.max(aspectRatio, 1) * 360}px` }}>
|
180
|
+
<PreviewControls hideSettings={!toggleVideo && !toggleAudio} />
|
181
|
+
<PreviewForm
|
182
|
+
name={name}
|
183
|
+
onChange={setName}
|
184
|
+
enableJoin={enableJoin}
|
185
|
+
onJoin={savePreferenceAndJoin}
|
186
|
+
cannotPublishVideo={!toggleVideo}
|
187
|
+
cannotPublishAudio={!toggleAudio}
|
188
|
+
/>
|
189
|
+
</Box>
|
190
|
+
</Container>
|
191
|
+
<Box css={{ position: 'absolute', right: '0', top: 0, height: '100%' }}>
|
192
|
+
<SidePane screenType="default" />
|
188
193
|
</Box>
|
189
|
-
</
|
194
|
+
</Flex>
|
190
195
|
) : (
|
191
196
|
<FullPageProgress />
|
192
197
|
);
|
@@ -274,7 +279,7 @@ export const PreviewControls = ({ hideSettings }: { hideSettings: boolean }) =>
|
|
274
279
|
>
|
275
280
|
<Flex css={{ gap: '$4' }}>
|
276
281
|
<AudioVideoToggle />
|
277
|
-
|
282
|
+
{!isMobile ? <VBToggle /> : null}
|
278
283
|
</Flex>
|
279
284
|
{!hideSettings ? <PreviewSettings /> : null}
|
280
285
|
</Flex>
|
@@ -33,10 +33,9 @@ export const RequestPrompt = ({
|
|
33
33
|
}
|
34
34
|
|
35
35
|
return (
|
36
|
-
<Dialog.Root open={open} onOpenChange={onOpenChange}>
|
36
|
+
<Dialog.Root open={open} modal={false} onOpenChange={onOpenChange}>
|
37
37
|
<Dialog.Portal>
|
38
|
-
<Dialog.
|
39
|
-
<Dialog.Content css={{ p: '$10' }}>
|
38
|
+
<Dialog.Content css={{ p: '$10' }} onInteractOutside={e => e.preventDefault()}>
|
40
39
|
<Dialog.Title css={{ p: 0, display: 'flex', flexDirection: 'row', gap: '$md', justifyContent: 'center' }}>
|
41
40
|
<Text variant="h6">{title}</Text>
|
42
41
|
</Dialog.Title>
|
@@ -1,14 +1,17 @@
|
|
1
1
|
import React, { Fragment, useEffect, useRef, useState } from 'react';
|
2
|
+
import { useMedia } from 'react-use';
|
2
3
|
import {
|
3
4
|
DeviceType,
|
4
5
|
selectIsLocalVideoEnabled,
|
5
6
|
selectLocalVideoTrackID,
|
6
7
|
selectVideoTrackByID,
|
7
8
|
useDevices,
|
9
|
+
useHMSActions,
|
8
10
|
useHMSStore,
|
9
11
|
} from '@100mslive/react-sdk';
|
10
12
|
import { MicOnIcon, SpeakerIcon, VideoOnIcon } from '@100mslive/react-icons';
|
11
13
|
import { Box, Button, Dropdown, Flex, StyledVideoTile, Text, Video } from '../../../';
|
14
|
+
import { config as cssConfig } from '../../../Theme';
|
12
15
|
import { DialogDropdownTrigger } from '../../primitives/DropdownTrigger';
|
13
16
|
import { useUISettings } from '../AppData/useUISettings';
|
14
17
|
import { useDropdownSelection } from '../hooks/useDropdownSelection';
|
@@ -30,7 +33,15 @@ const Settings = ({ setHide }) => {
|
|
30
33
|
const shouldShowAudioOutput = 'setSinkId' in HTMLMediaElement.prototype;
|
31
34
|
const mirrorLocalVideo = useUISettings(UI_SETTINGS.mirrorLocalVideo);
|
32
35
|
const trackSelector = selectVideoTrackByID(videoTrackId);
|
36
|
+
const hmsActions = useHMSActions();
|
33
37
|
const track = useHMSStore(trackSelector);
|
38
|
+
const isMobile = useMedia(cssConfig.media.md);
|
39
|
+
|
40
|
+
useEffect(() => {
|
41
|
+
if (isMobile) {
|
42
|
+
hmsActions.refreshDevices();
|
43
|
+
}
|
44
|
+
}, [hmsActions, isMobile]);
|
34
45
|
|
35
46
|
/**
|
36
47
|
* Chromium browsers return an audioOutput with empty label when no permissions are given
|
@@ -0,0 +1,50 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { Box } from '../../../Layout';
|
3
|
+
import { Text } from '../../../Text';
|
4
|
+
import { VBOption } from './VBOption';
|
5
|
+
import { VB_EFFECT } from './constants';
|
6
|
+
|
7
|
+
export const VBCollection = ({
|
8
|
+
options,
|
9
|
+
title,
|
10
|
+
activeBackgroundType = '',
|
11
|
+
activeBackground = '',
|
12
|
+
}: {
|
13
|
+
options: {
|
14
|
+
title?: string;
|
15
|
+
icon?: React.JSX.Element;
|
16
|
+
onClick?: () => Promise<void>;
|
17
|
+
mediaURL?: string;
|
18
|
+
type: string;
|
19
|
+
}[];
|
20
|
+
title: string;
|
21
|
+
activeBackground: HTMLImageElement | string;
|
22
|
+
activeBackgroundType: string;
|
23
|
+
}) => {
|
24
|
+
if (options.length === 0) {
|
25
|
+
return null;
|
26
|
+
}
|
27
|
+
return (
|
28
|
+
<Box css={{ mt: '$10' }}>
|
29
|
+
<Text variant="sm" css={{ color: '$on_surface_high', fontWeight: '$semiBold' }}>
|
30
|
+
{title}
|
31
|
+
</Text>
|
32
|
+
<Box css={{ py: '$4', display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: '$8' }}>
|
33
|
+
{options.map(option => (
|
34
|
+
<VBOption.Root
|
35
|
+
key={option?.mediaURL || option?.title}
|
36
|
+
{...option}
|
37
|
+
isActive={
|
38
|
+
([VB_EFFECT.NONE, VB_EFFECT.BLUR].includes(activeBackgroundType) &&
|
39
|
+
option.type === activeBackgroundType) ||
|
40
|
+
activeBackground === option?.mediaURL
|
41
|
+
}
|
42
|
+
>
|
43
|
+
<VBOption.Icon>{option?.icon}</VBOption.Icon>
|
44
|
+
<VBOption.Title>{option?.title}</VBOption.Title>
|
45
|
+
</VBOption.Root>
|
46
|
+
))}
|
47
|
+
</Box>
|
48
|
+
</Box>
|
49
|
+
);
|
50
|
+
};
|
@@ -0,0 +1,50 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { Box, Flex } from '../../../Layout';
|
3
|
+
import { Text } from '../../../Text';
|
4
|
+
|
5
|
+
const Root = ({
|
6
|
+
onClick,
|
7
|
+
mediaURL,
|
8
|
+
isActive,
|
9
|
+
children,
|
10
|
+
}: {
|
11
|
+
onClick?: () => Promise<void>;
|
12
|
+
mediaURL?: string;
|
13
|
+
isActive: boolean;
|
14
|
+
children?: React.JSX.Element[];
|
15
|
+
}) => (
|
16
|
+
<Flex
|
17
|
+
direction="column"
|
18
|
+
align="center"
|
19
|
+
css={{
|
20
|
+
p: '$5',
|
21
|
+
borderRadius: '$1',
|
22
|
+
bg: '$surface_bright',
|
23
|
+
border: `4px solid ${isActive ? '$primary_default' : '$surface_dim'}`,
|
24
|
+
cursor: 'pointer',
|
25
|
+
'&:hover': { border: '4px solid $primary_dim' },
|
26
|
+
...(mediaURL ? { height: '$20', backgroundImage: `url(${mediaURL})`, backgroundSize: 'cover' } : {}),
|
27
|
+
}}
|
28
|
+
onClick={async () => await onClick?.()}
|
29
|
+
>
|
30
|
+
{children}
|
31
|
+
</Flex>
|
32
|
+
);
|
33
|
+
|
34
|
+
const Title = ({ children }: { children?: string }) => {
|
35
|
+
return children ? (
|
36
|
+
<Text variant="xs" css={{ color: '$on_surface_medium' }}>
|
37
|
+
{children}
|
38
|
+
</Text>
|
39
|
+
) : null;
|
40
|
+
};
|
41
|
+
|
42
|
+
const Icon = ({ children }: { children?: React.JSX.Element }) => {
|
43
|
+
return children ? <Box css={{ color: '$on_surface_high' }}>{children}</Box> : null;
|
44
|
+
};
|
45
|
+
|
46
|
+
export const VBOption = {
|
47
|
+
Root,
|
48
|
+
Title,
|
49
|
+
Icon,
|
50
|
+
};
|
@@ -0,0 +1,165 @@
|
|
1
|
+
import React, { useEffect, useRef, useState } from 'react';
|
2
|
+
import {
|
3
|
+
HMSRoomState,
|
4
|
+
selectIsLargeRoom,
|
5
|
+
selectIsLocalVideoEnabled,
|
6
|
+
selectLocalPeer,
|
7
|
+
selectLocalPeerRole,
|
8
|
+
selectLocalVideoTrackID,
|
9
|
+
selectRoomState,
|
10
|
+
selectVideoTrackByID,
|
11
|
+
useHMSActions,
|
12
|
+
useHMSStore,
|
13
|
+
} from '@100mslive/react-sdk';
|
14
|
+
import { BlurPersonHighIcon, CloseIcon, CrossCircleIcon } from '@100mslive/react-icons';
|
15
|
+
import { Box, Flex, Video } from '../../../index';
|
16
|
+
import { Text } from '../../../Text';
|
17
|
+
import { VBCollection } from './VBCollection';
|
18
|
+
import { useSidepaneToggle } from '../AppData/useSidepane';
|
19
|
+
import { useUISettings } from '../AppData/useUISettings';
|
20
|
+
import { SIDE_PANE_OPTIONS, UI_SETTINGS } from '../../common/constants';
|
21
|
+
import { defaultMedia, VB_EFFECT, vbPlugin } from './constants';
|
22
|
+
|
23
|
+
const iconDims = { height: '40px', width: '40px' };
|
24
|
+
const MAX_RETRIES = 2;
|
25
|
+
|
26
|
+
export const VBPicker = () => {
|
27
|
+
const toggleVB = useSidepaneToggle(SIDE_PANE_OPTIONS.VB);
|
28
|
+
const hmsActions = useHMSActions();
|
29
|
+
const role = useHMSStore(selectLocalPeerRole);
|
30
|
+
const [isVBSupported, setIsVBSupported] = useState(false);
|
31
|
+
const localPeerVideoTrackID = useHMSStore(selectLocalVideoTrackID);
|
32
|
+
const localPeer = useHMSStore(selectLocalPeer);
|
33
|
+
const [background, setBackground] = useState(vbPlugin.background);
|
34
|
+
const [backgroundType, setBackgroundType] = useState(vbPlugin.backgroundType);
|
35
|
+
const isVideoOn = useHMSStore(selectIsLocalVideoEnabled);
|
36
|
+
const mirrorLocalVideo = useUISettings(UI_SETTINGS.mirrorLocalVideo);
|
37
|
+
const trackSelector = selectVideoTrackByID(localPeer?.videoTrack);
|
38
|
+
const track = useHMSStore(trackSelector);
|
39
|
+
const roomState = useHMSStore(selectRoomState);
|
40
|
+
const isLargeRoom = useHMSStore(selectIsLargeRoom);
|
41
|
+
const addedPluginToVideoTrack = useRef(false);
|
42
|
+
|
43
|
+
// Hidden in preview as the effect will be visible in the preview tile. Needed inside the room because the peer might not be on-screen
|
44
|
+
const showVideoTile = isVideoOn && isLargeRoom && roomState !== HMSRoomState.Preview;
|
45
|
+
|
46
|
+
const clearVBState = () => {
|
47
|
+
setBackground(VB_EFFECT.NONE);
|
48
|
+
setBackgroundType(VB_EFFECT.NONE);
|
49
|
+
};
|
50
|
+
|
51
|
+
useEffect(() => {
|
52
|
+
if (!localPeerVideoTrackID) {
|
53
|
+
return;
|
54
|
+
}
|
55
|
+
|
56
|
+
//check support of plugin
|
57
|
+
if (vbPlugin) {
|
58
|
+
const pluginSupport = hmsActions.validateVideoPluginSupport(vbPlugin);
|
59
|
+
setIsVBSupported(pluginSupport.isSupported);
|
60
|
+
}
|
61
|
+
}, [hmsActions, localPeerVideoTrackID]);
|
62
|
+
|
63
|
+
async function disableEffects() {
|
64
|
+
if (vbPlugin) {
|
65
|
+
vbPlugin.setBackground(VB_EFFECT.NONE, VB_EFFECT.NONE);
|
66
|
+
clearVBState();
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
async function addPlugin({ mediaURL = '', blurPower = 0 }) {
|
71
|
+
let retries = 0;
|
72
|
+
try {
|
73
|
+
if (mediaURL) {
|
74
|
+
const img = document.createElement('img');
|
75
|
+
img.alt = 'VB';
|
76
|
+
img.src = mediaURL;
|
77
|
+
try {
|
78
|
+
await vbPlugin.setBackground(img, VB_EFFECT.MEDIA);
|
79
|
+
} catch (e) {
|
80
|
+
console.error(e);
|
81
|
+
if (retries++ < MAX_RETRIES) {
|
82
|
+
await vbPlugin.setBackground(img, VB_EFFECT.MEDIA);
|
83
|
+
}
|
84
|
+
}
|
85
|
+
} else if (blurPower) {
|
86
|
+
await vbPlugin.setBackground(VB_EFFECT.BLUR, VB_EFFECT.BLUR);
|
87
|
+
}
|
88
|
+
setBackground(mediaURL || VB_EFFECT.BLUR);
|
89
|
+
setBackgroundType(mediaURL ? VB_EFFECT.MEDIA : VB_EFFECT.BLUR);
|
90
|
+
if (role && !addedPluginToVideoTrack.current) {
|
91
|
+
await hmsActions.addPluginToVideoTrack(vbPlugin, Math.floor(role.publishParams.video.frameRate / 2));
|
92
|
+
addedPluginToVideoTrack.current = true;
|
93
|
+
}
|
94
|
+
} catch (err) {
|
95
|
+
console.error('Failed to apply VB', err);
|
96
|
+
disableEffects();
|
97
|
+
}
|
98
|
+
}
|
99
|
+
|
100
|
+
useEffect(() => {
|
101
|
+
if (!isVideoOn) {
|
102
|
+
toggleVB();
|
103
|
+
}
|
104
|
+
}, [isVideoOn, toggleVB]);
|
105
|
+
|
106
|
+
if (!isVBSupported) {
|
107
|
+
return null;
|
108
|
+
}
|
109
|
+
|
110
|
+
return (
|
111
|
+
<Box css={{ maxHeight: '100%', overflowY: 'auto', pr: '$6' }}>
|
112
|
+
<Flex align="center" justify="between" css={{ w: '100%', position: 'sticky', top: 0 }}>
|
113
|
+
<Text variant="h6" css={{ color: '$on_surface_high' }}>
|
114
|
+
Virtual Background
|
115
|
+
</Text>
|
116
|
+
<Box
|
117
|
+
css={{ color: '$on_surface_high', '&:hover': { color: '$on_surface_medium' }, cursor: 'pointer' }}
|
118
|
+
onClick={toggleVB}
|
119
|
+
>
|
120
|
+
<CloseIcon />
|
121
|
+
</Box>
|
122
|
+
</Flex>
|
123
|
+
|
124
|
+
{showVideoTile ? (
|
125
|
+
<Video
|
126
|
+
mirror={track?.facingMode !== 'environment' && mirrorLocalVideo}
|
127
|
+
trackId={localPeer?.videoTrack}
|
128
|
+
data-testid="preview_tile"
|
129
|
+
css={{ width: '100%', height: '16rem', position: 'sticky', top: '$17' }}
|
130
|
+
/>
|
131
|
+
) : null}
|
132
|
+
|
133
|
+
<VBCollection
|
134
|
+
title="Effects"
|
135
|
+
options={[
|
136
|
+
{
|
137
|
+
title: 'No effect',
|
138
|
+
icon: <CrossCircleIcon style={iconDims} />,
|
139
|
+
type: VB_EFFECT.NONE,
|
140
|
+
onClick: async () => await disableEffects(),
|
141
|
+
},
|
142
|
+
{
|
143
|
+
title: 'Blur',
|
144
|
+
icon: <BlurPersonHighIcon style={iconDims} />,
|
145
|
+
type: VB_EFFECT.BLUR,
|
146
|
+
onClick: async () => await addPlugin({ blurPower: 0.5 }),
|
147
|
+
},
|
148
|
+
]}
|
149
|
+
activeBackgroundType={backgroundType || VB_EFFECT.NONE}
|
150
|
+
activeBackground={vbPlugin.background?.src || vbPlugin.background || VB_EFFECT.NONE}
|
151
|
+
/>
|
152
|
+
|
153
|
+
<VBCollection
|
154
|
+
title="Backgrounds"
|
155
|
+
options={defaultMedia.map(mediaURL => ({
|
156
|
+
type: VB_EFFECT.MEDIA,
|
157
|
+
mediaURL,
|
158
|
+
onClick: async () => await addPlugin({ mediaURL }),
|
159
|
+
}))}
|
160
|
+
activeBackgroundType={backgroundType || VB_EFFECT.NONE}
|
161
|
+
activeBackground={background?.src || background || VB_EFFECT.NONE}
|
162
|
+
/>
|
163
|
+
</Box>
|
164
|
+
);
|
165
|
+
};
|
@@ -0,0 +1,25 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { selectIsLocalVideoEnabled, useHMSStore } from '@100mslive/react-sdk';
|
3
|
+
import { VirtualBackgroundIcon } from '@100mslive/react-icons';
|
4
|
+
import { Tooltip } from '../../../Tooltip';
|
5
|
+
import IconButton from '../../IconButton';
|
6
|
+
import { useIsSidepaneTypeOpen, useSidepaneToggle } from '../AppData/useSidepane';
|
7
|
+
import { isSafari, SIDE_PANE_OPTIONS } from '../../common/constants';
|
8
|
+
|
9
|
+
export const VBToggle = () => {
|
10
|
+
const toggleVB = useSidepaneToggle(SIDE_PANE_OPTIONS.VB);
|
11
|
+
const isVBOpen = useIsSidepaneTypeOpen(SIDE_PANE_OPTIONS.VB);
|
12
|
+
const isVideoOn = useHMSStore(selectIsLocalVideoEnabled);
|
13
|
+
|
14
|
+
if (!isVideoOn || isSafari) {
|
15
|
+
return null;
|
16
|
+
}
|
17
|
+
|
18
|
+
return (
|
19
|
+
<Tooltip side="top" disabled={isVBOpen} title="Configure Virtual Background">
|
20
|
+
<IconButton active={!isVBOpen} onClick={toggleVB}>
|
21
|
+
<VirtualBackgroundIcon />
|
22
|
+
</IconButton>
|
23
|
+
</Tooltip>
|
24
|
+
);
|
25
|
+
};
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import { HMSVBPlugin, HMSVirtualBackgroundTypes } from '@100mslive/hms-virtual-background';
|
2
|
+
|
3
|
+
// Will support all media, setting to image here to test with current plugin interface
|
4
|
+
export const VB_EFFECT = {
|
5
|
+
BLUR: 'blur',
|
6
|
+
BEAUTIFY: 'BEAUTIFY',
|
7
|
+
NONE: 'none',
|
8
|
+
MEDIA: 'image',
|
9
|
+
};
|
10
|
+
|
11
|
+
export const defaultMedia = [
|
12
|
+
'https://assets.100ms.live/webapp/vb-mini/vb-1.jpg',
|
13
|
+
'https://assets.100ms.live/webapp/vb-mini/vb-2.jpg',
|
14
|
+
'https://assets.100ms.live/webapp/vb-mini/vb-3.png',
|
15
|
+
'https://assets.100ms.live/webapp/vb-mini/vb-4.jpg',
|
16
|
+
'https://assets.100ms.live/webapp/vb-mini/vb-5.jpg',
|
17
|
+
'https://assets.100ms.live/webapp/vb-mini/vb-6.jpg',
|
18
|
+
'https://assets.100ms.live/webapp/vb-mini/vb-7.jpg',
|
19
|
+
'https://assets.100ms.live/webapp/vb-mini/vb-8.jpg',
|
20
|
+
'https://assets.100ms.live/webapp/vb-mini/vb-9.jpg',
|
21
|
+
'https://assets.100ms.live/webapp/vb-mini/vb-10.jpg',
|
22
|
+
'https://assets.100ms.live/webapp/vb-mini/vb-11.jpg',
|
23
|
+
'https://assets.100ms.live/webapp/vb-mini/vb-12.jpg',
|
24
|
+
];
|
25
|
+
|
26
|
+
export const vbPlugin = new HMSVBPlugin(HMSVirtualBackgroundTypes.NONE, HMSVirtualBackgroundTypes.NONE);
|
@@ -1,6 +1,5 @@
|
|
1
1
|
import { useCallback, useEffect, useRef } from 'react';
|
2
2
|
import {
|
3
|
-
HMSException,
|
4
3
|
selectIsConnectedToRoom,
|
5
4
|
selectPermissions,
|
6
5
|
useHMSActions,
|
@@ -20,7 +19,7 @@ export const useAutoStartStreaming = () => {
|
|
20
19
|
const showStreamingUI = useShowStreamingUI();
|
21
20
|
const hmsActions = useHMSActions();
|
22
21
|
const isConnected = useHMSStore(selectIsConnectedToRoom);
|
23
|
-
const { isHLSRunning, isRTMPRunning } = useRecordingStreaming();
|
22
|
+
const { isHLSRunning, isRTMPRunning, isRecordingOn } = useRecordingStreaming();
|
24
23
|
const streamStartedRef = useRef(false);
|
25
24
|
|
26
25
|
const startHLS = useCallback(async () => {
|
@@ -32,9 +31,7 @@ export const useAutoStartStreaming = () => {
|
|
32
31
|
streamStartedRef.current = true;
|
33
32
|
await hmsActions.startHLSStreaming();
|
34
33
|
} catch (error) {
|
35
|
-
|
36
|
-
return;
|
37
|
-
}
|
34
|
+
console.error(error);
|
38
35
|
streamStartedRef.current = false;
|
39
36
|
setHLSStarted(false);
|
40
37
|
}
|
@@ -47,10 +44,10 @@ export const useAutoStartStreaming = () => {
|
|
47
44
|
}, [isHLSStarted, isHLSRunning]);
|
48
45
|
|
49
46
|
useEffect(() => {
|
50
|
-
if (!isConnected || streamStartedRef.current || !permissions?.hlsStreaming) {
|
47
|
+
if (!isConnected || streamStartedRef.current || !permissions?.hlsStreaming || isRecordingOn) {
|
51
48
|
return;
|
52
49
|
}
|
53
|
-
// Is a streaming kit and
|
50
|
+
// Is a streaming kit and peer with streaming permissions joins
|
54
51
|
startHLS();
|
55
52
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
56
53
|
}, [isConnected]);
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
2
|
-
import { useFullscreen, useMedia, useToggle } from 'react-use';
|
2
|
+
import { useFullscreen, useMedia, usePrevious, useToggle } from 'react-use';
|
3
3
|
import { HLSPlaybackState, HMSHLSPlayer, HMSHLSPlayerEvents } from '@100mslive/hls-player';
|
4
4
|
import screenfull from 'screenfull';
|
5
5
|
import { selectAppData, selectHLSState, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
|
@@ -42,6 +42,7 @@ const HLSView = () => {
|
|
42
42
|
const controlsRef = useRef();
|
43
43
|
const controlsTimerRef = useRef();
|
44
44
|
const [qualityDropDownOpen, setQualityDropDownOpen] = useState(false);
|
45
|
+
const lastHlsUrl = usePrevious(hlsUrl);
|
45
46
|
|
46
47
|
const isMobile = useMedia(config.media.md);
|
47
48
|
const isFullScreen = useFullscreen(hlsViewRef, show, {
|
@@ -64,6 +65,11 @@ const HLSView = () => {
|
|
64
65
|
videoEl?.removeEventListener('waiting', showLoader);
|
65
66
|
};
|
66
67
|
}, []);
|
68
|
+
useEffect(() => {
|
69
|
+
if (streamEnded && lastHlsUrl !== hlsUrl) {
|
70
|
+
setStreamEnded(false);
|
71
|
+
}
|
72
|
+
}, [hlsUrl, streamEnded, lastHlsUrl]);
|
67
73
|
|
68
74
|
useEffect(() => {
|
69
75
|
const videoElem = videoRef.current;
|