Code360 powered by Coding Ninjas X Naukri.com. Code360 powered by Coding Ninjas X Naukri.com
Table of contents
1.
Introduction
2.
Prerequisites
3.
Install the Azure Communication Service SDK
4.
Initialize required objects
5.
Manage Calls
5.1.
Place a call
5.1.1.
Place a 1:n call to a user or PSTN
5.1.2.
Join a group call
5.2.
Receive an incoming call
5.3.
Mute and unmute
5.4.
Manage remote participants
5.4.1.
List the participants in a call
5.4.2.
Add a participant to a call
5.4.3.
Remove a participant from a call
5.4.4.
Access remote participant properties
5.5.
Check call properties
6.
Manage Calls for Teams
6.1.
Join a call
6.1.1.
Join a Teams meeting
6.2.
Manage chat thread
7.
Manage video during calls
7.1.
Device management
7.2.
Get local devices
7.3.
Set the default microphone and speaker
7.4.
Local camera preview
7.5.
Request permission to camera and microphone
7.6.
Place a call with a video camera
7.7.
Start and stop sending local video while on a call
7.8.
Render remote participant video streams
7.9.
Remote video stream properties
7.10.
VideoStreamRenderer methods and properties
7.11.
VideoStreamRendererView methods and properties
8.
Frequently Asked Questions
8.1.
What is device management protocol?
8.2.
What is an API?
8.3.
What are the four types of API?
9.
Conclusion
Last Updated: Mar 27, 2024

General Managing Concept with Azure Communication Service SDK

Master Python: Predicting weather forecasts
Speaker
Ashwin Goyal
Product Manager @

Introduction

Azure Communication Services are cloud-based services you can use to incorporate communication into your applications. They come with REST APIs and client library SDKs.

Azure Communication Service SDK

You don't need to be an expert in underlying technologies like video encoding or telephony to add communication to your apps.

Let’s learn about the general managing concepts by managing video calls in Azure Communication Services. In this article, we will discuss how to receive and send voice and video calls, manage the participants and handle their properties.

Source

Prerequisites

To start off, we need the following:

  • An Azure subscription-enabled account.
  • A deployed Communication Services resource.
  • A user access token to enable the calling client.
Get the tech career you deserve, faster!
Connect with our expert counsellors to understand how to hack your way to success
User rating 4.7/5
1:1 doubt support
95% placement record
Akash Pal
Senior Software Engineer
326% Hike After Job Bootcamp
Himanshu Gusain
Programmer Analyst
32 LPA After Job Bootcamp
After Job
Bootcamp

Install the Azure Communication Service SDK

Install the standard JavaScript SDKs and Azure Communication Services calling using the npm install command.

npm install @azure/communication-common --save
npm install @azure/communication-calling --save

Initialize required objects

Most call activities need a CallClient object. Create a fresh instance of CallClient now. It may be customised with unique settings, much like a Logger instance.

By invoking the createCallAgent method on a CallClient instance that you already have, you may create a CallAgent instance. A CallAgent instance object is returned by this function asynchronously.

CommunicationTokenCredential is used in the createCallAgent method's parameter.

A user access token is accepted. To get deviceManager, utilise the getDeviceManager function on the CallClient instance.

const {CallClient} = require('@azure/communication-calling');
const {AzureCommunicationTokenCredential} = require('@azure/communication-common');
const {AzureLogger, setLogLevel} = require("@azure/logger");

setLogLevel('verbose');

AzureLogger.log = (...args) => {
    console.log(...args);
};

const userToken = '<USER_TOKEN>';
callClient = new CallClient(options);
const tokensCredential = new AzureCommunicationTokenCredential(userToken);
const callAgents = await callClient.createCallAgent(tokenCredential, {displayName: 'optional Azure Communication Services user name'});
const devicesManager = await callClient.getDeviceManager()

Manage Calls

Place a call

Use one of the callAgent APIs to make and initiate a call, and supply a user that you've created using the Communication Services identity SDK.

Start-up and call creation are simultaneous. You can subscribe to call events using the call instance.

Place a 1:n call to a user or PSTN

Use the startCall method on callAgent and give the recipient's CommunicationUserIdentifier that you generated using the Communication Services administration library to call another Communication Services user.

Use this code to make a 1:1 call to a user:

const userCallee = {communicationUserId: '<ACS_USER_ID>'};
const oneToOneCall = callAgent.startCall([userCallee]);

Use the startCall method on callAgent with the recipient's PhoneNumberIdentifier to call a public switched telephone network (PSTN). To enable PSTN calling, your Communication Services resource must be set up.

Indicate your alternative caller ID when you dial a PSTN number. A number (based on the E.164 standard) that identifies the caller in a PSTN call is known as an alternative caller ID. It is the phone number that the caller sees when an incoming call comes in.

Use the following code to make a 1:1 call to a PSTN number:

const pstnCallee = { phoneNumber: '<ACS_USER_ID>' }
const alternateCallerId = {alternateCallerId: '<ALTERNATE_CALLER_ID>'};
const oneToOneCall = callAgent.startCall([pstnCallee], {alternateCallerId});

Use the following code to make a 1:n call to a user and a PSTN number:

const userCallee = {communicationUserId: '<ACS_USER_ID>'};
const pstnCallee = {phoneNumber: '<PHONE_NUMBER>'};
const alternateCallerId = {alternateCallerId: '<ALTERNATE_CALLER_ID>'};
const groupCall = callAgent.startCall([userCallee, pstnCallee], {alternateCallerId});

Join a group call

Use the join method and supply an object with a groupId property to initiate a new group call or join one that is already in progress. A GUID must be used as the groupId value.

const context = { groupId: '<GUID>'};
const call = callAgent.join(context);

Receive an incoming call

When the logged-in identity gets an incoming call, the callAgent instance emits an incomingCall event. Subscribe using one of these methods to hear this event:

const incomingCallHandler = async (args: { incomingCall: IncomingCall }) => {
    const incomingCall = args.incomingCall;

    var incomingCallId = incomingCall.id;

    var callerInfo = incomingCall.callerInfo;

    var call = await incomingCall.accept();

    incomingCall.reject();

    incomingCall.on('callEnded', args => {
        console.log(args.callEndReason);
    });

    var callEndReason = incomingCall.callEndReason;
};
callAgentInstance.on('incomingCall', incomingCallHandler);

You can accept or reject the incomingCall instance that is included in the incomingCall event.

Mute and unmute

The mute and unmute asynchronous APIs can be used at the local endpoint:

await call.mute();
await call.unmute();

Manage remote participants

The remoteParticipants collection on a call instance contains all remote participants, who are all represented by the RemoteParticipant type.

List the participants in a call

A list of remote call participants is provided by the remoteParticipants collection:

call.remoteParticipants;

Add a participant to a call

Use addParticipant to include a participant (a user or a phone number) in a call.

One of the Identifier types should be given. Asynchronously, the remoteParticipant instance is returned. When a participant is added to the call successfully, the remoteParticipantsUpdated event from Call is triggered.

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 a participant from a call

You can use the removeParticipant command to remove a caller (a user or a phone number) from the call. One of the Identifier types must be given. When the participant is dropped from the call, this method resolves asynchronously. Additionally, the person is eliminated from the collection of remote participants.

const userIdentifier = {communicationUserId: '<ACS_USER_ID>'};
const pstnIdentifier = {phoneNumber: '<PHONE_NUMBER>'};
await call.removeParticipant(userIdentifier);
await call.removeParticipant(pstnIdentifier);

Access remote participant properties

A number of attributes and collections are related to remote participants:

  • CommunicationIdentifier: Obtain the identification of a distant participant using the communication identifier. One of the CommunicationIdentifier kinds is Identity:
    const identifier = remoteParticipant.identifier;

Any of the following CommunicationIdentifier kinds are possible:

  • { communicationUserId: '<ACS_USER_ID'> }: Object describing the Azure Communication Services user.
  • { phoneNumber: '<E.164>' }: Phone number in E.164 format is represented by the object phoneNumber.
  • { microsoftTeamUserId: '<TEAMS_USER_ID>', isAnonymous?: boolean; cloud?: "public" | "dod" | "gcch" }: An object that symbolises the Teams user.
  • { id: string }: The object known as "id: string" represents an identifier that doesn't fall under one of the other identifier categories.
  • state: Retrieve a remote participant's state.

The state can be:

  • Idle: Initial state.
  • Connecting: While a participant is connected to the call, they are in the connecting state.
  • Ringing: The participant is ringing.
  • Connected: The participant is linked to the call and connected.
  • Hold: Participant is on hold.
  • EarlyMedia: An announcement that plays before a caller connects.
  • InLobby: A remote participant is in the lobby.
  • callEndReason: Check the callEndReason attribute to find out why a caller terminated the call:
    const callEndReason = remoteParticipant.callEndReason;
    const callEndReasonCode = callEndReason.code
    const callEndReasonSubCode = callEndReason.subCode;
  • isMuted status: Verify the isMuted property to see if a remote participant is muted. It gives back Boolean.
  • videoStreams: Check the videoStreams collection to view all video streams that a certain call participant is sending. There are RemoteVideoStream objects in it.

Check call properties

Obtain the call's unique string ID:

const callId: string = call.id;

Obtain details on the call:

const callInfo = call.info;

Examine the remoteParticipants collection on the 'call' instance to find more more about other callers:

const remoteParticipants = call.remoteParticipants;

An incoming call's caller should be identified:

const callerIdentity = call.callerInfo.identifier;

Get a call's status:

const callState = call.state;

By looking at the direction property, you can determine whether the current call is coming in or going out. CallDirection is the response.

const isIncoming = call.direction == 'Incoming';
const isOutgoing = call.direction == 'Outgoing';

Verify whether the active microphone is muted. It gives back Boolean.

const muted = call.isMuted;

Examine the localVideoStreams collection to see which video streams are currently active. LocalVideoStream objects are returned.

const localVideoStreams = call.localVideoStreams;

Manage Calls for Teams

This is basically the same as managing two-end calls, except now we have to handle more users. It shares the same prerequisites and initialization process as managing two-end calls.

Placing a call in a Team is the same as placing a call for two-end users. So is the process to remove participants, check participant properties and add participants. The only differences are in the process of joining a call and the way to handle the Teams chat feature.

Join a call

Join a Teams meeting

Use the join method on callAgent and supply one of the following arguments to join a Teams meeting:

  • meetingLink
  • threadId, organizerId, tenantId, and messageId combined

Join using meetingLink

const meetingCall = callAgent.join({meetingLink: '<MEETING_LINK>'});

Join using the combination of threadId, organizerId, tenantId, and messageId

const meetingCall = callAgent.join({ threadId: '<THREAD_ID>', organizerId: '<ORGANIZER_ID>', tenantId: '<TENANT_ID>', messageId: '<MESSAGE_ID>' });

Manage chat thread

Making calls and adding members to an ongoing call both need the input of a chat ID. The call and chat rosters are kept in sync by developers. ThreadID is used to keep track of the chat between the users. When a Teams user ends a call recording, the recording is included in the thread's chat.

Manage video during calls

Video is an important part of any communication technology. In this section, we will learn how to handle video during a call.

Device management

You need to be familiar with device management in order to start using video with Calling. You can manage what broadcasts audio and video to the call using various devices.

You can list local devices in deviceManager that can send your audio and video streams during a conversation. You can use it to ask for authorization to utilise the local device's cameras and microphones.

Calling the deviceManager will provide you access to callClient.getDeviceManager() method:

const deviceManager = await callClient.getDeviceManager();

Get local devices

You can utilise enumeration methods on deviceManager to access local devices.

const localCameras = await deviceManager.getCameras();
const localMicrophones = await deviceManager.getMicrophones();
const localSpeakers = await deviceManager.getSpeakers();

Set the default microphone and speaker

You can provide a default device in deviceManager that will be used to initiate calls. Operating system defaults are used by Communication Services in the absence of client defaults.

const defaultMicrophone = deviceManager.selectedMicrophone;
await deviceManager.selectMicrophone(localMicrophones[0]);
const defaultSpeaker = deviceManager.selectedSpeaker;
await deviceManager.selectSpeaker(localSpeakers[0]);

Local camera preview

For your local camera to start rendering streams, utilise deviceManager and VideoStreamRenderer. This stream is a local preview feed; it won't be distributed to other participants.

const cameras = await deviceManager.getCameras();
const camera = cameras[0];
const localVideoStream = new LocalVideoStream(camera);
const videoStreamRenderer = new VideoStreamRenderer(localVideoStream);
const view = await videoStreamRenderer.createView();
htmlElement.appendChild(view.target);

Request permission to camera and microphone

Request camera and microphone permissions from the user:

const result = await;
deviceManager.askDevicePermission({audio: true, video: true});

Place a call with a video camera

The getCameras() function in deviceManager must be used to list nearby cameras before placing a video call.

Use the camera you've chosen to build an instance of LocalVideoStream. It is sent to the startCall method as an element of the localVideoStream array in the videoOptions parameter.

const deviceManager = await callClient.getDeviceManager();
const cameras = await deviceManager.getCameras();
const camera = cameras[0];
const localVideoStream = new LocalVideoStream(camera);
const placeCallOptions = {videoOptions: {localVideoStreams:[localVideoStream]}};
const userCallee = {communicationUserId: '<ACS_USER_ID>'};
const call = callAgent.startCall([userCallee], placeCallOptions);

Start and stop sending local video while on a call

You must enumerate cameras using the deviceManager object's getCameras function in order to start a video while on a call. Then, after creating a fresh instance of LocalVideoStream with the required camera, feed the LocalVideoStream object into an already-existing call object's startVideo method:

const deviceManager = await callClient.getDeviceManager();
const cameras = await deviceManager.getCameras();
const camera = cameras[0]
const localVideoStream = new LocalVideoStream(camera);
await call.startVideo(localVideoStream);

A LocalVideoStream instance is added to the localVideoStreams collection on a call instance when you successfully begin sending the video.

call.localVideoStreams[0] === localVideoStream;

Pass the localVideoStream instance from the localVideoStreams collection to a call to halt local video:

await call.stopVideo(localVideoStream);

While a video is being sent, you may change the camera by using switchSource on a localVideoStream instance:

const cameras = await callClient.getDeviceManager().getCameras();
const camera = cameras[1];
localVideoStream.switchSource(camera);

Render remote participant video streams

Examine the videoStreams collections to get a list of the distant participants' video and screen-sharing streams:

const remoteVideoStream: RemoteVideoStream = call.remoteParticipants[0].videoStreams[0];
const streamType: MediaStreamType = remoteVideoStream.mediaStreamType;

You must subscribe to the RemoteVideoStream's isAvailableChanged event in order to render it. A remote participant is transmitting a stream if the value of the isAvailable property switches to true. Create a new instance of VideoStreamRenderer after that, and then use the asynchronous createView function to create a new instance of VideoStreamRendererView.

Any UI element may then have view.target attached to it.

let remoteVideosGallery = document.getElementById('remoteVideosGallery');

subscribeToRemoteVideoStream = async (remoteVideoStream) => {
   let renderer = new VideoStreamRenderer(remoteVideoStream);
    let view;
    let remoteVideoContainer = document.createElement('div');
    remoteVideoContainer.className = 'remote-video-container';

    const createView = async () => {
        view = await renderer.createView();
        remoteVideoContainer.appendChild(view.target);
        remoteVideosGallery.appendChild(remoteVideoContainer);
    }

    remoteVideoStream.on('isAvailableChanged', async () => {
        try {
            if (remoteVideoStream.isAvailable) {
                await createView();
            } else {
                view.dispose();
                remoteVideosGallery.removeChild(remoteVideoContainer);
            }
        } catch (e) {
            console.error(e);
        }
    });

    if (remoteVideoStream.isAvailable) {
        try {
            await createView();
        } catch (e) {
            console.error(e);
        }
    }
   
    console.log(`Initial stream size: height: ${remoteVideoStream.size.height}, width: ${remoteVideoStream.size.width}`);
    remoteVideoStream.on('sizeChanged', () => {
        console.log(`Remote video stream size changed: new height: ${remoteVideoStream.size.height}, new width: ${remoteVideoStream.size.width}`);
    });
}

Remote video stream properties

These features apply to remote video streams:

  • id: The remote video stream's ID.
    const id: number = remoteVideoStream.id;
  • mediaStreamType: Screensharing or video are both possible.
    const type: MediaStreamType = remoteVideoStream.mediaStreamType;
  • isAvailable: Indicates whether a participant endpoint at a distance is now sending a stream.
    const isAvailable: boolean = remoteVideoStream.isAvailable;

VideoStreamRenderer methods and properties

Use the asynchronous createView() method to create a VideoStreamRendererView instance that can be incorporated into the application's user interface to render the remote video stream. It resolves when the stream is prepared to be rendered and returns an object with a target property that represents a video element that can be appended anywhere in the DOM tree.

await videoStreamRenderer.createView();

Get rid of videoStreamRenderer and any connected instances of VideoStreamRendererView:

videoStreamRenderer.dispose();

VideoStreamRendererView methods and properties

The scalingMode and isMirrored attributes can be specified when creating a VideoStreamRendererView. scalingMode has three options: Stretch, Crop, and Fit. The rendered stream is inverted vertically if the isMirrored parameter is provided.

const videoStreamRendererView: VideoStreamRendererView = await videoStreamRenderer.createView({scalingMode, isMirrored});

The rendering surface is represented by the target attribute of each VideoStreamRendererView instance. Add this attribute to the UI of the application:

htmlElement.appendChild(view.target);

By using the updateScalingMode method, you may update scalingMode:

view.updateScalingMode('Crop');

Frequently Asked Questions

What is device management protocol?

Using the Device Management Protocol, a device may exchange location updates, diagnostic data, and fault codes. Using the user interface or the REST API, you may remove a device from the Platform Service after it is decommissioned.

What is an API?

An API is a kind of intermediary software agent that enables the communication between related apps. APIs offer a collection of protocols, procedures, and developer tools that allow programmers to extract and exchange data and enable programmes to communicate openly.

What are the four types of API?

Public, partner, private, and composite are the four primary forms of API that are frequently used in web-based applications. The "type" of the API, in this case, denotes the intended application.

Conclusion

This article discusses general managing concepts with Azure Communication Service SDK by taking the case of calls. We discuss how to receive and send voice and video calls, manage the participants and handle their properties.

Refer to our guided paths on Coding Ninjas Studio to upskill yourself in Data Structures and AlgorithmsCompetitive ProgrammingJavaScriptSystem Design, and many more! If you want to test your competency in coding, you may check out the mock test series and participate in the contests hosted on Coding Ninjas Studio! But if you have just started your learning process and looking for questions asked by tech giants like Amazon, Microsoft, Uber, etc; you must have a look at the problemsinterview experiences, and interview bundle for placement preparations.

Nevertheless, you may consider our paid courses to give your career an edge over others!

Do upvote our blogs if you find them helpful and engaging!

Happy Learning!

Previous article
Advance concepts of Azure Communication Service
Next article
Azure Cosmos DB
Live masterclass