@100mslive/roomkit-react
Version:

197 lines (189 loc) • 5.86 kB
JSX
import React from 'react';
import {
DeviceType,
getAudioDeviceCategory,
HMSAudioDeviceCategory,
selectIsLocalVideoEnabled,
selectLocalVideoTrackID,
selectVideoTrackByID,
useDevices,
useHMSActions,
useHMSStore,
} from '@100mslive/react-sdk';
import {
BluetoothIcon,
CameraFlipIcon,
CheckIcon,
CrossIcon,
HeadphonesIcon,
SpeakerIcon,
TelePhoneIcon,
} from '@100mslive/react-icons';
import { HorizontalDivider } from '../../../Divider';
import { Label } from '../../../Label';
import { Box, Flex } from '../../../Layout';
import { Sheet } from '../../../Sheet';
import { Text } from '../../../Text';
import IconButton from '../../IconButton';
import { ToastManager } from '../Toast/ToastManager';
export const CamaraFlipActions = () => {
const actions = useHMSActions();
const { allDevices } = useDevices();
const { videoInput } = allDevices;
const isVideoOn = useHMSStore(selectIsLocalVideoEnabled);
const videoTrackId = useHMSStore(selectLocalVideoTrackID);
const localVideoTrack = useHMSStore(selectVideoTrackByID(videoTrackId));
if (!videoInput || !videoInput?.length || !localVideoTrack?.facingMode) {
return null;
}
return (
<Box>
<IconButton
disabled={!isVideoOn}
onClick={async () => {
try {
await actions.switchCamera();
} catch (e) {
ToastManager.addToast({
title: `Error while flipping camera ${e.message || ''}`,
variant: 'error',
});
}
}}
>
<CameraFlipIcon />
</IconButton>
</Box>
);
};
// It will handle and show audio input devices in Mweb while audio output devices in desktop
export const AudioActions = () => {
const { allDevices, selectedDeviceIDs, updateDevice } = useDevices();
// don't show speaker selector where the API is not supported, and use
// a generic word("Audio") for Mic. In some cases(Chrome Android for example) this changes both mic and speaker keeping them in sync.
const shouldShowAudioOutput = 'setSinkId' in HTMLMediaElement.prototype;
const { audioInput, audioOutput } = allDevices;
let availableAudioDevices = audioInput;
let selectedAudio = selectedDeviceIDs.audioInput;
if (shouldShowAudioOutput) {
availableAudioDevices = audioOutput;
selectedAudio = selectedDeviceIDs.audioOutput;
}
const hmsActions = useHMSActions();
const audioFiltered = availableAudioDevices?.find(item => !!item.label);
const currentSelection = availableAudioDevices?.find(item => item.deviceId === selectedAudio);
if (!audioFiltered) {
return null;
}
const deviceCategory = getAudioDeviceCategory(currentSelection?.label);
let AudioIcon = <SpeakerIcon />;
if (deviceCategory === HMSAudioDeviceCategory.BLUETOOTH) {
AudioIcon = <BluetoothIcon />;
} else if (deviceCategory === HMSAudioDeviceCategory.WIRED) {
AudioIcon = <HeadphonesIcon />;
} else if (deviceCategory === HMSAudioDeviceCategory.EARPIECE) {
AudioIcon = <TelePhoneIcon />;
}
return (
<AudioSelectionSheet
audioDevices={availableAudioDevices}
audioSelected={selectedAudio}
onChange={async deviceId => {
try {
await updateDevice({
deviceId,
deviceType: shouldShowAudioOutput ? DeviceType.audioOutput : DeviceType.audioInput,
});
} catch (e) {
ToastManager.addToast({
title: `Error while changing audio device ${e.message || ''}`,
variant: 'error',
});
}
}}
>
<Box
onClick={async () => {
// refresh device as `devicechange` listener won't work in mobile device
await hmsActions.refreshDevices();
}}
>
<IconButton>{AudioIcon}</IconButton>
</Box>
</AudioSelectionSheet>
);
};
const AudioSelectionSheet = ({ audioDevices, audioSelected, onChange, children }) => {
return (
<Sheet.Root>
<Sheet.Trigger asChild>{children}</Sheet.Trigger>
<Sheet.Content>
<Sheet.Title css={{ py: '$10', px: '$8', alignItems: 'center' }}>
<Flex direction="row" justify="between" css={{ w: '100%' }}>
<Text variant="h6" css={{ display: 'flex' }}>
Audio
</Text>
<Sheet.Close>
<IconButton as="div" data-testid="dialog_cross_icon">
<CrossIcon />
</IconButton>
</Sheet.Close>
</Flex>
</Sheet.Title>
<HorizontalDivider />
<Flex
direction="column"
css={{
px: '$8',
maxHeight: '80vh',
overflowY: 'auto',
}}
>
{audioDevices.map(audioDevice => {
return (
<SelectWithLabel
key={audioDevice.deviceId}
label={audioDevice.label}
id={audioDevice.deviceId}
checked={audioDevice.deviceId === audioSelected}
onChange={() => onChange(audioDevice.deviceId)}
/>
);
})}
</Flex>
</Sheet.Content>
</Sheet.Root>
);
};
const SelectWithLabel = ({ label, icon = <></>, checked, id, onChange }) => {
return (
<Flex
align="center"
css={{
my: '$2',
py: '$8',
w: '100%',
borderBottom: '1px solid $border_default',
}}
onClick={onChange}
>
<Label
htmlFor={id}
css={{
fontSize: '$md',
fontWeight: '$semiBold',
color: '$on_surface_high',
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
gap: '$8',
flex: '1 1 0',
}}
>
{icon}
{label}
</Label>
{checked && <CheckIcon width={24} height={24} />}
</Flex>
);
};