Quickstart: Add Data Channel messaging to your calling app
The Data Channel feature API enables real-time messaging during audio and video calls. In this quickstart guide, we'll illustrate how to integrate the Data Channel feature, enabling the exchange of text messages among participants within a group call. Please note that there are many different messaging solutions other than the Data Channel feature, and you should choose the suitable solution for your specific usage scenario.
Important
Please be aware that our current implementation of the DataChannel feature API doesn't support direct messaging between a web browser and a native app in a peer-to-peer call scenario.
Create a DataChannelSender object
First you need to create a DataChannelSender object to send messages. In this custom messaging application, we suggest assigning a number to channelId
, which serves to distinguish different application use cases. For instance, you can assign channelId
1000 for custom messages.
const dataChannel = call.feature(Features.DataChannel);
const messageSender = dataChannel.createDataChannelSender({
channelId: 1000
});
There are several other options, such as reliability, bandwidth, and priority. You can ignore these for now and use the default values. While the sender object is created, you still need a receiver object to receive messages.
Register a listener to obtain the DataChannelReceiver object
To acquire a receiver object, you need to register a listener that captures the dataChannelReceiverCreated
event.
When a receiver object is created, the SDK emits the event along with the receiver object.
dataChannel.on('dataChannelReceiverCreated', receiver => {
// receiver.channelId
// receiver.senderParticipantIdentifier, which shows the sender id
});
Within the listener callback function, you can access the receiver object and retrieve information such as channelId
and the sender participant ID senderParticipantIdentifier
.
It's your responsibility to maintain the receiver object reference, as the SDK emits the event once for each created receiver object.
Handle messageReady and close event of DataChannelReceiver object
When a message arrives, the DataChannelReceiver object receives the message, stores it in its internal buffer, and emits a messageReady
event.
It's not necessary to register messageReady
event listener to receive messages, as you can always call the readMessage
API at any time.
However, for best practice, we recommend reading message within the messageReady
listener callback, if message processing takes a long time, you can
offload the work to a Web Worker to prevent blocking the message reception.
dataChannel.on('dataChannelReceiverCreated', receiver => {
if (receiver.channelId === 1000) {
receiver.on('close', () => {
console.log(`data channel id = ${receiver.channelId} from ${JSON.stringify(receiver.senderParticipantIdentifier)} is closed`);
});
receiver.on('messageReady', () => {
const message = receiver.readMessage();
// process the message
});
}
});
Set participants
To specify the recipients for your messages, you can use DataChannelSender.setParticipants
API. The sender object maintains the most recent participant list you provide.
The participant type is CommunicationIdentifier
, which you can obtain from remoteParticipant.identifier
. For more information, please refer to Access remote participant properties.
const user = call.remoteParticipants[0]; // assume the user wants to send a message to the first participant in the remoteParticipants list
messageSender.setParticipants([user.identifier]);
Please note that the participant list is limited to 64 participants. If the participant list is an empty array, the SDK broadcasts the message to all participants in the call.
Send and receive messages
DataChannel feature API requires you to pass data as Uint8Array
type. You can't directly send a JavaScript string using sendMessage
API.
For example, if you want to send a string abc
, you can't use sender.sendMessage('abc')
. Instead, you need to serialize the data to a byte buffer first.
const data = (new TextEncoder()).encode('abc');
sender.sendMessage(data);
Here's another example for sending a JSON object.
const obj = {...}; // some object
const data = (new TextEncoder()).encode(JSON.stringify(obj));
sender.sendMessage(data);
Receive and decode the message
dataChannel.on('dataChannelReceiverCreated', receiver => {
if (receiver.channelId === 1000) {
const textDecoder = new TextDecoder();
receiver.on('close', () => {
console.log(`data channel id = ${receiver.channelId} from ${JSON.stringify(receiver.senderParticipantIdentifier)} is closed`);
});
receiver.on('messageReady', () => {
const message = receiver.readMessage();
const text = textDecoder.decode(message.data);
console.log(`from ${JSON.stringify(receiver.senderParticipantIdentifier)}:${text}`);
});
}
});
You can find a complete sample at the following link: https://github.com/Azure-Samples/communication-services-web-calling-tutorial
Important
Please be aware that the current Data Channel feature API doesn't support direct messaging between a web browser and a native app in a peer-to-peer call scenario.
Overview
The Data Channel feature API enables real-time data messaging during audio and video calls. In this quickstart guide, we illustrate how to integrate Data Channel feature to your call and use the Data Channel APIs to send and receive data messages through a data channel.
Prerequisites
Refer to the Voice Calling Quickstart to set up a sample app with voice calling.
Classes
Name | Description |
---|---|
DataChannelCallFeature | Used to start and manage data channel feature. |
DataChannelSender | Used to manage a data channel as a sender and send data. |
DataChannelReceiver | Used to manage a data channel as a receiver and receive data. |
DataChannelSenderOptions | Used for representing options to create a data channel sender. |
Enums
Name | Description |
---|---|
DataChannelPriority | Describes the priority options of data channel. Values: { NORMAL , HIGH }. |
DataChannelReliability | Describes the reliability options of data channel. Values: { LOSSY , DURABLE }. |
Error Code
Name | Description |
---|---|
DATA_CHANNEL_FAILED_TO_START | getDataChannelSender() can fail with this error code, indicating underlying Data Channel is not ready to be used. |
DATA_CHANNEL_RANDOM_ID_NOT_AVAILABLE | getDataChannelSender() can fail with this error code, indicating all available random channel IDs have already been used. |
DATA_CHANNEL_SENDER_CLOSED | sendMessage() can fail with this error code, indicating the sender has already been closed previously. |
DATA_CHANNEL_MESSAGE_SIZE_OVER_LIMIT | sendMessage() can fail with this error code, indicating the message data size exceeds the limit. You can get the message size limit using getMaxMessageSizeInBytes() in DataChannelSender . |
DATA_CHANNEL_MESSAGE_FAILURE_FOR_BANDWIDTH | sendMessage() can fail with this error code, indicating a failure in sending the message due to not enough bandwidth. |
DATA_CHANNEL_MESSAGE_FAILURE_FOR_TRAFFIC_LIMIT | sendMessage() can fail with this error code, indicating a failure in sending the message due to the overall usage of Data Channel not in compliance with the traffic limit rules. Refer to Data Channel Concept Document for details of the traffic limit. |
Methods
Enable Data Channel feature
- Get the ongoing call object established during the prerequisite steps.
- Get the Data Channel Feature object.
DataChannelCallFeature dataChannelCallFeature = call.feature(Features.DATA_CHANNEL);
Receiving data message
- Define the DataChannelReceiverCreatedListener.
DataChannelReceiverCreatedListener receiverCreatedListener = new DataChannelReceiverCreatedListener() {
@Override
public void onReceiverCreated(DataChannelReceiverCreatedEvent e) {
DataChannelReceiver receiver = e.getReceiver(); // get the new data channel receiver
int channelId = receiver.getChannelId(); // get the channel id
CommunicationIdentifier senderId = receiver.getSenderIdentifier(); // get the message sender id
// listen to the message received event and closed event from this receiver
// receiver.addOnMessageReceivedListener(messageReceivedlistener);
// receiver.addOnClosedListener(receiverClosedListener);
}
};
- Register the
receiverCreatedListener
.
dataChannelCallFeature.addOnReceiverCreatedListener(receiverCreatedListener);
- Define the MessageReceivedListener.
MessageReceivedListener messageReceivedListener = new MessageReceivedListener() {
@Override
public void onMessageReceived(PropertyChangedEvent e) {
DataChannelMessage message = e.getReceiver().receiveMessage(); // read the data message from the receiver
int sequence = message.getSequenceNumber(); // get the message sequence number
byte[] data = message.getData(); // get the data content
}
};
- Define the ReceiverClosedListener.
ReceiverClosedListener receiverClosedListener = new ReceiverClosedListener() {
@Override
public void onReceiverClosed(PropertyChangedEvent e) {
DataChannelReceiver receiver = e.getReceiver(); // get the data channel receiver to be closed
}
};
- Register the
messageReceivedListener
andreceiverClosedListener
.
receiver.addOnMessageReceivedListener(messageReceivedlistener);
receiver.addOnClosedListener(receiverClosedListener);
Sending data message
- Configure the DataChannelSenderOptions.
DataChannelSenderOptions options = new DataChannelSenderOptions();
options.setChannelId(1000);
options.setBitrateInKbps(32);
options.setPriority(DataChannelPriority.NORMAL);
options.setReliability(DataChannelReliability.LOSSY);
List<CommunicationIdentifier> participants = Arrays.asList( /* identifier1, identifier2, ... */ );
options.setParticipants(participants);
- Get the DataChannelSender and send data message
DataChannelSender dataChannelSender = dataChannelCallFeature.getDataChannelSender(options);
// msgData contains the byte[] data to be sent
dataChannelSender.sendMessage(msgData);
// change participants in the channel if needed
dataChannelSender.setParticipants(new ArrayList<CommunicationIdentifier>());
Important
Please be aware that the current Data Channel feature API doesn't support direct messaging between a web browser and a native app in a peer-to-peer call scenario.
Overview
The Data Channel feature API enables real-time data messaging during audio and video calls. In this quickstart guide, we illustrate how to integrate Data Channel feature to your call and use the Data Channel APIs to send and receive data messages through a data channel.
Prerequisites
Refer to the Voice Calling Quickstart to set up a sample app with voice calling.
Classes
Name | Description |
---|---|
DataChannelCallFeature | Used to start and manage data channel feature. |
DataChannelSender | Used to manage a data channel as a sender and send data. |
DataChannelReceiver | Used to manage a data channel as a receiver and receive data. |
DataChannelSenderOptions | Used for representing options to create a data channel sender. |
Enums
Name | Description |
---|---|
DataChannelPriority | Describes the priority options of data channel. Values: { normal , high }. |
DataChannelReliability | Describes the reliability options of data channel. Values: { lossy , durable }. |
Error Code
Name | Description |
---|---|
dataChannelFailedToStart | getDataChannelSender() can fail with this error code, indicating underlying Data Channel is not ready to be used. |
dataChannelRandomIdNotAvailable | getDataChannelSender() can fail with this error code, indicating all available random channel IDs have already been used. |
dataChannelSenderClosed | sendMessage() can fail with this error code, indicating the sender has already been closed previously. |
dataChannelMessageSizeOverLimit | sendMessage() can fail with this error code, indicating the message data size exceeds the limit. You can get the message size limit using maxMessageSizeInBytes in DataChannelSender . |
dataChannelMessageFailureForBandwidth | sendMessage() can fail with this error code, indicating a failure in sending the message due to not enough bandwidth. |
dataChannelMessageFailureForTrafficLimit | sendMessage() can fail with this error code, indicating a failure in sending the message due to the overall usage of Data Channel not in compliance with the traffic limit rules. Refer to Data Channel Concept Document for details of the traffic limit. |
Methods
Enable Data Channel feature
- Get the ongoing call object established during the prerequisite steps.
- Get the Data Channel Feature object.
var dataChannelCallFeature = self.call!.feature(Features.dataChannel)
Receiving data message
let featureDelegate = new FeatureDelegate()
let receiverDelegate = new ReceiverDelegate()
dataChannelCallFeature!.delegate = featureDelegate
class FeatureDelegate: NSObject, DataChannelCallFeatureDelegate {
public func dataChannelCallFeature(_ dataChannelCallFeature: DataChannelCallFeature, didCreateReceiver args: DataChannelReceiverCreatedEventArgs) {
let receiver = args.receiver // get the new data channel receiver
let channelId = receiver.channelId // get the channel id
let senderId = receiver.senderIdentifier // get the message sender id
receiver.delegate = receiverDelegate
}
}
class ReceiverDelegate: NSObject, DataChannelReceiverDelegate {
public func dataChannelReceiver(_ dataChannelReceiver: DataChannelReceiver, didReceiveMessage args: PropertyChangedEventArgs) {
let message = dataChannelReceiver.receiveMessage() // read the data message from the receiver
let sequence = message?.sequenceNumber // get the message sequence number
let data = message?.data // get the data content
}
public func dataChannelReceiver(_ dataChannelReceiver: DataChannelReceiver, didClose args: PropertyChangedEventArgs) {
let channelId = dataChannelReceiver.channelId // get the data channel id to be closed
}
}
Sending data message
- Configure the DataChannelSenderOptions.
let options = new DataChannelSenderOptions()
options.channelId = 1000
options.bitrateInKbps = 32
options.priority = DataChannelPriority.normal
options.reliability = DataChannelReliability.lossy
let communicationIdentifiers: [CommunicationIdentifier] = [ /* identifier1, identifier2, ... */ ]
options.participants = communicationIdentifiers
- Define the DataChannelSender and send data message
DataChannelSender sender = dataChannelCallFeature.getDataChannelSender(options)
// msgData contains the data to be sent
sender.sendMessage(msgData)
// change participants in the channel if needed
let participants: [CommunicationIdentifier] = []
dataChannelSender.setParticipants(participants: participants)
Important
Please be aware that the current Data Channel feature API doesn't support direct messaging between a web browser and a native app in a peer-to-peer call scenario.
Overview
The Data Channel feature API enables real-time data messaging during audio and video calls. In this quickstart guide, we illustrate how to integrate Data Channel feature to your call and use the Data Channel APIs to send and receive data messages through a data channel.
Prerequisites
Refer to the Voice Calling Quickstart to set up a sample app with voice calling.
Classes
Name | Description |
---|---|
DataChannelCallFeature | Used to start and manage data channel feature. |
DataChannelSender | Used to manage a data channel as a sender and send data. |
DataChannelReceiver | Used to manage a data channel as a receiver and receive data. |
DataChannelSenderOptions | Used for representing options to create a data channel sender. |
Enums
Name | Description |
---|---|
DataChannelPriority | Describes the priority options of data channel. Values: { Normal , High }. |
DataChannelReliability | Describes the reliability options of data channel. Values: { Lossy , Durable }. |
Error Code
Name | Description |
---|---|
DataChannelFailedToStart | GetDataChannelSender() can fail with this error code, indicating underlying Data Channel is not ready to be used. |
DataChannelRandomIdNotAvailable | GetDataChannelSender() can fail with this error code, indicating all available random channel IDs have already been used. |
DataChannelSenderClosed | SendMessage() can fail with this error code, indicating the sender has already been closed previously. |
DataChannelMessageSizeOverLimit | SendMessage() can fail with this error code, indicating the message data size exceeds the limit. You can get the message size limit using MaxMessageSizeInBytes in DataChannelSender . |
DataChannelMessageFailureForBandwidth | SendMessage() can fail with this error code, indicating a failure in sending the message due to not enough bandwidth. |
DataChannelMessageFailureForTrafficLimit | SendMessage() can fail with this error code, indicating a failure in sending the message due to the overall usage of Data Channel not in compliance with the traffic limit rules. Refer to Data Channel Concept Document for details of the traffic limit. |
Methods
Enable Data Channel feature
- Get the ongoing call object established during the prerequisite steps.
- Get the Data Channel Feature object.
DataChannelCallFeature dataChannelCallFeature = call.Features.DataChannel;
Receiving data message
- Define the DataChannelReceiverCreated event handler.
void DataChannelReceiverCreatedHandler(object sender, DataChannelReceiverCreatedEventArgs args)
{
DataChannelReceiver receiver = args.Receiver; // get the new data channel receiver
int channelId = receiver.ChannelId; // get the channel id
CallIdentifier senderId = receiver.SenderIdentifier; // get the message sender id
// add event handlers for the message received event and closed event from this receiver
// receiver.MessageReceived += MessageReceivedHandler;
// receiver.Closed += ReceiverClosedHandler;
}
- Attach the
DataChannelReceiverCreatedHandler
.
dataChannelCallFeature.ReceiverCreated += DataChannelReceiverCreatedHandler;
- Define the MessageReceived event handler.
void MessageReceivedHandler(object sender, PropertyChangedEventArgs args)
{
DataChannelMessage message = (sender as DataChannelReceiver).ReceiveMessage(); // read the data message from the receiver
long sequence = message.SequenceNumber; // get the message sequence number
byte[] data = message.Data; // get the data content
}
- Define the Closed event handler.
void ReceiverClosedHandler(object sender, PropertyChangedEventArgs args)
{
DataChannelReceiver receiver = sender as DataChannelReceiver; // get the data channel receiver to be closed
};
- Attach the
MessageReceivedHandler
andReceiverClosedHandler
.
receiver.MessageReceived += MessageReceivedHandler;
receiver.Closed += ReceiverClosedHandler;
Sending data message
- Configure the DataChannelSenderOptions.
DataChannelSenderOptions options = new DataChannelSenderOptions();
options.ChannelId = 1000;
options.BitrateInKbps = 32;
options.Priority = DataChannelPriority.Normal;
options.Reliability = DataChannelReliability.Lossy;
var participants = new List<CallIdentifier> { /* identifier1, identifier2, ... */ };
options.Participants = participants.AsReadOnly();
- Define the DataChannelSender and send data message
DataChannelSender sender = dataChannelCallFeature.GetDataChannelSender(options);
// msgData contains the byte[] data to be sent
sender.SendMessage(msgData);
// change participants in the channel if needed
sender.SetParticipants(new List<CallIdentifier>().AsReadOnly());
Next steps
For more information, see the following articles:
- Learn about Data Channel feature concept document
- Learn more about Calling SDK capabilities