packages/react-composites/src/composites/CallComposite/hooks/useHandlers.ts (269 lines of code) (raw):

// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. import { CommonCallingHandlers } from '@internal/calling-component-bindings'; import { _ComponentCallingHandlers } from '@internal/calling-component-bindings'; import { CommonProperties, toFlatCommunicationIdentifier } from '@internal/acs-ui-common'; import { ReactElement } from 'react'; import memoizeOne from 'memoize-one'; import { CommonCallAdapter } from '..'; import { VideoBackgroundBlurEffect, VideoBackgroundReplacementEffect } from '..'; import { useAdapter } from '../adapter/CallAdapterProvider'; import { isCameraOn } from '../utils'; import { DtmfTone } from '@azure/communication-calling'; import { AddPhoneNumberOptions } from '@azure/communication-calling'; import { Reaction } from '@azure/communication-calling'; import type { BackgroundReplacementConfig, BackgroundBlurConfig, ParticipantCapabilities } from '@azure/communication-calling'; import { CallSurvey, CallSurveyResponse } from '@azure/communication-calling'; import { CommunicationIdentifier, CommunicationUserIdentifier, PhoneNumberIdentifier } from '@azure/communication-common'; import { _toCommunicationIdentifier } from '@internal/acs-ui-common'; import { useSelector } from './useSelector'; import { getCapabilites } from '../selectors/baseSelectors'; type AdapterCommonCallingHandlers = Omit<CommonCallingHandlers, 'onAcceptCall' | 'onRejectCall'>; /** * @private */ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/explicit-function-return-type export const useHandlers = <PropsT>( // eslint-disable-next-line @typescript-eslint/no-unused-vars _component: (props: PropsT) => ReactElement | null ): Pick<AdapterCommonCallingHandlers, CommonProperties<AdapterCommonCallingHandlers, PropsT>> & Partial<_ComponentCallingHandlers> => { const adapter = useAdapter(); const capabilities = useSelector(getCapabilites); return createCompositeHandlers(adapter, capabilities); }; const createCompositeHandlers = memoizeOne( ( adapter: CommonCallAdapter, capabilities?: ParticipantCapabilities ): AdapterCommonCallingHandlers & Partial<_ComponentCallingHandlers> => { return { onCreateLocalStreamView: async (options) => { return await adapter.createStreamView(undefined, options); }, onCreateRemoteStreamView: async (userId, options) => { return await adapter.createStreamView(userId, options); }, onHangUp: async (forEveryone?: boolean) => { await adapter.leaveCall(forEveryone); }, onToggleHold: async () => { return adapter.getState().call?.state === 'LocalHold' ? await adapter.resumeCall() : await adapter.holdCall(); }, onAddParticipant: async ( participant: Partial<CommunicationUserIdentifier & PhoneNumberIdentifier>, options?: AddPhoneNumberOptions ) => { if ('communicationUserId' in participant) { return await adapter.addParticipant(participant as CommunicationUserIdentifier); } else if ('phoneNumber' in participant) { return await adapter.addParticipant(participant as PhoneNumberIdentifier, options); } }, onSendDtmfTone: async (dtmfTone: DtmfTone) => { await adapter.sendDtmfTone(dtmfTone); }, onRemoveParticipant: async (userId: string | CommunicationIdentifier) => { if (typeof userId === 'string') { await adapter.removeParticipant(userId); } else { await adapter.removeParticipant(_toCommunicationIdentifier(userId)); } }, onRaiseHand: async () => { await adapter.raiseHand(); }, onLowerHand: async () => { await adapter.lowerHand(); }, onToggleRaiseHand: async () => { adapter.getState().call?.raiseHand.localParticipantRaisedHand ? await adapter.lowerHand() : await adapter.raiseHand(); }, onReactionClick: async (reaction: Reaction) => { await adapter.onReactionClick(reaction); }, onSelectCamera: async (deviceInfo, options) => { await adapter.setCamera(deviceInfo, options); }, onSelectMicrophone: async (deviceInfo) => { await adapter.setMicrophone(deviceInfo); }, onSelectSpeaker: async (deviceInfo) => { await adapter.setSpeaker(deviceInfo); }, onStartCall: (participants, options?) => { const rawIds = participants.map((participant) => toFlatCommunicationIdentifier(participant)); return adapter.startCall(rawIds, options); }, onStartScreenShare: async () => { await adapter.startScreenShare(); }, onStopScreenShare: async () => { await adapter.stopScreenShare(); }, onToggleCamera: async (options) => { isCameraOn(adapter.getState()) ? await adapter.stopCamera() : await adapter.startCamera(options); }, onToggleMicrophone: async () => { return adapter.getState().call?.isMuted ? await adapter.unmute() : await adapter.mute(); }, onToggleScreenShare: async () => { return adapter.getState().call?.isScreenSharingOn ? await adapter.stopScreenShare() : await adapter.startScreenShare(); }, onStartLocalVideo: async () => { if (adapter.getState().call) { return adapter.startCamera(); } }, onDisposeLocalStreamView: async () => { return adapter.disposeLocalVideoStreamView(); }, onDisposeRemoteStreamView: async (userId) => { return adapter.disposeStreamView(userId); }, onDisposeRemoteScreenShareStreamView: async (userId) => { return adapter.disposeScreenShareStreamView(userId); }, onDisposeLocalScreenShareStreamView: async () => { return adapter.disposeScreenShareStreamView(''); }, onDisposeRemoteVideoStreamView: async (userId) => { return adapter.disposeRemoteVideoStreamView(userId); }, /* @conditional-compile-remove(call-readiness) */ askDevicePermission: async (constrain) => { await adapter.askDevicePermission(constrain); }, onRemoveVideoBackgroundEffects: async () => { return await adapter.stopVideoBackgroundEffects(); }, onBlurVideoBackground: async (backgroundBlurConfig?: BackgroundBlurConfig) => { const blurConfig: VideoBackgroundBlurEffect = { effectName: 'blur', ...backgroundBlurConfig }; return await adapter.startVideoBackgroundEffect(blurConfig); }, onReplaceVideoBackground: async (backgroundReplacementConfig: BackgroundReplacementConfig) => { const replacementConfig: VideoBackgroundReplacementEffect = { effectName: 'replacement', ...backgroundReplacementConfig }; return await adapter.startVideoBackgroundEffect(replacementConfig); }, onStartNoiseSuppressionEffect: async () => { return await adapter.startNoiseSuppressionEffect(); }, onStopNoiseSuppressionEffect: async () => { return await adapter.stopNoiseSuppressionEffect(); }, onStartCaptions: async (options) => { await adapter.startCaptions(options); }, onStopCaptions: async () => { await adapter.stopCaptions(); }, onSetSpokenLanguage: async (language) => { await adapter.setSpokenLanguage(language); }, onSetCaptionLanguage: async (language) => { await adapter.setCaptionLanguage(language); }, onSubmitSurvey: async (survey: CallSurvey): Promise<CallSurveyResponse | undefined> => { return await adapter.submitSurvey(survey); }, onStartSpotlight: async (userIds?: string[]): Promise<void> => { await adapter.startSpotlight(userIds); }, onStopSpotlight: async (userIds?: string[]): Promise<void> => { await adapter.stopSpotlight(userIds); }, onStopAllSpotlight: async (): Promise<void> => { await adapter.stopAllSpotlight(); }, onStartLocalSpotlight: capabilities?.spotlightParticipant.isPresent ? async (): Promise<void> => { await adapter.startSpotlight(); } : undefined, onStopLocalSpotlight: async (): Promise<void> => { await adapter.stopSpotlight(); }, onStartRemoteSpotlight: capabilities?.spotlightParticipant.isPresent ? async (userIds?: string[]): Promise<void> => { await adapter.startSpotlight(userIds); } : undefined, onStopRemoteSpotlight: capabilities?.removeParticipantsSpotlight.isPresent ? async (userIds?: string[]): Promise<void> => { await adapter.stopSpotlight(userIds); } : undefined, onMuteParticipant: async (userId: string): Promise<void> => { await adapter.muteParticipant(userId); }, onMuteAllRemoteParticipants: async (): Promise<void> => { await adapter.muteAllRemoteParticipants(); }, onForbidAudio: capabilities?.forbidOthersAudio?.isPresent ? async (userIds: string[]): Promise<void> => { await adapter.forbidAudio(userIds); } : undefined, onPermitAudio: capabilities?.forbidOthersAudio?.isPresent ? async (userIds: string[]): Promise<void> => { await adapter.permitAudio(userIds); } : undefined, onForbidOthersAudio: capabilities?.forbidOthersAudio?.isPresent ? async (): Promise<void> => { await adapter.forbidOthersAudio(); } : undefined, onPermitOthersAudio: capabilities?.forbidOthersAudio?.isPresent ? async (): Promise<void> => { await adapter.permitOthersAudio(); } : undefined, onForbidVideo: capabilities?.forbidOthersVideo?.isPresent ? async (userIds: string[]): Promise<void> => { await adapter.forbidVideo(userIds); } : undefined, onPermitVideo: capabilities?.forbidOthersVideo?.isPresent ? async (userIds: string[]): Promise<void> => { await adapter.permitVideo(userIds); } : undefined, onForbidOthersVideo: capabilities?.forbidOthersVideo?.isPresent ? async (): Promise<void> => { await adapter.forbidOthersVideo(); } : undefined, onPermitOthersVideo: capabilities?.forbidOthersVideo?.isPresent ? async (): Promise<void> => { await adapter.permitOthersVideo(); } : undefined, /* @conditional-compile-remove(together-mode) */ onCreateTogetherModeStreamView: async (options) => { return await adapter.createTogetherModeStreamView(options); }, /* @conditional-compile-remove(together-mode) */ onStartTogetherMode: async () => { return await adapter.startTogetherMode(); }, /* @conditional-compile-remove(together-mode) */ onSetTogetherModeSceneSize: (width: number, height: number) => { return adapter.setTogetherModeSceneSize(width, height); }, /* @conditional-compile-remove(together-mode) */ onDisposeTogetherModeStreamView: async () => { return await adapter.disposeTogetherModeStreamView(); }, onSendRealTimeText: async (text: string, isFinalized: boolean) => { return await adapter.sendRealTimeText(text, isFinalized); } }; } );