UNPKG

@azure/communication-react

Version:

React library for building modern communication user experiences utilizing Azure Communication Services

166 lines • 10.7 kB
// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import { Dropdown, Label, mergeStyles, Stack } from '@fluentui/react'; import { DefaultButton } from '@fluentui/react'; import { useEffect } from 'react'; import { useTheme } from "../../../../../react-components/src"; import React from 'react'; import { CallCompositeIcon } from '../../common/icons'; import { useLocale } from '../../localization'; import { deviceSelectionContainerStyles, dropDownStyles, dropDownTitleIconStyles, mainStackTokens, optionIconStyles, soundStackTokens } from '../styles/LocalDeviceSettings.styles'; import { useAdapter } from '../adapter/CallAdapterProvider'; import { ConfigurationPageCameraDropdown } from './ConfigurationPageCameraDropdown'; import { ConfigurationPageMicDropdown } from './ConfigurationPageMicDropdown'; import { cameraAndVideoEffectsContainerStyleDesktop } from '../styles/CallConfiguration.styles'; import { effectsButtonStyles } from '../styles/CallConfiguration.styles'; import { useSelector } from '../hooks/useSelector'; import { getRole, getVideoEffectsDependency } from '../selectors/baseSelectors'; import { getEnvironmentInfo } from '../selectors/baseSelectors'; import { _isSafari } from '../utils'; import { useId } from '@fluentui/react-hooks'; const getDropDownList = (list) => { // Remove duplicates const noDuplicates = new Map(); 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) => { if (type === 'Camera') { return React.createElement(CallCompositeIcon, { iconName: "LocalDeviceSettingsCamera", className: optionIconStyles }); } else if (type === 'Microphone') { return React.createElement(CallCompositeIcon, { iconName: "LocalDeviceSettingsMic", className: optionIconStyles }); } else if (type === 'Speaker') { return React.createElement(CallCompositeIcon, { iconName: "LocalDeviceSettingsSpeaker", className: optionIconStyles }); } else { return undefined; } }; const onRenderTitle = (iconType, props) => { var _a; return props ? React.createElement("div", { className: dropDownTitleIconStyles }, getOptionIcon(iconType), React.createElement("span", null, (_a = props[0]) === null || _a === void 0 ? void 0 : _a.text)) : React.createElement(React.Fragment, null); }; const localVideoViewOptions = { scalingMode: 'Crop', isMirrored: true }; /** * @private */ export const LocalDeviceSettings = (props) => { var _a; const theme = useTheme(); const locale = useLocale(); const adapter = useAdapter(); const onResolveVideoEffectDependency = useSelector(getVideoEffectsDependency); const defaultPlaceHolder = locale.strings.call.defaultPlaceHolder; const cameraLabel = locale.strings.call.cameraLabel; const soundLabel = locale.strings.call.soundLabel; const noSpeakersLabel = locale.strings.call.noSpeakersLabel; const noCameraLabel = locale.strings.call.noCamerasLabel; const noMicLabel = locale.strings.call.noMicrophonesLabel; const role = useSelector(getRole); const cameraPermissionGranted = props.cameraPermissionGranted; const micPermissionGranted = props.microphonePermissionGranted; const roleCanUseCamera = role !== 'Consumer'; const roleCanUseMic = role !== 'Consumer'; // TODO: speaker permission is tied to microphone permission (when you request 'audio' permission using the SDK) its // actually granting access to query both microphone and speaker. However the browser popup asks you explicity for // 'microphone'. This needs investigation on how we want to handle this and maybe needs follow up with SDK team. useEffect(() => { if (cameraPermissionGranted) { adapter.queryCameras(); } if (micPermissionGranted) { adapter.queryMicrophones(); } adapter.querySpeakers(); }, [adapter, cameraPermissionGranted, micPermissionGranted]); const hasCameras = props.cameras.length > 0; const hasMicrophones = props.microphones.length > 0; const hasSpeakers = props.speakers.length > 0; const environmentInfo = useSelector(getEnvironmentInfo); const isSafariWithNoSpeakers = _isSafari(environmentInfo) && !hasSpeakers; const cameraLabelId = useId('camera-label'); const soundLabelId = useId('sound-label'); const cameraGrantedDropdown = React.createElement(Dropdown, { "data-ui-id": "call-composite-local-camera-settings", "aria-labelledby": cameraLabelId, placeholder: hasCameras ? defaultPlaceHolder : noCameraLabel, options: cameraPermissionGranted ? getDropDownList(props.cameras) : [{ key: 'deniedOrUnknown', text: '' }], styles: dropDownStyles(theme), disabled: !cameraPermissionGranted || !hasCameras, errorMessage: props.cameraPermissionGranted === undefined || props.cameraPermissionGranted ? undefined : locale.strings.call.cameraPermissionDenied, defaultSelectedKey: micPermissionGranted ? props.selectedCamera ? props.selectedCamera.id : props.cameras ? (_a = props.cameras[0]) === null || _a === void 0 ? void 0 : _a.id : '' : 'deniedOrUnknown', onChange: (event, option, index) => __awaiter(void 0, void 0, void 0, function* () { const camera = props.cameras[index !== null && index !== void 0 ? index : 0]; if (camera) { yield props.onSelectCamera(camera, localVideoViewOptions); } else { console.error('No cameras available'); } }), onRenderTitle: (props) => onRenderTitle('Camera', props) }); const micGrantedDropdown = React.createElement(React.Fragment, null, roleCanUseMic && React.createElement(Dropdown, { "aria-labelledby": soundLabelId, placeholder: hasMicrophones ? defaultPlaceHolder : noMicLabel, styles: dropDownStyles(theme), disabled: !micPermissionGranted || !hasMicrophones, errorMessage: props.microphonePermissionGranted === undefined || props.microphonePermissionGranted ? undefined : locale.strings.call.microphonePermissionDenied, options: micPermissionGranted ? getDropDownList(props.microphones) : [{ key: 'deniedOrUnknown', text: '' }], defaultSelectedKey: micPermissionGranted ? props.selectedMicrophone ? props.selectedMicrophone.id : defaultDeviceId(props.microphones) : 'deniedOrUnknown', onChange: (event, option, index) => { const microphone = props.microphones[index !== null && index !== void 0 ? index : 0]; if (microphone) { props.onSelectMicrophone(microphone); } else { console.error('No microphones available'); } }, onRenderTitle: (props) => onRenderTitle('Microphone', props) })); const speakerDropdown = React.createElement(Dropdown, { "aria-labelledby": soundLabelId, placeholder: hasSpeakers ? defaultPlaceHolder : noSpeakersLabel, 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) => { const speaker = props.speakers[index !== null && index !== void 0 ? index : 0]; if (speaker) { props.onSelectSpeaker(speaker); } else { console.error('No speakers available'); } }, onRenderTitle: (props) => onRenderTitle('Speaker', props) }); return React.createElement(Stack, { "data-ui-id": "call-composite-device-settings", tokens: mainStackTokens, styles: deviceSelectionContainerStyles }, roleCanUseCamera && React.createElement(Stack, null, React.createElement(Stack, { horizontal: true, horizontalAlign: "space-between", styles: cameraAndVideoEffectsContainerStyleDesktop }, React.createElement(Label, { id: cameraLabelId, className: mergeStyles(dropDownStyles(theme).label) }, cameraLabel), onResolveVideoEffectDependency && React.createElement(DefaultButton, { iconProps: { iconName: 'ConfigurationScreenVideoEffectsButton' }, styles: effectsButtonStyles(theme, !cameraPermissionGranted), onClick: props.onClickVideoEffects, disabled: !cameraPermissionGranted, "data-ui-id": 'call-config-video-effects-button' }, locale.strings.call.configurationPageVideoEffectsButtonLabel)), React.createElement(ConfigurationPageCameraDropdown, { cameraGrantedDropdown: cameraGrantedDropdown, cameraPermissionGranted: cameraPermissionGranted !== null && cameraPermissionGranted !== void 0 ? cameraPermissionGranted : false, ariaLabelledby: cameraLabelId })), React.createElement(Stack, null, React.createElement(Label, { id: soundLabelId, className: mergeStyles(dropDownStyles(theme).label) }, soundLabel), React.createElement(Stack, { "data-ui-id": "call-composite-sound-settings", tokens: soundStackTokens }, React.createElement(ConfigurationPageMicDropdown, { micGrantedDropdown: micGrantedDropdown, micPermissionGranted: micPermissionGranted !== null && micPermissionGranted !== void 0 ? micPermissionGranted : false, ariaLabelledby: soundLabelId }), isSafariWithNoSpeakers ? React.createElement(React.Fragment, null) : speakerDropdown))); }; const defaultDeviceId = (devices) => { var _a; if (devices.length === 0) { return undefined; } const defaultDevice = devices.find(device => device.isSystemDefault); if (defaultDevice) { return defaultDevice.id; } return (_a = devices[0]) === null || _a === void 0 ? void 0 : _a.id; }; //# sourceMappingURL=LocalDeviceSettings.js.map