import React, { ChangeEventHandler, useMemo, useEffect, useState } from 'react'; import { SettingsIcon, CloseIcon } from '../Icons'; import Dialog from '@material-ui/core/Dialog'; import Slider from '@material-ui/core/Slider'; import { withStyles } from '@material-ui/core/styles'; import { closeMediaStream } from '../../utils'; import { hmsUiClassParserGenerator } from '../../utils/classes'; import { Button as TwButton } from '../TwButton'; import { Text } from '../Text'; import { useHMSStore } from '../../hooks/HMSRoomProvider'; import { selectLocalMediaSettings } from '../../store/selectors'; import { useHMSTheme } from '../../hooks/HMSThemeProvider'; import { getLocalDevices, getLocalStream } from '@100mslive/100ms-web-sdk'; interface SettingsClasses { root?: string; iconContainer?: string; dialogRoot?: string; dialogContainer?: string; dialogInner?: string; titleContainer?: string; titleIcon?: string; titleText?: string; formContainer?: string; formInner?: string; selectLabel?: string; selectContainer?: string; select?: string; selectInner?: string; divider?: string; sliderContainer?: string; sliderInner?: string; sliderLabelContainer?: string; sliderLabel?: string; slider?: string; errorContainer?: string; } export interface SettingsFormProps { selectedVideoInput?: string; selectedAudioInput?: string; selectedAudioOutput?: string; maxTileCount?: number; } export interface SettingsProps { initialValues?: SettingsFormProps; onChange?: (values: SettingsFormProps) => void; classes?: SettingsClasses; } const defaultClasses: SettingsClasses = { iconContainer: 'focus:outline-none mr-3 hover:bg-gray-200 p-2 rounded-lg', dialogRoot: 'rounded-xl ', dialogContainer: 'bg-white text-gray-100 dark:bg-gray-100 dark:text-white w-full p-2 overflow-y-auto rounded-xl', dialogInner: 'text-2xl mb-3 p-2 flex justify-between', titleContainer: 'flex items-center', titleIcon: 'pr-4', titleText: 'text-2xl leading-7', formContainer: 'flex flex-wrap text-base', formInner: 'w-full flex my-1.5', selectLabel: 'w-1/3 flex justify-end items-center', selectContainer: 'rounded-lg w-1/2 bg-gray-600 dark:bg-gray-200 p-2 mx-2', select: 'rounded-lg w-full h-full bg-gray-600 dark:bg-gray-200 focus:outline-none', selectInner: 'p-4', divider: 'bg-gray-600 dark:bg-gray-200 h-px w-full my-4', sliderContainer: 'w-full my-1.5', sliderInner: 'w-full flex', sliderLabelContainer: 'w-1/3 flex justify-end items-center ', sliderLabel: 'text-right', slider: 'rounded-lg w-1/2 p-2 mx-2 flex my-1 items-center ', errorContainer: 'flex justify-center items-center w-full px-8 py-4', }; const customClasses: SettingsClasses = { dialogContainer: 'no-scrollbar ', }; //TODO replce with own slider const HMSSlider = withStyles({ root: { color: document.documentElement.classList.contains('dark') ? 'white' : 'black', }, thumb: { backgroundColor: document.documentElement.classList.contains('dark') ? 'black' : 'white', border: '2px solid currentColor', '&:focus, &:hover, &$active': { boxShadow: 'inherit', }, color: document.documentElement.classList.contains('dark') ? 'white' : 'black', }, active: {}, valueLabel: { color: document.documentElement.classList.contains('dark') ? 'white' : 'black', }, })(Slider); const HMSDialog = withStyles({ paper: { borderRadius: '12px', backgroundColor: 'inherit', }, })(Dialog); //TODO split button and settings dialog export const Settings = ({ onChange, initialValues, classes, }: SettingsProps) => { const { tw } = useHMSTheme(); const styler = useMemo( () => hmsUiClassParserGenerator({ tw, classes, customClasses, defaultClasses, tag: 'hmsui-settings', }), [], ); const storeInitialValues = useHMSStore(selectLocalMediaSettings); const [open, setOpen] = useState(false); const [deviceGroups, setDeviceGroups] = useState<{ audioinput: MediaDeviceInfo[]; audiooutput: MediaDeviceInfo[]; videoinput: MediaDeviceInfo[]; }>({ audioinput: [], audiooutput: [], videoinput: [], }); const [error, setError] = useState(''); if (!initialValues) { initialValues = {}; } initialValues.selectedVideoInput = initialValues.selectedVideoInput || storeInitialValues.videoInputDeviceId; initialValues.selectedAudioInput = initialValues.selectedAudioInput || storeInitialValues.audioInputDeviceId; initialValues.selectedAudioOutput = initialValues.selectedAudioOutput || storeInitialValues.audioOutputDeviceId; const [values, setValues] = useState({ selectedAudioInput: initialValues?.selectedAudioInput ? initialValues?.selectedAudioInput : 'default', selectedVideoInput: initialValues?.selectedVideoInput ? initialValues?.selectedVideoInput : 'default', selectedAudioOutput: initialValues?.selectedAudioOutput ? initialValues?.selectedAudioOutput : 'default', maxTileCount: initialValues?.maxTileCount ? initialValues?.maxTileCount : 9, }); useEffect(() => { if (open) { getLocalStream({ video: true, audio: true }) .then(stream => { closeMediaStream(stream); getLocalDevices().then(deviceGroups => setDeviceGroups(deviceGroups)); }) .catch(err => setError(err.message)); } }, [open]); const handleClickOpen = () => { setOpen(true); }; const handleClose = () => { setOpen(false); onChange && onChange(values); }; const handleInputChange: ChangeEventHandler = event => { const newValues = { ...values }; newValues[event.currentTarget.name as keyof SettingsFormProps] = event.currentTarget.value; setValues(newValues); }; const handleSliderChange = (event: any, newValue: number | number[]) => { const newValues = { ...values }; //TODO make this generic if (typeof newValue === 'number') { newValues['maxTileCount'] = newValue; } setValues(newValues); }; const videoInput = deviceGroups['videoinput'] ? deviceGroups['videoinput'] : []; const audioInput = deviceGroups['audioinput'] ? deviceGroups['audioinput'] : []; const audioOutput = deviceGroups['audiooutput'] ? deviceGroups['audiooutput'] : []; //TODO handle case where selected device is not in list // audioOutput.length > 0 && audioOutput.findIndex(device => device.deviceId===values?.selectedAudioOutput)===-1 && setValues({selectedAudioOutput:videoInput[0].deviceId}); // audioInput.length > 0 && audioInput.findIndex(device => device.deviceId===values?.selectedAudioInput)===-1 && setValues({selectedAudioInput:videoInput[0].deviceId}); // videoInput.length > 0 && videoInput.findIndex(device => device.deviceId===values?.selectedVideoInput)===-1 && setValues({selectedVideoInput:videoInput[0].deviceId}); return ( <>
Settings
{error === '' ? ( <>
Camera:
{videoInput.length > 0 && ( )}
Microphone:
{audioInput.length > 0 && ( )}
Audio Output:
{audioOutput.length > 0 && ( )}
) : (
Error in accessing devices. Please check permissions. Are all devices plugged in?
)} {/*
On Entering Room:
Keep my microphone off
Keep my video off
*/} {/*
*/} {/*
Virtual Background:
On
*/} {/*
Off
*/} {/*
*/} {/*
*/} {/*
Mute all Button should:
Mute Everyone expect me.
Mute Everyone in the room.
*/}
Participants in view:
{/*
Always stay in small view.
*/} {/*
*/} {/*
*/}
); };