@azure/communication-calling v1.24.3
Azure Communication Calling client library for JavaScript
Get started with Azure Communication Services by using the Communication Services calling client library to add voice and video calling to your app. Read more about Azure Communication Services here
Getting started
Prerequisites
- An Azure account with an active subscription. Create an account for free.
- A deployed Communication Services resource. Create a Communication Services resource.
- A
User Access Token
to enable the call client. For more information on how to get aUser Access Token
- Optional: Complete the quickstart for getting started with adding calling to your application
Setting up
Install the client library
Use the npm install
command to install the Azure Communication Services Calling and Common client libraries for JavaScript.
npm install @azure/communication-common --save
npm install @azure/communication-calling --save
Object model
The following classes and interfaces handle some of the major features of the Azure Communication Services Calling client library:
Name | Description |
---|---|
CallClient | The CallClient is the main entry point to the Calling client library. |
CallAgent | The CallAgent is used to start and manage calls. |
DeviceManager | The DeviceManager is used to manage media devices |
AzureCommunicationTokenCredential | The AzureCommunicationTokenCredential class implements the CommunicationTokenCredential interface which is used to instantiate the CallAgent. |
Initialize the CallClient, create CallAgent, and access DeviceManager
Instantiate a new CallClient
instance. You can configure it with custom options like a Logger instance.
Once a CallClient
is instantiated, you can create a CallAgent
instance by calling the createCallAgent
method on the CallClient
instance. This asynchronously returns a CallAgent
instance object.
The createCallAgent
method takes a CommunicationTokenCredential
as an argument, which accepts a user access token.
// Set the logger's log level
setLogLevel('verbose');
// Redirect logger output to wherever desired. By default it logs to console
AzureLogger.log = (...args) => { console.log(...args) };
const userToken = '<user token>';
callClient = new CallClient(options);
const tokenCredential = new AzureCommunicationTokenCredential(userToken);
const callAgent = await callClient.createCallAgent(tokenCredential, {displayName: 'optional ACS user name'});
const deviceManager = await callClient.getDeviceManager()
Place an outgoing call
To create and start a call you need to use one of the APIs on CallAgent and provide a user that you've created through the Communication Services administration client library.
Call creation and start is synchronous. The Call instance allows you to subscribe to call events.
Place a call
Place a 1:1 call to a user or PSTN
To place a call to another Communication Services user, invoke the startCall
method on callAgent
and pass the callee's CommunicationUserIdentifier that you've created with the Communication Services Administration library.
const userCallee = { communicationUserId: '<ACS_USER_ID>' }
const oneToOneCall = callAgent.startCall([userCallee]);
To place a call to a PSTN, invoke the startCall
method on callAgent
and pass the callee's PhoneNumberIdentifier.
Your Communication Services resource must be configured to allow PSTN calling.
When calling a PSTN number, you must specify your alternate caller ID. An alternate caller Id refers to a phone number (based on the E.164 standard) identifiying the caller in a PSTN Call. For example, when you supply an alternate caller Id to the PSTN call, that phone number will be the one shown to the callee when the call is incoming.
!WARNING PSTN calling is currently in private preview. For access, apply to early adopter program.
const pstnCalee = { phoneNumber: '<ACS_USER_ID>' } const alternateCallerId = {alternateCallerId: '<Alternate caller Id>'}; const oneToOneCall = callAgent.startCall([pstnCallee], {alternateCallerId});
Place a 1:n call with users and PSTN
const userCallee = { communicationUserId: <ACS_USER_ID> }
const pstnCallee = { phoneNumber: <PHONE_NUMBER>};
const alternateCallerId = {alternateCallerId: '<Alternate caller Id>'};
const groupCall = callAgent.startCall([userCallee, pstnCallee], {alternateCallerId});
Place a 1:1 call with video camera
!WARNING There can currently be no more than one outgoing local video stream. To place a video call, you have to enumerate local cameras using the deviceManager
getCameras()
API. Once you select the desired camera, use it to construct aLocalVideoStream
instance and pass it withinvideoOptions
as an item within thelocalVideoStream
array to thestartCall
method. Once your call connects it'll automatically start sending a video stream from the selected camera to the other participant(s). This also applies to the Call.Accept() video options and CallAgent.join() video options.const deviceManager = await callClient.getDeviceManager(); const cameras = await deviceManager.getCameras(); const camera = cameras[0] localVideoStream = new LocalVideoStream(camera); const placeCallOptions = {videoOptions: {localVideoStreams:[localVideoStream]}}; const call = callAgent.startCall(['acsUserId'], placeCallOptions);
### Join a group call
To start a new group call or join an ongoing group call, use the 'join' method
and pass an object with a `groupId` property. The value has to be a GUID.
```js
const context = { groupId: <GUID>}
const call = callAgent.join(context);
Join a Teams Meeting
!NOTE This API is provided as a preview for developers and may change based on feedback that we receive. Do not use this API in a production environment. To use this api please use 'beta' release of ACS Calling Web SDK
To join a Teams meeting, use 'join' method and pass a meeting link or a meeting's coordinates
// Join using meeting link
const locator = { meetingLink: <meeting link>}
const call = callAgent.join(locator);
// Join using meeting coordinates
const locator = {
threadId: <thread id>,
organizerId: <organizer id>,
tenantId: <tenant id>,
messageId: <message id>
}
const call = callAgent.join(locator);
Receiving an incoming call
The CallAgent
instance emits an incomingCall
event when the logged in identity is receiving an incoming call. To listen to this event, subscribe in the following way:
const incomingCallHander = async (args: { incomingCall: IncomingCall }) => {
//Get incoming call id
var incomingCallId = incomingCall.id
// Get information about caller
var callerInfo = incomingCall.callerInfo
// Accept the call
var call = await incomingCall.accept();
// Reject the call
incomingCall.reject();
// Subscribe to callEnded event and get the call end reason
incomingCall.on('callEnded', args => {
console.log(args.callEndReason);
});
// callEndReason is also a property of IncomingCall
var callEndReason = incomingCall.callEndReason;
};
callAgentInstance.on('incomingCall', incomingCallHander);
The incomingCall
event will provide with an instance of IncomingCall
on which you can accept or reject a call.
Call Management
You can access call properties and perform various operations during a call to manage settings related to video and audio.
Call properties
- Get the unique ID (string) for this Call.
const callId: string = call.id;
- To learn about other participants in the call, inspect the
remoteParticipants
collection on thecall
instance. Array contains listRemoteParticipant
objects
const remoteParticipants = call.remoteParticipants;
- The identifier of caller if the call is incoming. Identifier is one of the
CommunicationIdentifier
types
const callerIdentity = call.callerInfo.identifier;
- Get the state of the Call.
const callState = call.state;
This returns a string representing the current state of a call:
- 'None' - initial call state
- 'Connecting' - initial transition state once call is placed or accepted
- 'Ringing' - for an outgoing call - indicates call is ringing for remote participants
- 'EarlyMedia' - indicates a state in which an announcement is played before the call is connected
- 'Connected' - call is connected
- 'LocalHold' - call is put on hold by local participant, no media is flowing between local endpoint and remote participant(s)
- 'RemoteHold' - call is put on hold by remote participant, no media is flowing between local endpoint and remote participant(s)
- 'InLobby' - indicates that user is in lobby
- 'Disconnecting' - transition state before the call goes to 'Disconnected' state
'Disconnected' - final call state
- If network connection is lost, state goes to 'Disconnected' after about 2 minutes.
To see why a given call ended, inspect the
callEndReason
property.
const callEndReason = call.callEndReason;
const callEndReasonCode = callEndReason.code // (number) code associated with the reason
const callEndReasonSubCode = callEndReason.subCode // (number) subCode associated with the reason
- To learn if the current call is an incoming or outgoing call, inspect the
direction
property, it returnsCallDirection
.
const isIncoming = call.direction == 'Incoming';
const isOutgoing = call.direction == 'Outgoing';
- To check if the current microphone is muted, inspect the
isMuted
property, it returnsBoolean
.
const muted = call.isMuted;
- To see if the screen sharing stream is being sent from a given endpoint, check the
isScreenSharingOn
property, it returnsBoolean
.
const isScreenSharingOn = call.isScreenSharingOn;
- To inspect active video streams, check the
localVideoStreams
collection, it containsLocalVideoStream
objects
const localVideoStreams = call.localVideoStreams;
Mute and unmute
To mute or unmute the local endpoint you can use the mute
and unmute
asynchronous APIs:
//mute local device
await call.mute();
//unmute local device
await call.unmute();
Start and stop sending local video
To start a video, you have to enumerate cameras using the getCameras
method on the deviceManager
object. Then create a new instance of LocalVideoStream
passing the desired camera into the startVideo
method as an argument:
const deviceManager = await callClient.getDeviceManager();
const cameras = await deviceManager.getCameras();
const camera = cameras[0]
const localVideoStream = new LocalVideoStream(camera);
await call.startVideo(localVideoStream);
Once you successfully start sending video, a LocalVideoStream
instance will be added to the localVideoStreams
collection on a call instance.
call.localVideoStreams[0] === localVideoStream;
To stop local video, pass the localVideoStream
instance available in the localVideoStreams
collection:
await call.stopVideo(localVideoStream);
You can switch to a different camera device while video is being sent by invoking switchSource
on a localVideoStream
instance:
const cameras = await callClient.getDeviceManager().getCameras();
const camera = cameras[1];
localVideoStream.switchSource(camera);
Remote participants management
All remote participants are represented by RemoteParticipant
type and available through remoteParticipants
collection on a call instance.
List participants in a call
The remoteParticipants
collection returns a list of remote participants in given call:
call.remoteParticipants; // [remoteParticipant, remoteParticipant....]
Remote participant properties
Remote participant has a set of properties and collections associated with it
CommunicationIdentifier
Get the identifier for this remote participant. Identity is one of the 'CommunicationIdentifier' types:
const identifier = remoteParticipant.identifier;
It can be one of 'CommunicationIdentifier' types:
- { communicationUserId: '<ACS_USER_ID'> } - object representing ACS User
- { phoneNumber: '<E.164>' } - object representing phone number in E.164 format
- { microsoftTeamsUserId: '<TEAMS_USER_ID>', isAnonymous?: boolean; cloud?: "public" | "dod" | "gcch" } - object representing Teams user
- { id: '<USER_ID>' } - object repredenting identifier that doesn't fit any of the other identifier types
State
Get state of this remote participant.
const state = remoteParticipant.state;
State can be one of
- 'Idle' - initial state
- 'Connecting' - transition state while participant is connecting to the call
- 'Ringing' - participant is ringing
- 'Connected' - participant is connected to the call
- 'Hold' - participant is on hold
- 'EarlyMedia' - announcement is played before participant is connected to the call
- 'InLobby' - indicates that remote participant is in lobby
- 'Disconnected' - final state - participant is disconnected from the call
- If remote participant loses their network connectivity, then remote participant state goes to 'Disconnected' after about 2 minutes.
Call End reason
To learn why participant left the call, inspect callEndReason
property:
const callEndReason = remoteParticipant.callEndReason;
const callEndReasonCode = callEndReason.code // (number) code associated with the reason
const callEndReasonSubCode = callEndReason.subCode // (number) subCode associated with the reason
Is Muted
To check whether this remote participant is muted or not, inspect isMuted
property, it returns Boolean
const isMuted = remoteParticipant.isMuted;
Is Speaking
To check whether this remote participant is speaking or not, inspect isSpeaking
property it returns Boolean
const isSpeaking = remoteParticipant.isSpeaking;
Video Streams
To inspect all video streams that a given participant is sending in this call, check videoStreams
collection, it contains RemoteVideoStream
objects
const videoStreams = remoteParticipant.videoStreams; // [RemoteVideoStream, ...]
Display Name
To get display name for this remote participant, inspect displayName
property it return string
const displayName = remoteParticipant.displayName;
Add a participant to a call
To add a participant to a call (either a user or a phone number) you can invoke addParticipant
.
Provide one of the 'Identifier' types.
This will synchronously return the remote participant instance.
const userIdentifier = { communicationUserId: <ACS_USER_ID> };
const pstnIdentifier = { phoneNumber: <PHONE_NUMBER>}
const remoteParticipant = call.addParticipant(userIdentifier);
const remoteParticipant = call.addParticipant(pstnIdentifier, {alternateCallerId: '<Alternate Caller ID>'});
Remove participant from a call
To remove a participant from a call (either a user or a phone number) you can invoke removeParticipant
.
You have to pass one of the 'Identifier' types
This will resolve asynchronously once the participant is removed from the call.
The participant will also be removed from the remoteParticipants
collection.
const userIdentifier = { communicationUserId: <ACS_USER_ID> };
const pstnIdentifier = { phoneNumber: <PHONE_NUMBER>}
await call.removeParticipant(userIdentifier);
await call.removeParticipant(pstnIdentifier);
Render remote participant video streams
To list the video streams and screen sharing streams of remote participants, inspect the videoStreams
collections:
const remoteVideoStream: RemoteVideoStream = call.remoteParticipants[0].videoStreams[0];
const streamType: MediaStreamType = remoteVideoStream.mediaStreamType;
To render a RemoteVideoStream
, you have to subscribe to a isAvailableChanged
event.
If the isAvailable
property changes to true
, a remote participant is sending a stream.
Once that happens, create a new instance of VideoStreamRenderer
, and then create a new VideoStreamRendererView
instance using the asynchronous
createView
method. You may then attach view.target
to any UI element.
Whenever availability of a remote stream changes you can choose to destroy the whole VideoStreamRenderer, a specific VideoStreamRendererView
or keep them, but this will result in displaying blank video frame.
function subscribeToRemoteVideoStream(remoteVideoStream: RemoteVideoStream) {
let renderer: VideoStreamRenderer;
const displayVideo = () => {
renderer = new VideoStreamRenderer(remoteVideoStream);
this._streamRenderersMap.set(stream, renderer);
const view = await videoStreamRenderer.createView();
htmlElement.appendChild(view.target);
}
remoteVideoStream.on('isAvailableChanged', async () => {
renderer = this._streamRenderersMap.get(stream);
if (remoteVideoStream.isAvailable && !renderer) {
displayVideo();
} else {
this._streamRenderersMap.delete(stream);
renderer.dispose();
}
});
renderer = this._streamRenderersMap.get(stream);
if (remoteVideoStream.isAvailable && !renderer) {
displayVideo();
}
}
Remote video stream properties
Remote video streams have the following properties:
Id
- ID of a remote video stream
const id: number = remoteVideoStream.id;
MediaStreamType
- can be 'Video' or 'ScreenSharing'
const type: MediaStreamType = remoteVideoStream.mediaStreamType;
isAvailable
- Indicates if remote participant endpoint is actively sending stream
const type: boolean = remoteVideoStream.isAvailable;
VideoStreamRenderer methods and properties
StreamSize
- dimensions ( width/height ) of the renderer
const size: {width: number; height: number} = videoStreamRenderer.size;
- Create a
VideoStreamRendererView
instance that can be later attached in the application UI to render the remote video stream.
videoStreamRenderer.createView()
- Dispose of the videoStreamRenderer and all associated
VideoStreamRendererView
instances.
videoStreamRenderer.dispose()
VideoStreamRendererView methods and properties
When creating a VideoStreamRendererView
you can specify scalingMode
and isMirrored
properties.
Scaling mode can be 'Stretch', 'Crop', or 'Fit'
If isMirrored
is specified, the rendered stream will be flipped vertically.
const videoStreamRendererView: VideoStreamRendererView = videoStreamRenderer.createView({ scalingMode, isMirrored });
Any given VideoStreamRendererView
instance has a target
property that represents the rendering surface. This has to be attached in the application UI:
htmlElement.appendChild(view.target);
You can later update the scaling mode by invoking the updateScalingMode
method.
view.updateScalingMode('Crop')
Device management
DeviceManager
lets you enumerate local devices that can be used in a call to transmit your audio/video streams. It also allows you to request permission from a user to access their microphone and camera using the native browser API.
You can access the deviceManager
by calling callClient.getDeviceManager()
method.
const deviceManager = await callClient.getDeviceManager();
Enumerate local devices
To access local devices, you can use enumeration methods on the Device Manager. Enumeration is an asynchronous action.
// Get a list of available video devices for use.
const localCameras = await deviceManager.getCameras(); // [VideoDeviceInfo, VideoDeviceInfo...]
// Get a list of available microphone devices for use.
const localMicrophones = await deviceManager.getMicrophones(); // [AudioDeviceInfo, AudioDeviceInfo...]
// Get a list of available speaker devices for use.
const localSpeakers = await deviceManager.getSpeakers(); // [AudioDeviceInfo, AudioDeviceInfo...]
Set default microphone/speaker
Device manager allows you to set a default device that will be used when starting a call. If client defaults are not set, Communication Services will fall back to OS defaults.
// Get the microphone device that is being used.
const defaultMicrophone = deviceManager.selectedMicrophone;
// Set the microphone device to use.
await deviceManager.selectMicrophone(localMicrophones[0]);
// Get the speaker device that is being used.
const defaultSpeaker = deviceManager.selectedSpeaker;
// Set the speaker device to use.
await deviceManager.selectSpeaker(localSpeakers[0]);
Local camera preview
You can use DeviceManager
and VideoStreamRenderer
to begin rendering streams from your local camera. This stream won't be sent to other participants; it's a local preview feed. This is an asynchronous action.
const cameras = await deviceManager.getCameras();
const camera = cameras[0];
const localCameraStream = new LocalVideoStream(camera);
const videoStreamRenderer = new VideoStreamRenderer(localCameraStream);
const view = await videoStreamRenderer.createView();
htmlElement.appendChild(view.target);
Request permission to camera/microphone
Prompt a user to grant camera/microphone permissions with the following:
const result = await deviceManager.askDevicePermission({audio: true, video: true});
This will resolve asynchronously with an object indicating if audio
and video
permissions were granted:
console.log(result.audio);
console.log(result.video);
Call recording management
!NOTE This API is provided as a preview for developers and may change based on feedback that we receive. Do not use this API in a production environment. To use this api please use 'beta' release of ACS Calling Web SDK
Call recording is an extended feature of the core Call
API. You first need to obtain the recording feature API object:
const callRecordingApi = call.api(Features.Recording);
Then, to can check if the call is being recorded, inspect the isRecordingActive
property of callRecordingApi
, it returns Boolean
.
const isResordingActive = callRecordingApi.isRecordingActive;
You can also subscribe to recording changes:
const isRecordingActiveChangedHandler = () => {
console.log(callRecordingApi.isRecordingActive);
};
callRecordingApi.on('isRecordingActiveChanged', isRecordingActiveChangedHandler);
Call Transfer management
!NOTE This API is provided as a preview for developers and may change based on feedback that we receive. Do not use this API in a production environment. To use this api please use 'beta' release of ACS Calling Web SDK
Call transfer is an extended feature of the core Call
API. You first need to obtain the transfer feature API object:
const callTransferApi = call.api(Features.Transfer);
Call transfer involves three parties transferor, transferee, and transfer target. Transfer flow is working as following:
- There is already a connected call between transferor and transferee
- transferor decide to transfer the call (transferee -> transfer target)
- transferor call
transfer
API - transferee decide to whether
accept
orreject
the transfer request to transfer target viatransferRequested
event. - transfer target will receive an incoming call only if transferee did
accept
the transfer request
Transfer terminology
- Transferor - The one who initiates the transfer request
- Transferee - The one who is being transferred by the transferor to the transfer target
- Transfer target - The one who is the target that is being transferred to
To transfer current call, you can use transfer
synchronous API. transfer
takes optional TransferCallOptions
which allows you to set disableForwardingAndUnanswered
flag:
disableForwardingAndUnanswered
= false - if transfer target doesn't answer the transfer call, then it will follow the transfer target forwarding and unanswered settingsdisableForwardingAndUnanswered
= true - if transfer target doesn't answer the transfer call, then the transfer attempt will end
// transfer target can be ACS user
const id = { communicationUserId: <ACS_USER_ID> };
// call transfer API
const transfer = callTransferApi.transfer({targetParticipant: id});
Transfer allows you to subscribe to transferStateChanged
and transferRequested
events. transferRequsted
event comes from call
instance, transferStateChanged
event and transfer state
and error
comes from transfer
instance
// transfer state
const transferState = transfer.state; // None | Transferring | Transferred | Failed
// to check the transfer failure reason
const transferError = transfer.error; // transfer error code that describes the failure if transfer request failed
Transferee can accept or reject the transfer request initiated by transferor in transferRequested
event via accept()
or reject()
in transferRequestedEventArgs
. You can access targetParticipant
information, accept
, reject
methods in transferRequestedEventArgs
.
// Transferee to accept the transfer request
callTransferApi.on('transferRequested', args => {
args.accept();
});
// Transferee to reject the transfer request
callTransferApi.on('transferRequested', args => {
args.reject();
});
Dominant speakers of a call
Dominant speakers for a call is an extended feature of the core Call
API and allows you obtain a list of the active speakers in the call.
This is a ranked list, where the first element in the list represents the last active speaker on the call and so on.
In order to obtain the dominant speakers in a call, you first need to obtain the call dominant speakers feature API object:
const callDominantSpeakersApi = call.api(Features.CallDominantSpeakers);
Then, obtain the list of the dominant speakers by calling dominantSpeakers
. This has a type of DominantSpeakersInfo
, which has the following members:
speakersList
contains the list of the ranked dominant speakers in the call. These are represented by their participant id.timestamp
is the latest update time for the dominant speakers in the call.
let dominantSpeakers: DominantSpeakersInfo = callDominantSpeakersApi.dominantSpeakers;
Also, you can subscribe to the dominantSpeakersChanged
event to know when the dominant speakers list has changed
const dominantSpeakersChangedHandler = () => {
// Get the most up to date list of dominant speakers
let dominantSpeakers = callDominantSpeakersApi.dominantSpeakers;
};
callDominantSpeakersApi.api(SDK.Features.CallDominantSpeakers).on('dominantSpeakersChanged', dominantSpeakersChangedHandler);
Handle the Dominant Speaker's video streams
Application can leverage DominantSpeakers feature to render the one or more of dominant speaker's video streams, and keep updating UI whenever dominant speaker list updates. This can be achieved with the following code example.
// RemoteParticipant obj representation of the dominant speaker
let dominantRemoteParticipant: RemoteParticipant;
// It is recommended to use a map to keep track of a stream's associated renderer
let streamRenderersMap: new Map<RemoteVideoStream, VideoStreamRenderer>();
function getRemoteParticipantForDominantSpeaker(dominantSpeakerIdentifier) {
let dominantRemoteParticipant: RemoteParticipant;
switch(dominantSpeakerIdentifier.kind) {
case 'communicationUser': {
dominantRemoteParticipant = currentCall.remoteParticipants.find(rm => {
return (rm.identifier as CommunicationUserIdentifier).communicationUserId === dominantSpeakerIdentifier.communicationUserId
});
break;
}
case 'microsoftTeamsUser': {
dominantRemoteParticipant = currentCall.remoteParticipants.find(rm => {
return (rm.identifier as MicrosoftTeamsUserIdentifier).microsoftTeamsUserId === dominantSpeakerIdentifier.microsoftTeamsUserId
});
break;
}
case 'unknown': {
dominantRemoteParticipant = currentCall.remoteParticipants.find(rm => {
return (rm.identifier as UnknownIdentifier).id === dominantSpeakerIdentifier.id
});
break;
}
}
return dominantRemoteParticipant;
}
// Handler function for when the dominant speaker changes
const dominantSpeakersChangedHandler = async () => {
// Get the new dominant speaker's identifier
const newDominantSpeakerIdentifier = currentCall.api(SDK.Features.DominantSpeakers).dominantSpeakers.speakersList[0];
if (newDominantSpeakerIdentifier) {
// Get the remote participant object that matches newDominantSpeakerIdentifier
const newDominantRemoteParticipant = getRemoteParticipantForDominantSpeaker(newDominantSpeakerIdentifier);
// Create the new dominant speaker's stream renderers
const streamViews = [];
for (const stream of newDominantRemoteParticipant.videoStreams) {
if (stream.isAvailable && !streamRenderersMap.get(stream)) {
const renderer = new VideoStreamRenderer(stream);
streamRenderersMap.set(stream, renderer);
const view = await videoStreamRenderer.createView();
streamViews.push(view);
}
}
// Remove the old dominant speaker's video streams by disposing of their associated renderers
if (dominantRemoteParticipant) {
for (const stream of dominantRemoteParticipant.videoStreams) {
const renderer = streamRenderersMap.get(stream);
if (renderer) {
streamRenderersMap.delete(stream);
renderer.dispose();
}
}
}
// Set the new dominant remote participant obj
dominantRemoteParticipant = newDominantRemoteParticipant
// Render the new dominant remote participant's streams
for (const view of streamViewsToRender) {
htmlElement.appendChild(view.target);
}
}
};
// When call is disconnected, set the dominant speaker to undefined
currentCall.on('stateChanged', () => {
if (currentCall === 'Disconnected') {
dominantRemoteParticipant = undefined;
}
});
const dominantSpeakerIdentifier = currentCall.api(SDK.Features.DominantSpeakers).dominantSpeakers.speakersList[0];
dominantRemoteParticipant = getRemoteParticipantForDominantSpeaker(dominantSpeakerIdentifier);
currentCall.api(SDK.Features.DominantSpeakers).on('dominantSpeakersChanged', dominantSpeakersChangedHandler);
function subscribeToRemoteVideoStream(stream: RemoteVideoStream, participant: RemoteParticipant) {
let renderer: VideoStreamRenderer;
const displayVideo = () => {
renderer = new VideoStreamRenderer(stream);
streamRenderersMap.set(stream, renderer);
const view = await renderer.createView();
htmlElement.appendChild(view.target);
}
stream.on('isAvailableChanged', async () => {
if (dominantRemoteParticipant !== participant) {
return;
}
renderer = streamRenderersMap.get(stream);
if (stream.isAvailable && !renderer) {
displayVideo();
} else {
streamRenderersMap.delete(stream);
renderer.dispose();
}
});
if (dominantRemoteParticipant !== participant) {
return;
}
renderer = streamRenderersMap.get(stream);
if (stream.isAvailable && !renderer) {
displayVideo();
}
}
Eventing model
You have to inspect current values and subscribe to update events for future values.
Properties
// Inspect current value
console.log(object.property);
// Subscribe to value updates
object.on('propertyChanged', () => {
// Inspect new value
console.log(object.property)
});
// Unsubscribe from updates:
object.off('propertyChanged', () => {});
// Example for inspecting call state
console.log(call.state);
call.on('stateChanged', () => {
console.log(call.state);
});
call.off('stateChanged', () => {});
Collections
// Inspect current collection
object.collection.forEach(v => {
console.log(v);
});
// Subscribe to collection updates
object.on('collectionUpdated', e => {
// Inspect new values added to the collection
e.added.forEach(v => {
console.log(v);
});
// Inspect values removed from the collection
e.removed.forEach(v => {
console.log(v);
});
});
// Unsubscribe from updates:
object.off('collectionUpdated', () => {});
// Example for subscribing to remote participants and their video streams
call.remoteParticipants.forEach(p => {
subscribeToRemoteParticipant(p);
})
call.on('remoteParticipantsUpdated', e => {
e.added.forEach(p => { subscribeToRemoteParticipant(p) })
e.removed.forEach(p => { unsubscribeFromRemoteParticipant(p) })
});
function subscribeToRemoteParticipant(p) {
console.log(p.state);
p.on('stateChanged', () => { console.log(p.state); });
p.videoStreams.forEach(v => { subscribeToRemoteVideoStream(v) });
p.on('videoStreamsUpdated', e => { e.added.forEach(v => { subscribeToRemoteVideoStream(v) }) })
}
5 days ago
7 days ago
20 days ago
19 days ago
20 days ago
1 month ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
4 months ago
4 months ago
4 months ago
4 months ago
5 months ago
6 months ago
6 months ago
6 months ago
6 months ago
7 months ago
7 months ago
9 months ago
7 months ago
8 months ago
11 months ago
10 months ago
8 months ago
9 months ago
10 months ago
9 months ago
8 months ago
10 months ago
9 months ago
9 months ago
10 months ago
11 months ago
12 months ago
12 months ago
12 months ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
2 years ago
1 year ago
2 years ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
4 years ago
4 years ago