@100mslive/roomkit-react 0.2.6 → 0.2.7-alpha.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. package/README.md +30 -33
  2. package/dist/{HLSView-A5DVXKEU.js → HLSView-4B5MUDFR.js} +2 -2
  3. package/dist/Prebuilt/common/constants.d.ts +4 -3
  4. package/dist/Prebuilt/components/AudioVideoToggle.d.ts +9 -0
  5. package/dist/Prebuilt/components/IconButtonWithOptions/IconButtonWithOptions.d.ts +11 -0
  6. package/dist/Prebuilt/components/hooks/useAudioOutputTest.d.ts +8 -0
  7. package/dist/{chunk-KUVM2TEZ.js → chunk-KST24BRA.js} +4227 -3807
  8. package/dist/chunk-KST24BRA.js.map +7 -0
  9. package/dist/index.cjs.js +5518 -5092
  10. package/dist/index.cjs.js.map +4 -4
  11. package/dist/index.js +1 -1
  12. package/dist/meta.cjs.json +666 -597
  13. package/dist/meta.esbuild.json +673 -604
  14. package/package.json +7 -6
  15. package/src/Prebuilt/common/constants.ts +7 -4
  16. package/src/Prebuilt/components/AppData/useUISettings.js +1 -1
  17. package/src/Prebuilt/components/AudioVideoToggle.tsx +308 -0
  18. package/src/Prebuilt/components/Footer/RoleOptions.tsx +1 -0
  19. package/src/Prebuilt/components/IconButtonWithOptions/IconButtonWithOptions.tsx +159 -0
  20. package/src/Prebuilt/components/Leave/DesktopLeaveRoom.tsx +0 -2
  21. package/src/Prebuilt/components/Notifications/HandRaisedNotifications.tsx +13 -2
  22. package/src/Prebuilt/components/Notifications/Notifications.tsx +1 -18
  23. package/src/Prebuilt/components/Settings/DeviceSettings.jsx +10 -17
  24. package/src/Prebuilt/components/hooks/useAudioOutputTest.tsx +20 -0
  25. package/dist/chunk-KUVM2TEZ.js.map +0 -7
  26. package/src/Prebuilt/components/AudioVideoToggle.jsx +0 -171
  27. package/src/Prebuilt/components/IconButtonWithOptions/IconButtonWithOptions.jsx +0 -121
  28. /package/dist/{HLSView-A5DVXKEU.js.map → HLSView-4B5MUDFR.js.map} +0 -0
package/package.json CHANGED
@@ -10,7 +10,7 @@
10
10
  "prebuilt",
11
11
  "roomkit"
12
12
  ],
13
- "version": "0.2.6",
13
+ "version": "0.2.7-alpha.1",
14
14
  "author": "100ms",
15
15
  "license": "MIT",
16
16
  "repository": {
@@ -82,10 +82,11 @@
82
82
  "react": ">=17.0.2 <19.0.0"
83
83
  },
84
84
  "dependencies": {
85
- "@100mslive/hls-player": "0.2.6",
86
- "@100mslive/hms-virtual-background": "1.12.6",
87
- "@100mslive/react-icons": "0.9.6",
88
- "@100mslive/react-sdk": "0.9.6",
85
+ "@100mslive/hls-player": "0.2.7-alpha.1",
86
+ "@100mslive/hms-noise-cancellation": "0.0.0-alpha.1",
87
+ "@100mslive/hms-virtual-background": "1.12.7-alpha.1",
88
+ "@100mslive/react-icons": "0.9.7-alpha.1",
89
+ "@100mslive/react-sdk": "0.9.7-alpha.1",
89
90
  "@100mslive/types-prebuilt": "0.12.6",
90
91
  "@emoji-mart/data": "^1.0.6",
91
92
  "@emoji-mart/react": "^1.0.1",
@@ -120,5 +121,5 @@
120
121
  "uuid": "^8.3.2",
121
122
  "worker-timers": "^7.0.40"
122
123
  },
123
- "gitHead": "928f9172a44fe6c47232ab84d2c991b04cd9f707"
124
+ "gitHead": "d9ed012d59612c39bc68dc427b5749405e4eeb38"
124
125
  }
@@ -92,11 +92,12 @@ export const HLS_TIMED_METADATA_DOC_URL =
92
92
 
93
93
  export const REMOTE_STOP_SCREENSHARE_TYPE = 'REMOTE_STOP_SCREENSHARE';
94
94
 
95
- export const isChrome = parsedUserAgent.getBrowser()?.name?.toLowerCase() === 'chrome';
96
- export const isFirefox = parsedUserAgent.getBrowser()?.name?.toLowerCase() === 'firefox';
97
- export const isSafari = parsedUserAgent.getBrowser()?.name?.toLowerCase() === 'safari';
95
+ // mweb could have browser name as "Mobile Chrome" or "Mobile Firefox"
96
+ export const isChrome = parsedUserAgent.getBrowser()?.name?.toLowerCase().includes('chrome');
97
+ export const isFirefox = parsedUserAgent.getBrowser()?.name?.toLowerCase().includes('firefox');
98
+ export const isSafari = parsedUserAgent.getBrowser()?.name?.toLowerCase().includes('safari');
98
99
  export const isIOS = parsedUserAgent.getOS()?.name?.toLowerCase() === 'ios';
99
- export const isMacOS = parsedUserAgent.getOS()?.name?.toLowerCase() === 'mac os';
100
+ export const isMacOS = parsedUserAgent.getOS()?.name?.toLowerCase() === 'macos';
100
101
  export const isAndroid = parsedUserAgent.getOS()?.name?.toLowerCase() === 'android';
101
102
  export const isIPadOS = false;
102
103
  // typeof navigator !== "undefined" &&
@@ -136,3 +137,5 @@ export enum QUESTION_TYPE {
136
137
  export const ROLE_CHANGE_DECLINED = 'role_change_declined';
137
138
 
138
139
  export const DEFAULT_PORTAL_CONTAINER = '.prebuilt-container';
140
+
141
+ export const TEST_AUDIO_URL = 'https://100ms.live/test-audio.wav';
@@ -90,7 +90,7 @@ export const usePinnedTrack = () => {
90
90
 
91
91
  export const useSubscribedNotifications = notificationKey => {
92
92
  const notificationPreference = useHMSStore(selectAppDataByPath(APP_DATA.subscribedNotifications, notificationKey));
93
- return notificationPreference;
93
+ return notificationPreference || {};
94
94
  };
95
95
 
96
96
  export const useIsNotificationDisabled = () => {
@@ -0,0 +1,308 @@
1
+ import React, { Fragment, useEffect, useState } from 'react';
2
+ import { HMSKrispPlugin } from '@100mslive/hms-noise-cancellation';
3
+ import {
4
+ DeviceType,
5
+ HMSRoomState,
6
+ selectIsLocalAudioPluginPresent,
7
+ selectLocalAudioTrackID,
8
+ selectLocalVideoTrackID,
9
+ selectRoomState,
10
+ selectVideoTrackByID,
11
+ useAVToggle,
12
+ useDevices,
13
+ useHMSActions,
14
+ useHMSStore,
15
+ } from '@100mslive/react-sdk';
16
+ import {
17
+ AudioLevelIcon,
18
+ CameraFlipIcon,
19
+ CheckIcon,
20
+ MicOffIcon,
21
+ MicOnIcon,
22
+ SettingsIcon,
23
+ SpeakerIcon,
24
+ VideoOffIcon,
25
+ VideoOnIcon,
26
+ } from '@100mslive/react-icons';
27
+ import { IconButtonWithOptions } from './IconButtonWithOptions/IconButtonWithOptions';
28
+ // @ts-ignore: No implicit Any
29
+ import SettingsModal from './Settings/SettingsModal';
30
+ // @ts-ignore: No implicit Any
31
+ import { ToastManager } from './Toast/ToastManager';
32
+ import { Dropdown } from '../../Dropdown';
33
+ import { Box, Flex } from '../../Layout';
34
+ import { Switch } from '../../Switch';
35
+ import { Text } from '../../Text';
36
+ import { Tooltip } from '../../Tooltip';
37
+ import IconButton from '../IconButton';
38
+ import { useRoomLayoutConferencingScreen } from '../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
39
+ import { useAudioOutputTest } from './hooks/useAudioOutputTest';
40
+ import { isMacOS, TEST_AUDIO_URL } from '../common/constants';
41
+
42
+ // const optionsCSS = { fontWeight: '$semiBold', color: '$on_surface_high', w: '100%' };
43
+
44
+ export const Options = ({
45
+ options,
46
+ selectedDeviceId,
47
+ onClick,
48
+ }: {
49
+ options?: Array<MediaDeviceInfo | InputDeviceInfo>;
50
+ selectedDeviceId?: string;
51
+ onClick: (deviceId: string) => Promise<void>;
52
+ }) => {
53
+ return (
54
+ <>
55
+ {options?.map(option => (
56
+ <Dropdown.Item
57
+ key={option.label}
58
+ css={{
59
+ backgroundColor: selectedDeviceId === option.deviceId ? '$surface_bright' : '$surface_dim',
60
+ p: '$4 $8',
61
+ h: '$15',
62
+ fontSize: '$xs',
63
+ justifyContent: 'space-between',
64
+ }}
65
+ onClick={() => {
66
+ onClick(option.deviceId);
67
+ }}
68
+ >
69
+ {option.label}
70
+ {selectedDeviceId === option.deviceId ? <CheckIcon width={16} height={16} /> : null}
71
+ </Dropdown.Item>
72
+ ))}
73
+ </>
74
+ );
75
+ };
76
+
77
+ const OptionLabel = ({ children, icon }: { children: React.ReactNode; icon: React.ReactNode }) => {
78
+ return (
79
+ <Dropdown.Label
80
+ css={{
81
+ h: '$16',
82
+ p: '$4 $8',
83
+ color: '$on_surface_medium',
84
+ bg: 'transparent',
85
+ fontSize: '$xs',
86
+ gap: '$4',
87
+ alignItems: 'center',
88
+ }}
89
+ >
90
+ <Flex css={{ alignItems: 'center', justifyContent: 'center', '& svg': { size: '$8' } }}>{icon}</Flex> {children}
91
+ </Dropdown.Label>
92
+ );
93
+ };
94
+
95
+ const plugin = new HMSKrispPlugin();
96
+ const NoiseCancellation = () => {
97
+ const localPeerAudioTrackID = useHMSStore(selectLocalAudioTrackID);
98
+ const isPluginAdded = useHMSStore(selectIsLocalAudioPluginPresent(plugin.getName()));
99
+ const [active, setActive] = useState(isPluginAdded);
100
+ const [inProgress, setInProgress] = useState(false);
101
+ const actions = useHMSActions();
102
+
103
+ useEffect(() => {
104
+ (async () => {
105
+ setInProgress(true);
106
+ if (active && !isPluginAdded) {
107
+ await actions.addPluginToAudioTrack(plugin);
108
+ }
109
+ if (!active && isPluginAdded) {
110
+ await actions.removePluginFromAudioTrack(plugin);
111
+ }
112
+ setInProgress(false);
113
+ })();
114
+ }, [actions, active, isPluginAdded]);
115
+
116
+ if (!plugin.isSupported() || !localPeerAudioTrackID) {
117
+ return null;
118
+ }
119
+
120
+ return (
121
+ <Dropdown.Item
122
+ css={{
123
+ p: '$4 $8',
124
+ h: '$15',
125
+ fontSize: '$xs',
126
+ justifyContent: 'space-between',
127
+ }}
128
+ onClick={e => {
129
+ e.preventDefault();
130
+ setActive(value => !value);
131
+ }}
132
+ >
133
+ <Text css={{ display: 'flex', alignItems: 'center', gap: '$2', fontSize: '$xs', '& svg': { size: '$8' } }}>
134
+ <AudioLevelIcon />
135
+ Reduce Noise
136
+ </Text>
137
+ <Switch
138
+ id="noise_cancellation"
139
+ checked={active}
140
+ disabled={inProgress}
141
+ onClick={e => e.stopPropagation()}
142
+ onCheckedChange={value => {
143
+ setActive(value);
144
+ }}
145
+ />
146
+ </Dropdown.Item>
147
+ );
148
+ };
149
+
150
+ const AudioOutputLabel = ({ deviceId }: { deviceId: string }) => {
151
+ const { playing, setPlaying, audioRef } = useAudioOutputTest({ deviceId });
152
+ return (
153
+ <OptionLabel icon={<SpeakerIcon />}>
154
+ <Box css={{ flex: '1 1 0' }}>Speakers</Box>
155
+ <Text
156
+ variant="xs"
157
+ css={{ color: '$primary_bright', '&:hover': { cursor: 'pointer' } }}
158
+ onClick={async () => {
159
+ if (playing) {
160
+ return;
161
+ }
162
+ await audioRef.current?.play();
163
+ }}
164
+ >
165
+ <audio
166
+ ref={audioRef}
167
+ src={TEST_AUDIO_URL}
168
+ onEnded={() => setPlaying(false)}
169
+ onPlay={() => setPlaying(true)}
170
+ style={{ display: 'none' }}
171
+ />
172
+ {playing ? 'Playing Sound...' : 'Play Test Sound'}
173
+ </Text>
174
+ </OptionLabel>
175
+ );
176
+ };
177
+
178
+ const AudioSettings = ({ onClick }: { onClick: () => void }) => {
179
+ return (
180
+ <>
181
+ <Dropdown.Item
182
+ css={{
183
+ backgroundColor: '$surface_dim',
184
+ p: '$4 $8',
185
+ h: '$15',
186
+ alignItems: 'center',
187
+ gap: '$2',
188
+ fontSize: '$xs',
189
+ '& svg': { size: '$8' },
190
+ }}
191
+ onClick={onClick}
192
+ >
193
+ <SettingsIcon /> Audio Settings
194
+ </Dropdown.Item>
195
+ </>
196
+ );
197
+ };
198
+
199
+ export const AudioVideoToggle = ({ hideOptions = false }) => {
200
+ const { allDevices, selectedDeviceIDs, updateDevice } = useDevices();
201
+ const { videoInput, audioInput, audioOutput } = allDevices;
202
+ const { isLocalVideoEnabled, isLocalAudioEnabled, toggleAudio, toggleVideo } = useAVToggle();
203
+ const actions = useHMSActions();
204
+ const videoTrackId = useHMSStore(selectLocalVideoTrackID);
205
+ const localVideoTrack = useHMSStore(selectVideoTrackByID(videoTrackId));
206
+ const roomState = useHMSStore(selectRoomState);
207
+ const hasAudioDevices = Number(audioInput?.length) > 0;
208
+ const hasVideoDevices = Number(videoInput?.length) > 0;
209
+ const shouldShowAudioOutput = 'setSinkId' in HTMLMediaElement.prototype && Number(audioOutput?.length) > 0;
210
+ const { screenType } = useRoomLayoutConferencingScreen();
211
+ const [showSettings, setShowSettings] = useState(false);
212
+
213
+ if (!toggleAudio && !toggleVideo) {
214
+ return null;
215
+ }
216
+
217
+ return (
218
+ <Fragment>
219
+ {toggleAudio ? (
220
+ <IconButtonWithOptions
221
+ disabled={!toggleAudio}
222
+ hideOptions={hideOptions || !hasAudioDevices}
223
+ onDisabledClick={toggleAudio}
224
+ tooltipMessage={`Turn ${isLocalAudioEnabled ? 'off' : 'on'} audio (${isMacOS ? '⌘' : 'ctrl'} + d)`}
225
+ icon={
226
+ !isLocalAudioEnabled ? <MicOffIcon data-testid="audio_off_btn" /> : <MicOnIcon data-testid="audio_on_btn" />
227
+ }
228
+ active={isLocalAudioEnabled}
229
+ onClick={toggleAudio}
230
+ key="toggleAudio"
231
+ >
232
+ <Dropdown.Group>
233
+ <OptionLabel icon={<MicOnIcon />}>{!shouldShowAudioOutput ? 'Audio' : 'Microphone'}</OptionLabel>
234
+ <Options
235
+ options={audioInput}
236
+ selectedDeviceId={selectedDeviceIDs.audioInput}
237
+ onClick={deviceId => updateDevice({ deviceId, deviceType: DeviceType.audioInput })}
238
+ />
239
+ </Dropdown.Group>
240
+ <Dropdown.ItemSeparator css={{ mx: 0 }} />
241
+ {shouldShowAudioOutput && (
242
+ <>
243
+ <AudioOutputLabel deviceId={selectedDeviceIDs.audioOutput || ''} />
244
+ <Dropdown.Group>
245
+ <Options
246
+ options={audioOutput}
247
+ selectedDeviceId={selectedDeviceIDs.audioOutput}
248
+ onClick={deviceId => updateDevice({ deviceId, deviceType: DeviceType.audioOutput })}
249
+ />
250
+ </Dropdown.Group>
251
+ </>
252
+ )}
253
+ <Dropdown.ItemSeparator css={{ mx: 0 }} />
254
+ <NoiseCancellation />
255
+ <Dropdown.ItemSeparator css={{ mx: 0 }} />
256
+ <AudioSettings onClick={() => setShowSettings(true)} />
257
+ </IconButtonWithOptions>
258
+ ) : null}
259
+
260
+ {toggleVideo ? (
261
+ <IconButtonWithOptions
262
+ disabled={!toggleVideo}
263
+ hideOptions={hideOptions || !hasVideoDevices}
264
+ onDisabledClick={toggleVideo}
265
+ tooltipMessage={`Turn ${isLocalVideoEnabled ? 'off' : 'on'} video (${isMacOS ? '⌘' : 'ctrl'} + e)`}
266
+ icon={
267
+ !isLocalVideoEnabled ? (
268
+ <VideoOffIcon data-testid="video_off_btn" />
269
+ ) : (
270
+ <VideoOnIcon data-testid="video_on_btn" />
271
+ )
272
+ }
273
+ key="toggleVideo"
274
+ active={isLocalVideoEnabled}
275
+ onClick={toggleVideo}
276
+ >
277
+ <Options
278
+ options={videoInput}
279
+ selectedDeviceId={selectedDeviceIDs.videoInput}
280
+ onClick={deviceId => updateDevice({ deviceId, deviceType: DeviceType.videoInput })}
281
+ />
282
+ </IconButtonWithOptions>
283
+ ) : null}
284
+
285
+ {localVideoTrack?.facingMode && roomState === HMSRoomState.Preview ? (
286
+ <Tooltip title="Switch Camera" key="switchCamera">
287
+ <IconButton
288
+ onClick={async () => {
289
+ try {
290
+ await actions.switchCamera();
291
+ } catch (e) {
292
+ ToastManager.addToast({
293
+ title: `Error while flipping camera ${(e as Error).message || ''}`,
294
+ variant: 'error',
295
+ });
296
+ }
297
+ }}
298
+ >
299
+ <CameraFlipIcon />
300
+ </IconButton>
301
+ </Tooltip>
302
+ ) : null}
303
+ {showSettings && (
304
+ <SettingsModal open={showSettings} onOpenChange={() => setShowSettings(false)} screenType={screenType} />
305
+ )}
306
+ </Fragment>
307
+ );
308
+ };
@@ -80,6 +80,7 @@ export const RoleOptions = ({ roleName, peerList }: { roleName: string; peerList
80
80
  return (
81
81
  <Dropdown.Root open={openOptions} onOpenChange={setOpenOptions}>
82
82
  <Dropdown.Trigger
83
+ data-testid="role_group_options"
83
84
  onClick={e => e.stopPropagation()}
84
85
  className="role_actions"
85
86
  asChild
@@ -0,0 +1,159 @@
1
+ import React from 'react';
2
+ import { VerticalMenuIcon } from '@100mslive/react-icons';
3
+ import { Dropdown } from '../../../Dropdown';
4
+ import { Flex } from '../../../Layout';
5
+ import { styled } from '../../../Theme';
6
+ import { Tooltip } from '../../../Tooltip';
7
+ import IconButton from '../../IconButton';
8
+
9
+ const variants = {
10
+ disabled: {
11
+ true: {
12
+ bg: '$surface_brighter',
13
+ },
14
+ },
15
+ active: {
16
+ false: {
17
+ bg: '$secondary_dim',
18
+ },
19
+ },
20
+ };
21
+
22
+ const IconSection = styled(IconButton, {
23
+ w: 'unset',
24
+ h: '$14',
25
+ p: '$4',
26
+ r: '$1',
27
+ bg: '$transparent',
28
+ borderTopRightRadius: 0,
29
+ borderColor: '$border_bright',
30
+ borderBottomRightRadius: 0,
31
+ position: 'relative',
32
+ '&:not([disabled]):focus-visible': {
33
+ zIndex: 1,
34
+ },
35
+ '@md': {
36
+ mx: 0,
37
+ borderTopRightRadius: '$1',
38
+ borderBottomRightRadius: '$1',
39
+ },
40
+ variants: {
41
+ ...variants,
42
+ hideOptions: {
43
+ true: {
44
+ borderTopRightRadius: '$1',
45
+ borderBottomRightRadius: '$1',
46
+ },
47
+ },
48
+ },
49
+ });
50
+
51
+ const OptionsSection = styled(IconButton, {
52
+ w: 'unset',
53
+ h: '$14',
54
+ p: '$4 $2',
55
+ r: '$1',
56
+ borderTopLeftRadius: 0,
57
+ borderColor: '$border_bright',
58
+ borderBottomLeftRadius: 0,
59
+ borderLeftWidth: 0,
60
+ position: 'relative',
61
+ '&:not([disabled]):focus-visible': {
62
+ zIndex: 1,
63
+ },
64
+ '@md': {
65
+ display: 'none',
66
+ },
67
+ variants,
68
+ });
69
+
70
+ const Icon = styled(Flex, {
71
+ alignItems: 'center',
72
+ justifyContent: 'center',
73
+ color: '$on_primary_high',
74
+ variants: {
75
+ disabled: {
76
+ true: {
77
+ color: '$on_surface_low',
78
+ },
79
+ },
80
+ active: {
81
+ true: {
82
+ color: '$on_surface_high',
83
+ },
84
+ },
85
+ },
86
+ });
87
+
88
+ export const IconButtonWithOptions = ({
89
+ disabled = false,
90
+ onDisabledClick = () => {
91
+ return;
92
+ },
93
+ tooltipMessage = '',
94
+ icon,
95
+ children,
96
+ active,
97
+ hideOptions = false,
98
+ onClick = () => {
99
+ return;
100
+ },
101
+ }: {
102
+ onClick: () => void;
103
+ onDisabledClick: () => void;
104
+ icon: React.ReactNode;
105
+ children: React.ReactNode;
106
+ hideOptions?: boolean;
107
+ active: boolean;
108
+ disabled?: boolean;
109
+ tooltipMessage?: string;
110
+ }) => {
111
+ const commonProps = { disabled, active };
112
+ return (
113
+ <Flex>
114
+ <IconSection {...commonProps} onClick={onClick} hideOptions={hideOptions}>
115
+ <Tooltip disabled={!tooltipMessage} title={tooltipMessage}>
116
+ <Icon {...commonProps}>{icon}</Icon>
117
+ </Tooltip>
118
+ </IconSection>
119
+ {!hideOptions && children ? (
120
+ <Dropdown.Root>
121
+ <Dropdown.Trigger
122
+ asChild
123
+ // onClick does not work
124
+ onPointerDown={e => {
125
+ if (disabled) {
126
+ e.preventDefault();
127
+ onDisabledClick();
128
+ }
129
+ }}
130
+ >
131
+ <OptionsSection {...commonProps}>
132
+ <Tooltip title="View Options">
133
+ <Icon {...commonProps}>
134
+ <VerticalMenuIcon />
135
+ </Icon>
136
+ </Tooltip>
137
+ </OptionsSection>
138
+ </Dropdown.Trigger>
139
+ <Dropdown.Content
140
+ sideOffset={5}
141
+ alignOffset={-44}
142
+ align="start"
143
+ side="top"
144
+ css={{
145
+ w: 344,
146
+ maxWidth: '100%',
147
+ maxHeight: 'unset',
148
+ p: 0,
149
+ border: 'none',
150
+ bg: '$surface_dim',
151
+ }}
152
+ >
153
+ {children}
154
+ </Dropdown.Content>
155
+ </Dropdown.Root>
156
+ ) : null}
157
+ </Flex>
158
+ );
159
+ };
@@ -1,8 +1,6 @@
1
1
  import React, { Fragment, useState } from 'react';
2
2
  import { ConferencingScreen } from '@100mslive/types-prebuilt';
3
- // @ts-ignore: No implicit Any
4
3
  import { selectIsConnectedToRoom, selectPermissions, useHMSStore, useRecordingStreaming } from '@100mslive/react-sdk';
5
- // @ts-ignore: No implicit Any
6
4
  import { ExitIcon, StopIcon, VerticalMenuIcon } from '@100mslive/react-icons';
7
5
  import { Dropdown } from '../../../Dropdown';
8
6
  import { Box, Flex } from '../../../Layout';
@@ -11,25 +11,36 @@ import {
11
11
  // @ts-ignore: No implicit Any
12
12
  import { ToastBatcher } from '../Toast/ToastBatcher';
13
13
  import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
14
+ // @ts-ignore: No implicit Any
15
+ import { useSubscribedNotifications } from '../AppData/useUISettings';
14
16
 
15
17
  export const HandRaisedNotifications = () => {
16
18
  const notification = useHMSNotifications(HMSNotificationTypes.HAND_RAISE_CHANGED);
17
19
  const roomState = useHMSStore(selectRoomState);
18
20
  const vanillaStore = useHMSVanillaStore();
19
21
  const { on_stage_exp } = useRoomLayoutConferencingScreen().elements || {};
22
+ const subscribedNotifications = useSubscribedNotifications();
20
23
 
21
24
  useEffect(() => {
22
25
  if (!notification?.data) {
23
26
  return;
24
27
  }
25
- if (roomState !== HMSRoomState.Connected || notification.data.isLocal || !on_stage_exp) {
28
+
29
+ // Don't show toast message in case of local peer.
30
+ if (
31
+ roomState !== HMSRoomState.Connected ||
32
+ notification.data.isLocal ||
33
+ !on_stage_exp ||
34
+ !subscribedNotifications.METADATA_UPDATED
35
+ ) {
26
36
  return;
27
37
  }
28
38
  const hasPeerHandRaised = vanillaStore.getState(selectHasPeerHandRaised(notification.data.id));
29
39
  if (hasPeerHandRaised) {
30
40
  ToastBatcher.showToast({ notification, type: 'RAISE_HAND' });
41
+ console.debug('Metadata updated', notification.data);
31
42
  }
32
- }, [notification, on_stage_exp, roomState, vanillaStore]);
43
+ }, [notification, on_stage_exp, roomState, subscribedNotifications.METADATA_UPDATED, vanillaStore]);
33
44
 
34
45
  return null;
35
46
  };
@@ -16,8 +16,6 @@ import { GroupIcon } from '@100mslive/react-icons';
16
16
  import { Box, Button } from '../../..';
17
17
  import { useUpdateRoomLayout } from '../../provider/roomLayoutProvider';
18
18
  // @ts-ignore: No implicit Any
19
- import { ToastBatcher } from '../Toast/ToastBatcher';
20
- // @ts-ignore: No implicit Any
21
19
  import { ToastManager } from '../Toast/ToastManager';
22
20
  import { AutoplayBlockedModal } from './AutoplayBlockedModal';
23
21
  import { ChatNotifications } from './ChatNotifications';
@@ -34,8 +32,6 @@ import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvid
34
32
  import { usePollViewToggle } from '../AppData/useSidepane';
35
33
  // @ts-ignore: No implicit Any
36
34
  import { useIsNotificationDisabled, useSubscribedNotifications } from '../AppData/useUISettings';
37
- // @ts-ignore: No implicit Any
38
- import { getMetadata } from '../../common/utils';
39
35
  import { ROLE_CHANGE_DECLINED } from '../../common/constants';
40
36
 
41
37
  const pollToastKey: Record<string, string> = {};
@@ -43,7 +39,7 @@ const pollToastKey: Record<string, string> = {};
43
39
  export function Notifications() {
44
40
  const localPeerID = useHMSStore(selectLocalPeerID);
45
41
  const notification = useHMSNotifications();
46
- const subscribedNotifications = useSubscribedNotifications() || {};
42
+ const subscribedNotifications = useSubscribedNotifications();
47
43
  const roomState = useHMSStore(selectRoomState);
48
44
  const updateRoomLayoutForRole = useUpdateRoomLayout();
49
45
  const isNotificationDisabled = useIsNotificationDisabled();
@@ -65,19 +61,6 @@ export function Notifications() {
65
61
  return;
66
62
  }
67
63
  switch (notification.type) {
68
- case HMSNotificationTypes.METADATA_UPDATED:
69
- if (roomState !== HMSRoomState.Connected) {
70
- return;
71
- }
72
- // Don't show toast message when metadata is updated and raiseHand is false.
73
- // Don't show toast message in case of local peer.
74
- const metadata = getMetadata(notification.data?.metadata);
75
- if (!metadata?.isHandRaised || notification.data.isLocal) return;
76
-
77
- console.debug('Metadata updated', notification.data);
78
- if (!subscribedNotifications.METADATA_UPDATED) return;
79
- ToastBatcher.showToast({ notification, type: 'RAISE_HAND' });
80
- break;
81
64
  case HMSNotificationTypes.NAME_UPDATED:
82
65
  console.log(notification.data.id + ' changed their name to ' + notification.data.name);
83
66
  break;
@@ -14,9 +14,10 @@ import { Box, Button, Dropdown, Flex, StyledVideoTile, Text, Video } from '../..
14
14
  import { config as cssConfig } from '../../../Theme';
15
15
  import { DialogDropdownTrigger } from '../../primitives/DropdownTrigger';
16
16
  import { useUISettings } from '../AppData/useUISettings';
17
+ import { useAudioOutputTest } from '../hooks/useAudioOutputTest';
17
18
  import { useDropdownSelection } from '../hooks/useDropdownSelection';
18
19
  import { settingOverflow } from './common';
19
- import { UI_SETTINGS } from '../../common/constants';
20
+ import { TEST_AUDIO_URL, UI_SETTINGS } from '../../common/constants';
20
21
 
21
22
  /**
22
23
  * wrap the button on click of whom settings should open, this component will take care of the rest,
@@ -182,22 +183,8 @@ const DeviceSelector = ({ title, devices, selection, onChange, icon, children =
182
183
  );
183
184
  };
184
185
 
185
- const TEST_AUDIO_URL = 'https://100ms.live/test-audio.wav';
186
-
187
186
  const TestAudio = ({ id }) => {
188
- const audioRef = useRef(null);
189
- const [playing, setPlaying] = useState(false);
190
- useEffect(() => {
191
- if (audioRef.current && id) {
192
- try {
193
- if (typeof audioRef.current.setSinkId !== 'undefined') {
194
- audioRef.current.setSinkId(id);
195
- }
196
- } catch (error) {
197
- console.log(error);
198
- }
199
- }
200
- }, [id]);
187
+ const { playing, setPlaying, audioRef } = useAudioOutputTest({ deviceId: id });
201
188
  return (
202
189
  <>
203
190
  <Button
@@ -218,7 +205,13 @@ const TestAudio = ({ id }) => {
218
205
  &nbsp; speaker
219
206
  </Text>
220
207
  </Button>
221
- <audio ref={audioRef} src={TEST_AUDIO_URL} onEnded={() => setPlaying(false)} onPlay={() => setPlaying(true)} />
208
+ <audio
209
+ ref={audioRef}
210
+ src={TEST_AUDIO_URL}
211
+ onEnded={() => setPlaying(false)}
212
+ onPlay={() => setPlaying(true)}
213
+ css={{ display: 'none' }}
214
+ />
222
215
  </>
223
216
  );
224
217
  };