communication-react-19
Version:
React library for building modern communication user experiences utilizing Azure Communication Services (React 19 compatible fork)
184 lines • 11.6 kB
JavaScript
// 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, _DevicePermissionDropdown } 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';
/* @conditional-compile-remove(call-readiness) */
import { useHandlers } from '../hooks/useHandlers';
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]);
/* @conditional-compile-remove(call-readiness) */
const dropdownProps = useHandlers(_DevicePermissionDropdown);
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,
/* @conditional-compile-remove(call-readiness) */
dropdownProps: dropdownProps,
/* @conditional-compile-remove(call-readiness) */
onClickEnableDevicePermission: props.onClickEnableDevicePermission, 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,
/* @conditional-compile-remove(call-readiness) */
dropdownProps: dropdownProps,
/* @conditional-compile-remove(call-readiness) */
onClickEnableDevicePermission: props.onClickEnableDevicePermission, 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