♻️(frontend) decouple audio/video controls for reorganization clarity
Temporary state separating audio and video controls to improve clarity and prepare for device selection/toggle component reorganization. Work in progress to better structure device-related components before implementing final unified control architecture.
This commit is contained in:
committed by
aleb_the_flash
parent
59e0643dde
commit
40cedba8ae
@@ -0,0 +1,124 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
useMediaDeviceSelect,
|
||||
useTrackToggle,
|
||||
UseTrackToggleProps,
|
||||
} from '@livekit/components-react'
|
||||
import { Button, Menu, MenuList } from '@/primitives'
|
||||
import { RiArrowUpSLine, RiMicLine, RiMicOffLine } from '@remixicon/react'
|
||||
import { LocalAudioTrack, LocalVideoTrack, Track } from 'livekit-client'
|
||||
|
||||
import { ToggleDevice } from '@/features/rooms/livekit/components/controls/ToggleDevice.tsx'
|
||||
import { css } from '@/styled-system/css'
|
||||
import { usePersistentUserChoices } from '../../../hooks/usePersistentUserChoices'
|
||||
import { useSnapshot } from 'valtio'
|
||||
import { permissionsStore } from '@/stores/permissions'
|
||||
import { ToggleDeviceConfig } from '../../../config/ToggleDeviceConfig'
|
||||
import Source = Track.Source
|
||||
import * as React from 'react'
|
||||
|
||||
type AudioDevicesControlProps = Omit<
|
||||
UseTrackToggleProps<Source.Microphone>,
|
||||
'source' | 'onChange'
|
||||
> & {
|
||||
track?: LocalAudioTrack | LocalVideoTrack
|
||||
hideMenu?: boolean
|
||||
}
|
||||
|
||||
export const AudioDevicesControl = ({
|
||||
track,
|
||||
hideMenu,
|
||||
...props
|
||||
}: AudioDevicesControlProps) => {
|
||||
const config: ToggleDeviceConfig = {
|
||||
kind: 'audioinput',
|
||||
iconOn: RiMicLine,
|
||||
iconOff: RiMicOffLine,
|
||||
shortcut: {
|
||||
key: 'd',
|
||||
ctrlKey: true,
|
||||
},
|
||||
longPress: {
|
||||
key: 'Space',
|
||||
},
|
||||
}
|
||||
const { t } = useTranslation('rooms', { keyPrefix: 'join' })
|
||||
|
||||
const { saveAudioInputDeviceId, saveAudioInputEnabled } =
|
||||
usePersistentUserChoices()
|
||||
|
||||
const onChange = React.useCallback(
|
||||
(enabled: boolean, isUserInitiated: boolean) =>
|
||||
isUserInitiated ? saveAudioInputEnabled(enabled) : null,
|
||||
[saveAudioInputEnabled]
|
||||
)
|
||||
|
||||
const trackProps = useTrackToggle({
|
||||
source: Source.Microphone,
|
||||
onChange,
|
||||
...props,
|
||||
})
|
||||
|
||||
const permissions = useSnapshot(permissionsStore)
|
||||
const isPermissionDeniedOrPrompted =
|
||||
permissions.isMicrophoneDenied || permissions.isMicrophonePrompted
|
||||
|
||||
const { devices, activeDeviceId, setActiveMediaDevice } =
|
||||
useMediaDeviceSelect({ kind: 'audioinput', track })
|
||||
|
||||
const selectLabel = t('audioinput.choose')
|
||||
|
||||
return (
|
||||
<div
|
||||
className={css({
|
||||
display: 'flex',
|
||||
gap: '1px',
|
||||
})}
|
||||
>
|
||||
<ToggleDevice
|
||||
{...trackProps}
|
||||
config={config}
|
||||
variant="primaryDark"
|
||||
toggle={trackProps.toggle}
|
||||
isPermissionDeniedOrPrompted={isPermissionDeniedOrPrompted}
|
||||
toggleButtonProps={{
|
||||
...(hideMenu
|
||||
? {
|
||||
groupPosition: undefined,
|
||||
}
|
||||
: {}),
|
||||
}}
|
||||
/>
|
||||
{!hideMenu && (
|
||||
<Menu variant="dark">
|
||||
<Button
|
||||
isDisabled={isPermissionDeniedOrPrompted}
|
||||
tooltip={selectLabel}
|
||||
aria-label={selectLabel}
|
||||
groupPosition="right"
|
||||
square
|
||||
variant={
|
||||
trackProps.enabled && !isPermissionDeniedOrPrompted
|
||||
? 'primaryDark'
|
||||
: 'error2'
|
||||
}
|
||||
>
|
||||
<RiArrowUpSLine />
|
||||
</Button>
|
||||
<MenuList
|
||||
items={devices.map((d) => ({
|
||||
value: d.deviceId,
|
||||
label: d.label,
|
||||
}))}
|
||||
selectedItem={activeDeviceId}
|
||||
onAction={(value) => {
|
||||
setActiveMediaDevice(value as string)
|
||||
saveAudioInputDeviceId(value as string)
|
||||
}}
|
||||
variant="dark"
|
||||
/>
|
||||
</Menu>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
useMediaDeviceSelect,
|
||||
useTrackToggle,
|
||||
UseTrackToggleProps,
|
||||
} from '@livekit/components-react'
|
||||
import { Button, Menu, MenuList } from '@/primitives'
|
||||
import { RiArrowUpSLine, RiVideoOffLine, RiVideoOnLine } from '@remixicon/react'
|
||||
import { LocalVideoTrack, Track, VideoCaptureOptions } from 'livekit-client'
|
||||
|
||||
import { ToggleDevice } from '@/features/rooms/livekit/components/controls/ToggleDevice'
|
||||
import { css } from '@/styled-system/css'
|
||||
import { usePersistentUserChoices } from '../../../hooks/usePersistentUserChoices'
|
||||
import { BackgroundProcessorFactory } from '../../blur'
|
||||
import { useSnapshot } from 'valtio'
|
||||
import { permissionsStore } from '@/stores/permissions'
|
||||
import { ToggleDeviceConfig } from '../../../config/ToggleDeviceConfig'
|
||||
import Source = Track.Source
|
||||
import * as React from 'react'
|
||||
|
||||
type VideoDeviceControlProps = Omit<
|
||||
UseTrackToggleProps<Source.Camera>,
|
||||
'source' | 'onChange'
|
||||
> & {
|
||||
track?: LocalVideoTrack
|
||||
hideMenu?: boolean
|
||||
}
|
||||
|
||||
export const VideoDeviceControl = ({
|
||||
track,
|
||||
hideMenu,
|
||||
...props
|
||||
}: VideoDeviceControlProps) => {
|
||||
const config: ToggleDeviceConfig = {
|
||||
kind: 'videoinput',
|
||||
iconOn: RiVideoOnLine,
|
||||
iconOff: RiVideoOffLine,
|
||||
shortcut: {
|
||||
key: 'e',
|
||||
ctrlKey: true,
|
||||
},
|
||||
}
|
||||
|
||||
const { t } = useTranslation('rooms', { keyPrefix: 'join' })
|
||||
|
||||
const { userChoices, saveVideoInputDeviceId, saveVideoInputEnabled } =
|
||||
usePersistentUserChoices()
|
||||
|
||||
const onChange = React.useCallback(
|
||||
(enabled: boolean, isUserInitiated: boolean) =>
|
||||
isUserInitiated ? saveVideoInputEnabled(enabled) : null,
|
||||
[saveVideoInputEnabled]
|
||||
)
|
||||
|
||||
const trackProps = useTrackToggle({
|
||||
source: Source.Camera,
|
||||
onChange,
|
||||
...props,
|
||||
})
|
||||
|
||||
const permissions = useSnapshot(permissionsStore)
|
||||
|
||||
const isPermissionDeniedOrPrompted =
|
||||
permissions.isCameraDenied || permissions.isCameraPrompted
|
||||
|
||||
const toggle = () => {
|
||||
/**
|
||||
* We need to make sure that we apply the in-memory processor when re-enabling the camera.
|
||||
* Before, we had the following bug:
|
||||
* 1 - Configure a processor on join screen
|
||||
* 2 - Turn off camera on join screen
|
||||
* 3 - Join the room
|
||||
* 4 - Turn on the camera
|
||||
* 5 - No processor is applied to the camera
|
||||
* Expected: The processor is applied.
|
||||
*
|
||||
* See https://github.com/numerique-gouv/meet/pull/309#issuecomment-2622404121
|
||||
*/
|
||||
const processor = BackgroundProcessorFactory.deserializeProcessor(
|
||||
userChoices.processorSerialized
|
||||
)
|
||||
|
||||
const toggle = trackProps.toggle as (
|
||||
forceState: boolean,
|
||||
captureOptions: VideoCaptureOptions
|
||||
) => Promise<void>
|
||||
|
||||
toggle(!trackProps.enabled, {
|
||||
processor: processor,
|
||||
} as VideoCaptureOptions)
|
||||
}
|
||||
|
||||
const { devices, activeDeviceId, setActiveMediaDevice } =
|
||||
useMediaDeviceSelect({ kind: 'videoinput', track })
|
||||
|
||||
const selectLabel = t('videoinput.choose')
|
||||
|
||||
return (
|
||||
<div
|
||||
className={css({
|
||||
display: 'flex',
|
||||
gap: '1px',
|
||||
})}
|
||||
>
|
||||
<ToggleDevice
|
||||
{...trackProps}
|
||||
config={config}
|
||||
variant="primaryDark"
|
||||
toggle={toggle}
|
||||
isPermissionDeniedOrPrompted={isPermissionDeniedOrPrompted}
|
||||
toggleButtonProps={{
|
||||
...(hideMenu
|
||||
? {
|
||||
groupPosition: undefined,
|
||||
}
|
||||
: {}),
|
||||
}}
|
||||
/>
|
||||
{!hideMenu && (
|
||||
<Menu variant="dark">
|
||||
<Button
|
||||
isDisabled={isPermissionDeniedOrPrompted}
|
||||
tooltip={selectLabel}
|
||||
aria-label={selectLabel}
|
||||
groupPosition="right"
|
||||
square
|
||||
variant={
|
||||
trackProps.enabled && !isPermissionDeniedOrPrompted
|
||||
? 'primaryDark'
|
||||
: 'error2'
|
||||
}
|
||||
>
|
||||
<RiArrowUpSLine />
|
||||
</Button>
|
||||
<MenuList
|
||||
items={devices.map((d) => ({
|
||||
value: d.deviceId,
|
||||
label: d.label,
|
||||
}))}
|
||||
selectedItem={activeDeviceId}
|
||||
onAction={(value) => {
|
||||
setActiveMediaDevice(value as string)
|
||||
saveVideoInputDeviceId(value as string)
|
||||
}}
|
||||
variant="dark"
|
||||
/>
|
||||
</Menu>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
useMediaDeviceSelect,
|
||||
useTrackToggle,
|
||||
UseTrackToggleProps,
|
||||
} from '@livekit/components-react'
|
||||
import { Button, Menu, MenuList } from '@/primitives'
|
||||
import { RiArrowUpSLine } from '@remixicon/react'
|
||||
import {
|
||||
LocalAudioTrack,
|
||||
LocalVideoTrack,
|
||||
Track,
|
||||
VideoCaptureOptions,
|
||||
} from 'livekit-client'
|
||||
|
||||
import { ToggleDevice } from '@/features/rooms/livekit/components/controls/ToggleDevice.tsx'
|
||||
import { css } from '@/styled-system/css'
|
||||
import { ButtonRecipeProps } from '@/primitives/buttonRecipe'
|
||||
import { useEffect, useMemo } from 'react'
|
||||
import { usePersistentUserChoices } from '../../hooks/usePersistentUserChoices'
|
||||
import { BackgroundProcessorFactory } from '../blur'
|
||||
import { useSnapshot } from 'valtio'
|
||||
import { permissionsStore } from '@/stores/permissions'
|
||||
import {
|
||||
TOGGLE_DEVICE_CONFIG,
|
||||
ToggleSource,
|
||||
} from '../../config/ToggleDeviceConfig'
|
||||
|
||||
type SelectToggleDeviceProps<T extends ToggleSource> =
|
||||
UseTrackToggleProps<T> & {
|
||||
track?: LocalAudioTrack | LocalVideoTrack
|
||||
initialDeviceId?: string
|
||||
onActiveDeviceChange: (deviceId: string) => void
|
||||
source: ToggleSource
|
||||
variant?: NonNullable<ButtonRecipeProps>['variant']
|
||||
menuVariant?: 'dark' | 'light'
|
||||
hideMenu?: boolean
|
||||
}
|
||||
|
||||
export const SelectToggleDevice = <T extends ToggleSource>({
|
||||
track,
|
||||
initialDeviceId,
|
||||
onActiveDeviceChange,
|
||||
hideMenu,
|
||||
variant = 'primaryDark',
|
||||
menuVariant = 'light',
|
||||
...props
|
||||
}: SelectToggleDeviceProps<T>) => {
|
||||
const config = TOGGLE_DEVICE_CONFIG[props.source]
|
||||
if (!config) {
|
||||
throw new Error('Invalid source')
|
||||
}
|
||||
const { t } = useTranslation('rooms', { keyPrefix: 'join' })
|
||||
const trackProps = useTrackToggle(props)
|
||||
|
||||
const { userChoices } = usePersistentUserChoices()
|
||||
|
||||
const permissions = useSnapshot(permissionsStore)
|
||||
const isPermissionDeniedOrPrompted = useMemo(() => {
|
||||
switch (config.kind) {
|
||||
case 'audioinput':
|
||||
return (
|
||||
permissions.isMicrophoneDenied || permissions.isMicrophonePrompted
|
||||
)
|
||||
case 'videoinput':
|
||||
return permissions.isCameraDenied || permissions.isCameraPrompted
|
||||
}
|
||||
}, [permissions, config.kind])
|
||||
|
||||
const toggle = () => {
|
||||
if (props.source === Track.Source.Camera) {
|
||||
/**
|
||||
* We need to make sure that we apply the in-memory processor when re-enabling the camera.
|
||||
* Before, we had the following bug:
|
||||
* 1 - Configure a processor on join screen
|
||||
* 2 - Turn off camera on join screen
|
||||
* 3 - Join the room
|
||||
* 4 - Turn on the camera
|
||||
* 5 - No processor is applied to the camera
|
||||
* Expected: The processor is applied.
|
||||
*
|
||||
* See https://github.com/numerique-gouv/meet/pull/309#issuecomment-2622404121
|
||||
*/
|
||||
const processor = BackgroundProcessorFactory.deserializeProcessor(
|
||||
userChoices.processorSerialized
|
||||
)
|
||||
|
||||
const toggle = trackProps.toggle as (
|
||||
forceState: boolean,
|
||||
captureOptions: VideoCaptureOptions
|
||||
) => Promise<void>
|
||||
|
||||
toggle(!trackProps.enabled, {
|
||||
processor: processor,
|
||||
} as VideoCaptureOptions)
|
||||
} else {
|
||||
trackProps.toggle()
|
||||
}
|
||||
}
|
||||
|
||||
const { devices, activeDeviceId, setActiveMediaDevice } =
|
||||
useMediaDeviceSelect({ kind: config.kind, track })
|
||||
|
||||
/**
|
||||
* When providing only track outside of a room context, activeDeviceId is undefined.
|
||||
* So we need to initialize it with the initialDeviceId.
|
||||
* nb: I don't understand why useMediaDeviceSelect cannot infer it from track device id.
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (initialDeviceId !== undefined) {
|
||||
setActiveMediaDevice(initialDeviceId)
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [setActiveMediaDevice])
|
||||
|
||||
const selectLabel = t('choose', { keyPrefix: `join.${config.kind}` })
|
||||
|
||||
return (
|
||||
<div
|
||||
className={css({
|
||||
display: 'flex',
|
||||
gap: '1px',
|
||||
})}
|
||||
>
|
||||
<ToggleDevice
|
||||
{...trackProps}
|
||||
config={config}
|
||||
variant={variant}
|
||||
toggle={toggle}
|
||||
isPermissionDeniedOrPrompted={isPermissionDeniedOrPrompted}
|
||||
toggleButtonProps={{
|
||||
...(hideMenu
|
||||
? {
|
||||
groupPosition: undefined,
|
||||
}
|
||||
: {}),
|
||||
}}
|
||||
/>
|
||||
{!hideMenu && (
|
||||
<Menu variant={menuVariant}>
|
||||
<Button
|
||||
isDisabled={isPermissionDeniedOrPrompted}
|
||||
tooltip={selectLabel}
|
||||
aria-label={selectLabel}
|
||||
groupPosition="right"
|
||||
square
|
||||
variant={
|
||||
trackProps.enabled && !isPermissionDeniedOrPrompted
|
||||
? variant
|
||||
: 'error2'
|
||||
}
|
||||
>
|
||||
<RiArrowUpSLine />
|
||||
</Button>
|
||||
<MenuList
|
||||
items={devices.map((d) => ({
|
||||
value: d.deviceId,
|
||||
label: d.label,
|
||||
}))}
|
||||
selectedItem={activeDeviceId}
|
||||
onAction={(value) => {
|
||||
setActiveMediaDevice(value as string)
|
||||
onActiveDeviceChange(value as string)
|
||||
}}
|
||||
variant={menuVariant}
|
||||
/>
|
||||
</Menu>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import { MobileControlBar } from './MobileControlBar'
|
||||
import { DesktopControlBar } from './DesktopControlBar'
|
||||
import { SettingsDialogProvider } from '../../components/controls/SettingsDialogContext'
|
||||
import { useIsMobile } from '@/utils/useIsMobile'
|
||||
import { usePersistentUserChoices } from '../../hooks/usePersistentUserChoices'
|
||||
|
||||
/** @public */
|
||||
export type ControlBarControls = {
|
||||
@@ -48,53 +47,16 @@ export interface ControlBarProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
* @public
|
||||
*/
|
||||
export function ControlBar({ onDeviceError }: ControlBarProps) {
|
||||
const {
|
||||
saveAudioInputEnabled,
|
||||
saveVideoInputEnabled,
|
||||
saveAudioInputDeviceId,
|
||||
saveVideoInputDeviceId,
|
||||
} = usePersistentUserChoices()
|
||||
|
||||
const microphoneOnChange = React.useCallback(
|
||||
(enabled: boolean, isUserInitiated: boolean) =>
|
||||
isUserInitiated ? saveAudioInputEnabled(enabled) : null,
|
||||
[saveAudioInputEnabled]
|
||||
)
|
||||
|
||||
const cameraOnChange = React.useCallback(
|
||||
(enabled: boolean, isUserInitiated: boolean) =>
|
||||
isUserInitiated ? saveVideoInputEnabled(enabled) : null,
|
||||
[saveVideoInputEnabled]
|
||||
)
|
||||
|
||||
const barProps = {
|
||||
onDeviceError,
|
||||
microphoneOnChange,
|
||||
cameraOnChange,
|
||||
saveAudioInputDeviceId,
|
||||
saveVideoInputDeviceId,
|
||||
}
|
||||
|
||||
const isMobile = useIsMobile()
|
||||
|
||||
return (
|
||||
<SettingsDialogProvider>
|
||||
{isMobile ? (
|
||||
<MobileControlBar {...barProps} />
|
||||
<MobileControlBar onDeviceError={onDeviceError} />
|
||||
) : (
|
||||
<DesktopControlBar {...barProps} />
|
||||
<DesktopControlBar onDeviceError={onDeviceError} />
|
||||
)}
|
||||
</SettingsDialogProvider>
|
||||
)
|
||||
}
|
||||
|
||||
export interface ControlBarAuxProps {
|
||||
onDeviceError: ControlBarProps['onDeviceError']
|
||||
microphoneOnChange: (
|
||||
enabled: boolean,
|
||||
isUserInitiated: boolean
|
||||
) => void | null
|
||||
cameraOnChange: (enabled: boolean, isUserInitiated: boolean) => void | null
|
||||
saveAudioInputDeviceId: (deviceId: string) => void
|
||||
saveVideoInputDeviceId: (deviceId: string) => void
|
||||
}
|
||||
export type ControlBarAuxProps = Pick<ControlBarProps, 'onDeviceError'>
|
||||
|
||||
@@ -2,7 +2,6 @@ import { supportsScreenSharing } from '@livekit/components-core'
|
||||
import { ControlBarAuxProps } from './ControlBar'
|
||||
import { css } from '@/styled-system/css'
|
||||
import { LeaveButton } from '../../components/controls/LeaveButton'
|
||||
import { SelectToggleDevice } from '../../components/controls/SelectToggleDevice'
|
||||
import { Track } from 'livekit-client'
|
||||
import { ReactionsToggle } from '../../components/controls/ReactionsToggle'
|
||||
import { HandToggle } from '../../components/controls/HandToggle'
|
||||
@@ -11,14 +10,10 @@ import { OptionsButton } from '../../components/controls/Options/OptionsButton'
|
||||
import { StartMediaButton } from '../../components/controls/StartMediaButton'
|
||||
import { MoreOptions } from './MoreOptions'
|
||||
import { useRef } from 'react'
|
||||
import { VideoDeviceControl } from '../../components/controls/Device/VideoDeviceControl'
|
||||
import { AudioDevicesControl } from '../../components/controls/Device/AudioDevicesControl'
|
||||
|
||||
export function DesktopControlBar({
|
||||
onDeviceError,
|
||||
microphoneOnChange,
|
||||
cameraOnChange,
|
||||
saveAudioInputDeviceId,
|
||||
saveVideoInputDeviceId,
|
||||
}: ControlBarAuxProps) {
|
||||
export function DesktopControlBar({ onDeviceError }: ControlBarAuxProps) {
|
||||
const browserSupportsScreenSharing = supportsScreenSharing()
|
||||
const desktopControlBarEl = useRef<HTMLDivElement>(null)
|
||||
return (
|
||||
@@ -53,27 +48,15 @@ export function DesktopControlBar({
|
||||
gap: '0.65rem',
|
||||
})}
|
||||
>
|
||||
<SelectToggleDevice
|
||||
source={Track.Source.Microphone}
|
||||
onChange={microphoneOnChange}
|
||||
<AudioDevicesControl
|
||||
onDeviceError={(error) =>
|
||||
onDeviceError?.({ source: Track.Source.Microphone, error })
|
||||
}
|
||||
onActiveDeviceChange={(deviceId) =>
|
||||
saveAudioInputDeviceId(deviceId ?? '')
|
||||
}
|
||||
menuVariant="dark"
|
||||
/>
|
||||
<SelectToggleDevice
|
||||
source={Track.Source.Camera}
|
||||
onChange={cameraOnChange}
|
||||
<VideoDeviceControl
|
||||
onDeviceError={(error) =>
|
||||
onDeviceError?.({ source: Track.Source.Camera, error })
|
||||
}
|
||||
onActiveDeviceChange={(deviceId) =>
|
||||
saveVideoInputDeviceId(deviceId ?? '')
|
||||
}
|
||||
menuVariant="dark"
|
||||
/>
|
||||
<ReactionsToggle />
|
||||
{browserSupportsScreenSharing && (
|
||||
|
||||
@@ -4,7 +4,6 @@ import { ControlBarAuxProps } from './ControlBar'
|
||||
import React from 'react'
|
||||
import { css } from '@/styled-system/css'
|
||||
import { LeaveButton } from '../../components/controls/LeaveButton'
|
||||
import { SelectToggleDevice } from '../../components/controls/SelectToggleDevice'
|
||||
import { Track } from 'livekit-client'
|
||||
import { HandToggle } from '../../components/controls/HandToggle'
|
||||
import { Button } from '@/primitives/Button'
|
||||
@@ -24,14 +23,10 @@ import { ResponsiveMenu } from './ResponsiveMenu'
|
||||
import { ToolsToggle } from '../../components/controls/ToolsToggle'
|
||||
import { CameraSwitchButton } from '../../components/controls/CameraSwitchButton'
|
||||
import { useConfig } from '@/api/useConfig'
|
||||
import { AudioDevicesControl } from '../../components/controls/Device/AudioDevicesControl'
|
||||
import { VideoDeviceControl } from '../../components/controls/Device/VideoDeviceControl'
|
||||
|
||||
export function MobileControlBar({
|
||||
onDeviceError,
|
||||
microphoneOnChange,
|
||||
cameraOnChange,
|
||||
saveAudioInputDeviceId,
|
||||
saveVideoInputDeviceId,
|
||||
}: ControlBarAuxProps) {
|
||||
export function MobileControlBar({ onDeviceError }: ControlBarAuxProps) {
|
||||
const { t } = useTranslation('rooms')
|
||||
const [isMenuOpened, setIsMenuOpened] = React.useState(false)
|
||||
const browserSupportsScreenSharing = supportsScreenSharing()
|
||||
@@ -62,27 +57,15 @@ export function MobileControlBar({
|
||||
})}
|
||||
>
|
||||
<LeaveButton />
|
||||
<SelectToggleDevice
|
||||
source={Track.Source.Microphone}
|
||||
onChange={microphoneOnChange}
|
||||
<AudioDevicesControl
|
||||
onDeviceError={(error) =>
|
||||
onDeviceError?.({ source: Track.Source.Microphone, error })
|
||||
}
|
||||
onActiveDeviceChange={(deviceId) =>
|
||||
saveAudioInputDeviceId(deviceId ?? '')
|
||||
}
|
||||
hideMenu={true}
|
||||
/>
|
||||
<SelectToggleDevice
|
||||
source={Track.Source.Camera}
|
||||
onChange={cameraOnChange}
|
||||
<VideoDeviceControl
|
||||
onDeviceError={(error) =>
|
||||
onDeviceError?.({ source: Track.Source.Camera, error })
|
||||
}
|
||||
onActiveDeviceChange={(deviceId) =>
|
||||
saveVideoInputDeviceId(deviceId ?? '')
|
||||
}
|
||||
hideMenu={true}
|
||||
/>
|
||||
<HandToggle />
|
||||
<Button
|
||||
|
||||
Reference in New Issue
Block a user