packages/calling-stateful-client/src/TeamsCallAgentDeclarative.ts (82 lines of code) (raw):

// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. import { TeamsCallAgent } from '@azure/communication-calling'; import { TeamsIncomingCall } from '@azure/communication-calling'; import { CallCommon, CallAgentCommon } from './BetaToStableTypes'; import { clearCallRelatedState, DeclarativeCallCommon, ProxyCallAgentCommon } from './CallAgentDeclarativeCommon'; import { CallContext } from './CallContext'; import { _isTeamsCall, _isTeamsCallAgent } from './TypeGuards'; import { InternalCallContext } from './InternalCallContext'; import { teamsCallDeclaratify } from './TeamsCallDeclarative'; /** * @public * Proxies the {@link @azure/communication-calling#TeamsIncomingCall} interface. */ export type TeamsIncomingCallManagement = { /** * @beta * @Remark This attribute doesn't exist on the {@link @azure/communication-calling#TeamsCallAgent} interface. * @returns readonly array of {@link DeclarativeTeamsIncomingCall} */ incomingCalls: ReadonlyArray<TeamsIncomingCall>; }; /** * @public * `DeclarativeTeamsCallAgent` extends and proxies the {@link @azure/communication-calling#TeamsCallAgent} */ export type DeclarativeTeamsCallAgent = TeamsCallAgent & TeamsIncomingCallManagement; /** * ProxyTeamsCallAgent proxies TeamsCallAgent and saves any returned state in the given context. It will subscribe to all state * updates in the TeamsCallAgent and in the contained TeamsCalls and RemoteParticipants. When dispose is called it will * unsubscribe from all state updates. */ class ProxyTeamsCallAgent extends ProxyCallAgentCommon implements ProxyHandler<DeclarativeTeamsCallAgent> { private _callAgent: TeamsCallAgent; constructor(callAgent: TeamsCallAgent, context: CallContext, internalContext: InternalCallContext) { super(context, internalContext); this._callAgent = callAgent; this.subscribe(); } private subscribe = (): void => { this._callAgent.on('callsUpdated', this.callsUpdated); this._callAgent.on('incomingCall', this.incomingCall); // There could be scenario that when ProxyTeamsCallAgent is created that the given CallAgent already has TeamsCalls. In this // case we need to make sure to subscribe to those already existing Calls. for (const call of this._callAgent.calls) { this.addCall(call); } }; protected unsubscribe = (): void => { this._callAgent.off('callsUpdated', this.callsUpdated); this._callAgent.off('incomingCall', this.incomingCall); this.unregisterSubscriber(); }; protected callDeclaratify(call: CallCommon, context: CallContext): DeclarativeCallCommon { if (_isTeamsCall(call)) { return teamsCallDeclaratify(call, context); } throw new Error('Not reachable code, DeclarativeTeamsCallAgent.callDeclaratify must be called with an TeamsCall.'); } protected startCall(agent: TeamsCallAgent, args: Parameters<TeamsCallAgent['startCall']>): CallCommon { if (_isTeamsCallAgent(agent)) { return agent.startCall(...args); } throw new Error('Not reachable code, DeclarativeTeamsCallAgent.startCall must be called with an TeamsCallAgent.'); } protected joinCall(agent: CallAgentCommon, args: Parameters<TeamsCallAgent['join']>): CallCommon { if (_isTeamsCallAgent(agent)) { return agent.join(...args); } throw new Error('Not reachable code, DeclarativeTeamsCallAgent.joinCall must be called with an TeamsCallAgent.'); } protected agentSubscribe(agent: CallAgentCommon, args: Parameters<TeamsCallAgent['on']>): void { if (_isTeamsCallAgent(agent)) { agent.on(...args); return; } throw new Error( 'Not reachable code, DeclarativeTeamsCallAgent.agentSubscribe must be called with an TeamsCallAgent.' ); } protected agentUnsubscribe(agent: CallAgentCommon, args: Parameters<TeamsCallAgent['off']>): void { if (_isTeamsCallAgent(agent)) { agent.off(...args); return; } throw new Error( 'Not reachable code, DeclarativeTeamsCallAgent.agentUnsubscribe must be called with an TeamsCallAgent.' ); } public get<P extends keyof CallAgentCommon>(target: TeamsCallAgent, prop: P): any { return super.getCommon(target, prop); } } /** * Creates a declarative CallAgent by proxying TeamsCallAgent with ProxyTeamsCallAgent which will track state updates by updating * the given context. * * @param callAgent - TeamsCallAgent from SDK * @param context - CallContext from StatefulCallClient * @param internalContext- InternalCallContext from StatefulCallClient */ export const teamsCallAgentDeclaratify = ( callAgent: TeamsCallAgent, context: CallContext, internalContext: InternalCallContext ): DeclarativeTeamsCallAgent => { clearCallRelatedState(context, internalContext); return new Proxy( callAgent, new ProxyTeamsCallAgent(callAgent, context, internalContext) ) as DeclarativeTeamsCallAgent; };