import { AudioDeviceInfo , VideoDeviceInfo } from '@azure/communication-calling' ; import { Dropdown , Icon , IDropdownOption , Label , mergeStyles , Stack } from '@fluentui/react' ; import { useTheme , VideoStreamOptions } from '@internal/react-components' ; import React from 'react' ; import { useLocale } from '../../localization' ; import { dropDownStyles , dropDownTitleIconStyles , mainStackTokens , optionIconStyles } from '../styles/LocalDeviceSettings.styles' ; type iconType = 'Camera' | 'Microphone' | 'Speaker' ; const getDropDownList = ( list ) : IDropdownOption [ ] => { const noDuplicates = new Map < string , VideoDeviceInfo | AudioDeviceInfo > ( ) ; for ( const item of list ) { noDuplicates . set ( item . id , item ) ; } const dropdownList = [ ] ; for ( const item of noDuplicates . values ( ) ) { dropdownList . push ( { key : item . id , text : item . name === '' ? item . deviceType : item . name } ) ; } return dropdownList ; } ; const getOptionIcon = ( type ) : JSX . Element | undefined => { if ( type === 'Camera' ) { return < Icon iconName = "LocalDeviceSettingsCamera" className = { optionIconStyles } / > ; } else if ( type === 'Microphone' ) { return < Icon iconName = "LocalDeviceSettingsMic" className = { optionIconStyles } / > ; } else if ( type === 'Speaker' ) { return < Icon iconName = "LocalDeviceSettingsSpeaker" className = { optionIconStyles } / > ; } else { return undefined ; } } ; const onRenderTitle = ( iconType , props ? ) : JSX . Element => { const icon = props && getOptionIcon ( iconType ) ; return props ? ( < div className = { dropDownTitleIconStyles } > { icon } < span > { props [ 0 ] . text } < /span> < /div>) : (<></ > ) ; } ; const localVideoViewOptions = { scalingMode : 'Crop' , isMirrored : true } as VideoStreamOptions ; private export interface LocalDeviceSettingsType { cameras : VideoDeviceInfo [ ] ; microphones : AudioDeviceInfo [ ] ; speakers : AudioDeviceInfo [ ] ; selectedCamera ? : VideoDeviceInfo ; selectedMicrophone ? : AudioDeviceInfo ; selectedSpeaker ? : AudioDeviceInfo ; microphonePermissionGranted : boolean | undefined ; cameraPermissionGranted : boolean | undefined ; onSelectCamera : ( device : VideoDeviceInfo , options ? : VideoStreamOptions ) => Promise < void > ; onSelectMicrophone : ( device : AudioDeviceInfo ) => Promise < void > ; onSelectSpeaker : ( device : AudioDeviceInfo ) => Promise < void > ; } private export const LocalDeviceSettings = ( props ) : JSX . Element => { const theme = useTheme ( ) ; const locale = useLocale ( ) ; const defaultPlaceHolder = locale . strings . call . defaultPlaceHolder ; const cameraLabel = locale . strings . call . cameraLabel ; const soundLabel = locale . strings . call . soundLabel ; return ( < Stack data - ui - id = "call-composite-device-settings" tokens = { mainStackTokens } > < Stack > < Label id = { 'call-composite-local-camera-settings-label' } className = { mergeStyles ( dropDownStyles ( theme ) . label ) } disabled = { ! props . cameraPermissionGranted } > { cameraLabel } < /Label> < Dropdown data - ui - id = "call-composite-local-camera-settings" aria - labelledby = { 'call-composite-local-camera-settings-label' } placeholder = { defaultPlaceHolder } options = { props . cameraPermissionGranted ? getDropDownList ( props . cameras ) : [ { key : 'deniedOrUnknown' , text : '' } ] } styles = { dropDownStyles ( theme ) } disabled = { ! props . cameraPermissionGranted } errorMessage = { props . cameraPermissionGranted === undefined || props . cameraPermissionGranted ? undefined : locale . strings . call . cameraPermissionDenied } defaultSelectedKey = { props . cameraPermissionGranted ? props . selectedCamera ? props . selectedCamera . id : props . cameras ? props . cameras [ 0 ] ?. id : '' : 'deniedOrUnknown' } onChange = { ( event , option , index ) => { props . onSelectCamera ( props . cameras [ index ?? 0 ] , localVideoViewOptions ) ; } } onRenderTitle = { ( props ? ) => onRenderTitle ( 'Camera' , props ) } /> < /Stack> < Stack > < Label id = { 'call-composite-local-sound-settings-label' } className = { mergeStyles ( dropDownStyles ( theme ) . label ) } disabled = { ! props . microphonePermissionGranted } > { soundLabel } < /Label> < Stack data - ui - id = "call-composite-sound-settings" tokens = { mainStackTokens } > < Dropdown aria - labelledby = { 'call-composite-local-sound-settings-label' } placeholder = { defaultPlaceHolder } styles = { dropDownStyles ( theme ) } disabled = { ! props . microphonePermissionGranted } errorMessage = { props . microphonePermissionGranted === undefined || props . microphonePermissionGranted ? undefined : locale . strings . call . microphonePermissionDenied } options = { props . microphonePermissionGranted ? getDropDownList ( props . microphones ) : [ { key : 'deniedOrUnknown' , text : '' } ] } defaultSelectedKey = { props . microphonePermissionGranted ? props . selectedMicrophone ? props . selectedMicrophone . id : defaultDeviceId ( props . microphones ) : 'deniedOrUnknown' } onChange = { ( event , option ? , index ? ) => { props . onSelectMicrophone ( props . microphones [ index ?? 0 ] ) ; } } onRenderTitle = { ( props ? ) => onRenderTitle ( 'Microphone' , props ) } /> < Dropdown aria - labelledby = { 'call-composite-local-sound-settings-label' } placeholder = { defaultPlaceHolder } styles = { dropDownStyles ( theme ) } disabled = { props . speakers . length === 0 } options = { getDropDownList ( props . speakers ) } defaultSelectedKey = { props . selectedSpeaker ? props . selectedSpeaker . id : defaultDeviceId ( props . speakers ) } onChange = { ( event , option ? , index ? ) => { props . onSelectSpeaker ( props . speakers [ index ?? 0 ] ) ; } } onRenderTitle = { ( props ? ) => onRenderTitle ( 'Speaker' , props ) } /> < /Stack> < /Stack> < /Stack>); } ; const defaultDeviceId = ( devices ) : string => { if ( devices . length === 0 ) { return '' ; } const defaultDevice = devices . find ( ( device ) => device . isSystemDefault ) ; if ( defaultDevice ) { return defaultDevice . id ; } return devices [ 0 ] . id ; } ;