import { AudioDeviceInfo , VideoDeviceInfo , PermissionConstraints , GroupCallLocator , TeamsMeetingLinkLocator , Call } from '@azure/communication-calling' ; import { VideoStreamOptions } from '@internal/react-components' ; import { ParticipantsJoinedListener , ParticipantsLeftListener , IsMutedChangedListener , CallIdChangedListener , IsLocalScreenSharingActiveChangedListener , DisplayNameChangedListener , IsSpeakingChangedListener , CallAdapter , CallAdapterState , createAzureCommunicationCallAdapter , CallEndedListener } from '../../CallComposite' ; import { MessageReceivedListener , MessageReadListener , ChatAdapter , ChatAdapterState } from '../../ChatComposite' ; import { MeetingAdapter , MeetingEvent } from './MeetingAdapter' ; import { meetingAdapterStateFromBackingStates , MeetingAdapterState , mergeCallAdapterStateIntoMeetingAdapterState , mergeChatAdapterStateIntoMeetingAdapterState } from '../state/MeetingAdapterState' ; import { createAzureCommunicationChatAdapter } from '../../ChatComposite/adapter/AzureCommunicationChatAdapter' ; import { EventEmitter } from 'events' ; import { CommunicationTokenCredential , CommunicationUserIdentifier } from '@azure/communication-common' ; import { toFlatCommunicationIdentifier } from '@internal/acs-ui-common' ; type MeetingAdapterStateChangedHandler = ( newState : MeetingAdapterState ) => void ; /** Context of meeting, which is a centralized context for all state updates */ class MeetingContext { private emitter = new EventEmitter ( ) ; private state : MeetingAdapterState ; constructor ( clientState ) { this . state = clientState ; } public onStateChange ( handler ) { this . emitter . on ( 'stateChanged' , handler ) ; } public offStateChange ( handler ) { this . emitter . off ( 'stateChanged' , handler ) ; } public setState ( state ) { this . state = state ; this . emitter . emit ( 'stateChanged' , this . state ) ; } public getState ( ) { return this . state ; } public updateClientState ( clientState ) { this . setState ( clientState ) ; } public updateClientStateWithChatState ( chatAdapterState ) { this . updateClientState ( mergeChatAdapterStateIntoMeetingAdapterState ( this . state , chatAdapterState ) ) ; } public updateClientStateWithCallState ( callAdapterState ) { this . updateClientState ( mergeCallAdapterStateIntoMeetingAdapterState ( this . state , callAdapterState ) ) ; } } /**
 * Meeting adapter backed by Azure Communication Services.
 * Created for easy use with the Meeting Composite.
 */ export class AzureCommunicationMeetingAdapter implements MeetingAdapter { private callAdapter : CallAdapter ; private chatAdapter : ChatAdapter ; private context : MeetingContext ; private onChatStateChange : ( newChatAdapterState : ChatAdapterState ) => void ; private onCallStateChange : ( newChatAdapterState : CallAdapterState ) => void ; constructor ( callAdapter , chatAdapter ) { this . bindPublicMethods ( ) ; this . callAdapter = callAdapter ; this . chatAdapter = chatAdapter ; this . context = new MeetingContext ( meetingAdapterStateFromBackingStates ( callAdapter , chatAdapter ) ) ; const onChatStateChange = ( newChatAdapterState ) : void => { this . context . updateClientStateWithChatState ( newChatAdapterState ) ; } ; this . chatAdapter . onStateChange ( onChatStateChange ) ; this . onChatStateChange = onChatStateChange ; const onCallStateChange = ( newCallAdapterState ) : void => { this . context . updateClientStateWithCallState ( newCallAdapterState ) ; } ; this . callAdapter . onStateChange ( onCallStateChange ) ; this . onCallStateChange = onCallStateChange ; } private bindPublicMethods ( ) { this . joinMeeting . bind ( this ) ; this . leaveMeeting . bind ( this ) ; this . startMeeting . bind ( this ) ; this . onStateChange . bind ( this ) ; this . offStateChange . bind ( this ) ; this . getState . bind ( this ) ; this . dispose . bind ( this ) ; this . setCamera . bind ( this ) ; this . setMicrophone . bind ( this ) ; this . setSpeaker . bind ( this ) ; this . askDevicePermission . bind ( this ) ; this . queryCameras . bind ( this ) ; this . queryMicrophones . bind ( this ) ; this . querySpeakers . bind ( this ) ; this . startCamera . bind ( this ) ; this . stopCamera . bind ( this ) ; this . mute . bind ( this ) ; this . unmute . bind ( this ) ; this . startScreenShare . bind ( this ) ; this . stopScreenShare . bind ( this ) ; this . removeParticipant . bind ( this ) ; this . createStreamView . bind ( this ) ; this . disposeStreamView . bind ( this ) ; this . fetchInitialData . bind ( this ) ; this . sendMessage . bind ( this ) ; this . sendReadReceipt . bind ( this ) ; this . sendTypingIndicator . bind ( this ) ; this . loadPreviousChatMessages . bind ( this ) ; this . updateMessage . bind ( this ) ; this . deleteMessage . bind ( this ) ; this . on . bind ( this ) ; this . off . bind ( this ) ; } /** Join existing Meeting. */ public joinMeeting ( microphoneOn ? ) { return this . callAdapter . joinCall ( microphoneOn ) ; } /** Leave current Meeting. */ public async leaveMeeting ( ) { await this . chatAdapter . removeParticipant ( toFlatCommunicationIdentifier ( this . chatAdapter . getState ( ) . userId ) ) ; await this . callAdapter . leaveCall ( ) ; } /** Start a new Meeting. */ public startMeeting ( participants ) { return this . callAdapter . startCall ( participants ) ; } param handler public onStateChange ( handler ) { this . context . onStateChange ( handler ) ; } param handler public offStateChange ( handler ) { this . context . offStateChange ( handler ) ; } /** Get current Meeting state. */ public getState ( ) { return this . context . getState ( ) ; } /** Dispose of the current Meeting Adapter. */ public dispose ( ) { this . chatAdapter . offStateChange ( this . onChatStateChange ) ; this . callAdapter . offStateChange ( this . onCallStateChange ) ; this . chatAdapter . dispose ( ) ; this . callAdapter . dispose ( ) ; } /** Remove a participant from the Meeting. */ public async removeParticipant ( userId ) { await this . chatAdapter . removeParticipant ( userId ) ; await this . callAdapter . removeParticipant ( userId ) ; } public async setCamera ( device , options ? ) { await this . callAdapter . setCamera ( device , options ) ; } /** Set the microphone to be used in the meeting. */ public async setMicrophone ( device ) { await this . callAdapter . setMicrophone ( device ) ; } /** Set the speaker to be used in the meeting. */ public async setSpeaker ( device ) { await this . callAdapter . setSpeaker ( device ) ; } public async askDevicePermission ( constraints ) { await this . callAdapter . askDevicePermission ( constraints ) ; } /** Query for available cameras. */ public async queryCameras ( ) { return await this . callAdapter . queryCameras ( ) ; } /** Query for available microphones. */ public async queryMicrophones ( ) { return await this . callAdapter . queryMicrophones ( ) ; } /** Query for available speakers. */ public async querySpeakers ( ) { return await this . callAdapter . querySpeakers ( ) ; } /** Start the camera for the user in the Meeting. */ public async startCamera ( options ? ) { await this . callAdapter . startCamera ( options ) ; } /** Stop the camera for the user in the Meeting. */ public async stopCamera ( ) { await this . callAdapter . stopCamera ( ) ; } /** Mute the user in the Meeting. */ public async mute ( ) { await this . callAdapter . mute ( ) ; } /** Unmute the user in the Meeting. */ public async unmute ( ) { await this . callAdapter . unmute ( ) ; } /** Trigger the user to start screen share. */ public async startScreenShare ( ) { await this . callAdapter . startScreenShare ( ) ; } /** Stop the current active screen share. */ public async stopScreenShare ( ) { await this . callAdapter . stopScreenShare ( ) ; } /** Create a stream view for a remote participants video feed. */ public async createStreamView ( remoteUserId ? , options ? ) { await this . callAdapter . createStreamView ( remoteUserId , options ) ; } /** Dispose of a created stream view of a remote participants video feed. */ public async disposeStreamView ( remoteUserId ? , options ? ) { await this . callAdapter . disposeStreamView ( remoteUserId , options ) ; } /** Fetch initial Meeting data such as chat messages. */ public async fetchInitialData ( ) { await this . chatAdapter . fetchInitialData ( ) ; } /** Send a chat message. */ public async sendMessage ( content ) { await this . chatAdapter . sendMessage ( content ) ; } /** Send a chat read receipt. */ public async sendReadReceipt ( chatMessageId ) { await this . chatAdapter . sendReadReceipt ( chatMessageId ) ; } /** Send an isTyping indicator. */ public async sendTypingIndicator ( ) { await this . chatAdapter . sendTypingIndicator ( ) ; } /** Load previous Meeting chat messages. */ public async loadPreviousChatMessages ( messagesToLoad ) { return await this . chatAdapter . loadPreviousChatMessages ( messagesToLoad ) ; } /** Update an existing message. */ public async updateMessage ( messageId , content ) { return await this . chatAdapter . updateMessage ( messageId , content ) ; } /** Delete an existing message. */ public async deleteMessage ( messageId ) { return await this . chatAdapter . deleteMessage ( messageId ) ; } on ( event , listener ) ; on ( event , listener ) ; on ( event , listener ) ; on ( event , listener ) ; on ( event , listener ) ; on ( event , listener ) ; on ( event , listener ) ; on ( event , listener ) ; on ( event , listener ) ; on ( event , listener ) ; on ( event , listener ) ; on ( event , listener ) ; on ( event , listener ) { switch ( event ) { case 'participantsJoined' : this . callAdapter . on ( event , listener ) ; break ; case 'participantsLeft' : this . callAdapter . on ( 'participantsLeft' , listener ) ; break ; case 'meetingEnded' : this . callAdapter . on ( 'callEnded' , listener ) ; break ; case 'isMutedChanged' : this . callAdapter . on ( 'isMutedChanged' , listener ) ; break ; case 'callIdChanged' : this . callAdapter . on ( 'callIdChanged' , listener ) ; break ; case 'isLocalScreenSharingActiveChanged' : this . callAdapter . on ( 'isLocalScreenSharingActiveChanged' , listener ) ; break ; case 'displayNameChanged' : this . callAdapter . on ( 'displayNameChanged' , listener ) ; break ; case 'isSpeakingChanged' : this . callAdapter . on ( 'isSpeakingChanged' , listener ) ; break ; case 'messageReceived' : this . chatAdapter . on ( 'messageReceived' , listener ) ; break ; case 'messageSent' : this . chatAdapter . on ( 'messageSent' , listener ) ; break ; case 'messageRead' : this . chatAdapter . on ( 'messageRead' , listener ) ; break ; case 'error' : throw 'on(Error) not implemented yet.' ; default : throw `Unknown MeetingEvent: ${ event }` ; } } off ( event , listener ) ; off ( event , listener ) ; off ( event , listener ) ; off ( event , listener ) ; off ( event , listener ) ; off ( event , listener ) ; off ( event , listener ) ; off ( event , listener ) ; off ( event , listener ) ; off ( event , listener ) ; off ( event , listener ) ; off ( event , listener ) ; off ( event , listener ) { switch ( event ) { case 'participantsJoined' : this . callAdapter . off ( event , listener ) ; break ; case 'participantsLeft' : this . callAdapter . off ( 'participantsLeft' , listener ) ; break ; case 'meetingEnded' : this . callAdapter . off ( 'callEnded' , listener ) ; break ; case 'isMutedChanged' : this . callAdapter . off ( 'isMutedChanged' , listener ) ; break ; case 'callIdChanged' : this . callAdapter . off ( 'callIdChanged' , listener ) ; break ; case 'isLocalScreenSharingActiveChanged' : this . callAdapter . off ( 'isLocalScreenSharingActiveChanged' , listener ) ; break ; case 'displayNameChanged' : this . callAdapter . off ( 'displayNameChanged' , listener ) ; break ; case 'isSpeakingChanged' : this . callAdapter . off ( 'isSpeakingChanged' , listener ) ; break ; case 'messageReceived' : this . chatAdapter . off ( 'messageReceived' , listener ) ; break ; case 'messageSent' : this . chatAdapter . off ( 'messageSent' , listener ) ; break ; case 'messageRead' : this . chatAdapter . off ( 'messageRead' , listener ) ; break ; case 'error' : throw 'on(Error) not implemented yet.' ; default : throw `Unknown MeetingEvent: ${ event }` ; } } } /**
 * Arguments for  createAzureCommunicationMeetingAdapter beta export type AzureCommunicationMeetingAdapterArgs = { endpoint : string ; userId : CommunicationUserIdentifier ; displayName : string ; credential : CommunicationTokenCredential ; chatThreadId : string ; callLocator : TeamsMeetingLinkLocator | GroupCallLocator ; } ; beta export const createAzureCommunicationMeetingAdapter = async ( { userId , displayName , credential , endpoint , chatThreadId , callLocator } ) : Promise < MeetingAdapter > => { const callAdapter = await createAzureCommunicationCallAdapter ( { userId , displayName , credential , locator : callLocator } ) ; const chatAdapter = await createAzureCommunicationChatAdapter ( { endpoint , userId , displayName , credential , threadId : chatThreadId } ) ; return new AzureCommunicationMeetingAdapter ( callAdapter , chatAdapter ) ; } ;