@100mslive/roomkit-react 0.3.13-alpha.1 → 0.3.13-alpha.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,6 +5,7 @@ import {
5
5
  HMSRoomState,
6
6
  selectIsLocalAudioPluginPresent,
7
7
  selectLocalAudioTrackID,
8
+ selectLocalPeer,
8
9
  selectLocalVideoTrackID,
9
10
  selectRoom,
10
11
  selectRoomState,
@@ -27,9 +28,12 @@ import {
27
28
  } from '@100mslive/react-icons';
28
29
  import { IconButtonWithOptions } from './IconButtonWithOptions/IconButtonWithOptions';
29
30
  // @ts-ignore: No implicit Any
31
+ import { ActionTile } from './MoreSettings/ActionTile';
32
+ // @ts-ignore: No implicit Any
30
33
  import SettingsModal from './Settings/SettingsModal';
31
34
  // @ts-ignore: No implicit Any
32
35
  import { ToastManager } from './Toast/ToastManager';
36
+ import { AudioLevel } from '../../AudioLevel';
33
37
  import { Dropdown } from '../../Dropdown';
34
38
  import { Box, Flex } from '../../Layout';
35
39
  import { Switch } from '../../Switch';
@@ -38,10 +42,11 @@ import { Tooltip } from '../../Tooltip';
38
42
  import IconButton from '../IconButton';
39
43
  import { useRoomLayoutConferencingScreen } from '../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
40
44
  // @ts-ignore: No implicit Any
41
- import { useIsNoiseCancellationEnabled, useSetNoiseCancellationEnabled } from './AppData/useUISettings';
45
+ import { useIsNoiseCancellationEnabled, useSetNoiseCancellation } from './AppData/useUISettings';
42
46
  import { useAudioOutputTest } from './hooks/useAudioOutputTest';
43
47
  import { isMacOS, TEST_AUDIO_URL } from '../common/constants';
44
48
 
49
+ const krispPlugin = new HMSKrispPlugin();
45
50
  // const optionsCSS = { fontWeight: '$semiBold', color: '$on_surface_high', w: '100%' };
46
51
 
47
52
  export const Options = ({
@@ -96,32 +101,82 @@ const OptionLabel = ({ children, icon }: { children: React.ReactNode; icon: Reac
96
101
  );
97
102
  };
98
103
 
99
- const plugin = new HMSKrispPlugin();
100
- const NoiseCancellation = () => {
101
- const localPeerAudioTrackID = useHMSStore(selectLocalAudioTrackID);
102
- const [enabled, setEnabled] = useSetNoiseCancellationEnabled();
103
- const isPluginAdded = useHMSStore(selectIsLocalAudioPluginPresent(plugin.getName()));
104
- const [inProgress, setInProgress] = useState(false);
104
+ const useNoiseCancellationWithPlugin = () => {
105
105
  const actions = useHMSActions();
106
- const room = useHMSStore(selectRoom);
106
+ const [inProgress, setInProgress] = useState(false);
107
+ const [, setNoiseCancellationEnabled] = useSetNoiseCancellation();
108
+ const setNoiseCancellationWithPlugin = async (enabled: boolean) => {
109
+ if (inProgress) {
110
+ return;
111
+ }
112
+ setInProgress(true);
113
+ if (enabled) {
114
+ await actions.addPluginToAudioTrack(krispPlugin);
115
+ } else {
116
+ await actions.removePluginFromAudioTrack(krispPlugin);
117
+ }
118
+ setNoiseCancellationEnabled(enabled);
119
+ setInProgress(false);
120
+ };
121
+ return {
122
+ setNoiseCancellationWithPlugin,
123
+ inProgress,
124
+ };
125
+ };
107
126
 
108
- useEffect(() => {
109
- (async () => {
110
- setInProgress(true);
111
- if (enabled && !isPluginAdded) {
112
- await actions.addPluginToAudioTrack(plugin);
113
- }
114
- if (!enabled && isPluginAdded) {
115
- await actions.removePluginFromAudioTrack(plugin);
116
- }
117
- setInProgress(false);
118
- })();
119
- }, [actions, enabled, isPluginAdded]);
127
+ export const NoiseCancellation = ({
128
+ actionTile,
129
+ iconOnly,
130
+ setOpenOptionsSheet,
131
+ }: {
132
+ setOpenOptionsSheet?: (value: boolean) => void;
133
+ iconOnly?: boolean;
134
+ actionTile?: boolean;
135
+ }) => {
136
+ const localPeerAudioTrackID = useHMSStore(selectLocalAudioTrackID);
137
+ const isNoiseCancellationEnabled = useIsNoiseCancellationEnabled();
138
+ const { setNoiseCancellationWithPlugin, inProgress } = useNoiseCancellationWithPlugin();
139
+ const room = useHMSStore(selectRoom);
140
+ const isKrispPluginAdded = useHMSStore(selectIsLocalAudioPluginPresent(krispPlugin.getName()));
120
141
 
121
- if (!plugin.isSupported() || !room.isNoiseCancellationEnabled || !localPeerAudioTrackID) {
142
+ if (!krispPlugin.isSupported() || !room.isNoiseCancellationEnabled || !localPeerAudioTrackID) {
122
143
  return null;
123
144
  }
124
145
 
146
+ if (actionTile) {
147
+ return (
148
+ <ActionTile.Root
149
+ active={isNoiseCancellationEnabled && isKrispPluginAdded}
150
+ disable={inProgress}
151
+ onClick={async () => {
152
+ await setNoiseCancellationWithPlugin(!isNoiseCancellationEnabled);
153
+ setOpenOptionsSheet?.(false);
154
+ }}
155
+ >
156
+ <AudioLevelIcon />
157
+ <ActionTile.Title>{isNoiseCancellationEnabled ? 'Noise Reduced' : 'Reduce Noise'}</ActionTile.Title>
158
+ </ActionTile.Root>
159
+ );
160
+ }
161
+
162
+ if (iconOnly) {
163
+ return (
164
+ <Tooltip title={isNoiseCancellationEnabled ? 'Noise Reduced' : 'Reduce Noise'}>
165
+ <IconButton
166
+ onClick={async () => {
167
+ await setNoiseCancellationWithPlugin(!isNoiseCancellationEnabled);
168
+ }}
169
+ disabled={inProgress}
170
+ css={{
171
+ bg: isNoiseCancellationEnabled && isKrispPluginAdded ? '$surface_brighter' : '$background_dim',
172
+ borderColor: isNoiseCancellationEnabled && isKrispPluginAdded ? '$border_brighter' : '$border_bright',
173
+ }}
174
+ >
175
+ <AudioLevelIcon />
176
+ </IconButton>
177
+ </Tooltip>
178
+ );
179
+ }
125
180
  return (
126
181
  <>
127
182
  <Dropdown.ItemSeparator css={{ mx: 0 }} />
@@ -132,9 +187,9 @@ const NoiseCancellation = () => {
132
187
  fontSize: '$xs',
133
188
  justifyContent: 'space-between',
134
189
  }}
135
- onClick={e => {
190
+ onClick={async e => {
136
191
  e.preventDefault();
137
- setEnabled(!enabled);
192
+ await setNoiseCancellationWithPlugin(!isNoiseCancellationEnabled);
138
193
  }}
139
194
  >
140
195
  <Text css={{ display: 'flex', alignItems: 'center', gap: '$2', fontSize: '$xs', '& svg': { size: '$8' } }}>
@@ -143,11 +198,11 @@ const NoiseCancellation = () => {
143
198
  </Text>
144
199
  <Switch
145
200
  id="noise_cancellation"
146
- checked={enabled && isPluginAdded}
201
+ checked={isNoiseCancellationEnabled && isKrispPluginAdded}
147
202
  disabled={inProgress}
148
203
  onClick={e => e.stopPropagation()}
149
- onCheckedChange={value => {
150
- setEnabled(value);
204
+ onCheckedChange={async value => {
205
+ await setNoiseCancellationWithPlugin(value);
151
206
  }}
152
207
  />
153
208
  </Dropdown.Item>
@@ -204,10 +259,10 @@ const AudioSettings = ({ onClick }: { onClick: () => void }) => {
204
259
  </>
205
260
  );
206
261
  };
207
-
208
- export const AudioVideoToggle = ({ hideOptions = false }) => {
262
+ export const AudioVideoToggle = ({ hideOptions = false }: { hideOptions?: boolean }) => {
209
263
  const { allDevices, selectedDeviceIDs, updateDevice } = useDevices();
210
264
  const { videoInput, audioInput, audioOutput } = allDevices;
265
+ const localPeer = useHMSStore(selectLocalPeer);
211
266
  const { isLocalVideoEnabled, isLocalAudioEnabled, toggleAudio, toggleVideo } = useAVToggle();
212
267
  const actions = useHMSActions();
213
268
  const videoTrackId = useHMSStore(selectLocalVideoTrackID);
@@ -218,15 +273,15 @@ export const AudioVideoToggle = ({ hideOptions = false }) => {
218
273
  const shouldShowAudioOutput = 'setSinkId' in HTMLMediaElement.prototype && Number(audioOutput?.length) > 0;
219
274
  const { screenType } = useRoomLayoutConferencingScreen();
220
275
  const [showSettings, setShowSettings] = useState(false);
221
- const isPluginAdded = useHMSStore(selectIsLocalAudioPluginPresent(plugin.getName()));
276
+ const isKrispPluginAdded = useHMSStore(selectIsLocalAudioPluginPresent(krispPlugin.getName()));
222
277
  const isNoiseCancellationEnabled = useIsNoiseCancellationEnabled();
278
+ const { setNoiseCancellationWithPlugin, inProgress } = useNoiseCancellationWithPlugin();
279
+ const showMuteIcon = !isLocalAudioEnabled || !toggleAudio;
223
280
 
224
281
  useEffect(() => {
225
282
  (async () => {
226
- if (isNoiseCancellationEnabled && !isPluginAdded) {
227
- await actions.addPluginToAudioTrack(plugin);
228
- }
229
- if (isNoiseCancellationEnabled && isPluginAdded) {
283
+ if (isNoiseCancellationEnabled && !isKrispPluginAdded && !inProgress && localPeer?.audioTrack) {
284
+ await setNoiseCancellationWithPlugin(true);
230
285
  ToastManager.addToast({
231
286
  title: `Noise Reduction Enabled`,
232
287
  variant: 'standard',
@@ -235,7 +290,8 @@ export const AudioVideoToggle = ({ hideOptions = false }) => {
235
290
  });
236
291
  }
237
292
  })();
238
- }, [actions, isNoiseCancellationEnabled, isPluginAdded]);
293
+ // eslint-disable-next-line react-hooks/exhaustive-deps
294
+ }, [isNoiseCancellationEnabled, localPeer?.audioTrack, inProgress]);
239
295
 
240
296
  if (!toggleAudio && !toggleVideo) {
241
297
  return null;
@@ -256,7 +312,10 @@ export const AudioVideoToggle = ({ hideOptions = false }) => {
256
312
  key="toggleAudio"
257
313
  >
258
314
  <Dropdown.Group>
259
- <OptionLabel icon={<MicOnIcon />}>{!shouldShowAudioOutput ? 'Audio' : 'Microphone'}</OptionLabel>
315
+ <OptionLabel icon={<MicOnIcon />}>
316
+ <Box css={{ flex: '1 1 0' }}>{!shouldShowAudioOutput ? 'Audio' : 'Microphone'}</Box>
317
+ {!showMuteIcon && <AudioLevel trackId={localPeer?.audioTrack} />}
318
+ </OptionLabel>
260
319
  <Options
261
320
  options={audioInput}
262
321
  selectedDeviceId={selectedDeviceIDs.audioInput}
@@ -18,7 +18,7 @@ export const CaptionIcon = () => {
18
18
  return null;
19
19
  }
20
20
  return (
21
- <Tooltip title={isCaption ? 'Disable caption' : 'Enable caption'}>
21
+ <Tooltip title={isCaption ? 'Hide closed captions' : 'Show closed captions'}>
22
22
  <IconButton data-testid="caption_btn" onClick={onClick}>
23
23
  {isCaption ? <ClosedCaptionIcon width="20" height="20px" /> : <OpenCaptionIcon width="20" height="20px" />}
24
24
  </IconButton>
@@ -35,6 +35,7 @@ import { Box, Loading, Tooltip } from '../../../..';
35
35
  import { Sheet } from '../../../../Sheet';
36
36
  // @ts-ignore: No implicit any
37
37
  import IconButton from '../../../IconButton';
38
+ import { NoiseCancellation } from '../../AudioVideoToggle';
38
39
  // @ts-ignore: No implicit any
39
40
  import { EmojiReaction } from '../../EmojiReaction';
40
41
  // @ts-ignore: No implicit any
@@ -54,8 +55,11 @@ import { useRoomLayoutHeader } from '../../../provider/roomLayoutProvider/hooks/
54
55
  import { useSheetToggle } from '../../AppData/useSheet';
55
56
  // @ts-ignore: No implicit any
56
57
  import { usePollViewToggle, useSidepaneToggle } from '../../AppData/useSidepane';
57
- // @ts-ignore: No implicit Any
58
- import { useSetIsCaptionEnabled, useShowPolls } from '../../AppData/useUISettings';
58
+ import {
59
+ useSetIsCaptionEnabled,
60
+ useShowPolls,
61
+ // @ts-ignore: No implicit Any
62
+ } from '../../AppData/useUISettings';
59
63
  // @ts-ignore: No implicit any
60
64
  import { useDropdownList } from '../../hooks/useDropdownList';
61
65
  import { useMyMetadata } from '../../hooks/useMetadata';
@@ -197,6 +201,7 @@ export const MwebOptions = ({
197
201
  <ActionTile.Title>{isHandRaised ? 'Lower' : 'Raise'} Hand</ActionTile.Title>
198
202
  </ActionTile.Root>
199
203
  ) : null}
204
+ <NoiseCancellation setOpenOptionsSheet={setOpenOptionsSheet} actionTile />
200
205
  {isTranscriptionAllowed ? (
201
206
  <ActionTile.Root
202
207
  onClick={() => {
@@ -19,7 +19,7 @@ import { AudioLevel } from '../../../AudioLevel';
19
19
  import { useHMSPrebuiltContext } from '../../AppContext';
20
20
  import IconButton from '../../IconButton';
21
21
  import SidePane from '../../layouts/SidePane';
22
- import { AudioVideoToggle } from '../AudioVideoToggle';
22
+ import { AudioVideoToggle, NoiseCancellation } from '../AudioVideoToggle';
23
23
  import Chip from '../Chip';
24
24
  import TileConnection from '../Connection/TileConnection';
25
25
  import FullPageProgress from '../FullPageProgress';
@@ -30,8 +30,11 @@ import SettingsModal from '../Settings/SettingsModal';
30
30
  import { VBToggle } from '../VirtualBackground/VBToggle';
31
31
  import PreviewForm from './PreviewForm';
32
32
  import { useRoomLayoutPreviewScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
33
- // @ts-ignore: No implicit Any
34
- import { useAuthToken, useUISettings } from '../AppData/useUISettings';
33
+ import {
34
+ useAuthToken,
35
+ useUISettings,
36
+ // @ts-ignore: No implicit Any
37
+ } from '../AppData/useUISettings';
35
38
  // @ts-ignore: No implicit Any
36
39
  import { defaultPreviewPreference, UserPreferencesKeys, useUserPreferences } from '../hooks/useUserPreferences';
37
40
  // @ts-ignore: No implicit Any
@@ -251,7 +254,6 @@ export const PreviewTile = ({ name, error }: { name: string; error?: boolean })
251
254
 
252
255
  export const PreviewControls = ({ hideSettings, vbEnabled }: { hideSettings: boolean; vbEnabled: boolean }) => {
253
256
  const isMobile = useMedia(cssConfig.media.md);
254
-
255
257
  return (
256
258
  <Flex
257
259
  justify={hideSettings && isMobile ? 'center' : 'between'}
@@ -264,7 +266,10 @@ export const PreviewControls = ({ hideSettings, vbEnabled }: { hideSettings: boo
264
266
  <AudioVideoToggle />
265
267
  {vbEnabled ? <VBToggle /> : null}
266
268
  </Flex>
267
- {!hideSettings ? <PreviewSettings /> : null}
269
+ <Flex align="center" gap="1">
270
+ {isMobile && <NoiseCancellation iconOnly />}
271
+ {!hideSettings ? <PreviewSettings /> : null}
272
+ </Flex>
268
273
  </Flex>
269
274
  );
270
275
  };
@@ -1,5 +1,6 @@
1
1
  import React, { Suspense, useEffect, useState } from 'react';
2
2
  import { ControlPosition } from 'react-draggable';
3
+ import { useMedia } from 'react-use';
3
4
  import {
4
5
  ConferencingScreen,
5
6
  DefaultConferencingScreen_Elements,
@@ -17,6 +18,7 @@ import { PeopleAddIcon, ShareScreenIcon } from '@100mslive/react-icons';
17
18
  import FullPageProgress from '../components/FullPageProgress';
18
19
  import { GridLayout } from '../components/VideoLayouts/GridLayout';
19
20
  import { Box, Flex } from '../../Layout';
21
+ import { config } from '../../Theme';
20
22
  // @ts-ignore: No implicit Any
21
23
  import { EmbedView } from './EmbedView';
22
24
  // @ts-ignore: No implicit Any
@@ -51,7 +53,8 @@ export const VideoStreamingSection = ({
51
53
  const pdfAnnotatorActive = usePDFConfig();
52
54
  const isMobileHLSStream = useMobileHLSStream();
53
55
  const isLandscapeHLSStream = useLandscapeHLSStream();
54
- const [captionPosition, setCaptionPosition] = useState<ControlPosition>({ x: -200, y: 0 });
56
+ const isMobile = useMedia(config.media.md);
57
+ const [captionPosition, setCaptionPosition] = useState<ControlPosition>({ x: isMobile ? 0 : -200, y: 0 });
55
58
  useCloseScreenshareWhiteboard();
56
59
 
57
60
  const { isNotAllowedToPublish, isScreenOnlyPublishParams, hasSubscribedRolePublishing } = useWaitingRoomInfo();