Data Channels
LiveSwitch supports data channels for MCU and SFU connections. Data channels support the transfer of binary or text data. You can use data channels to transfer any sort of data outside of the audio or video use case typically associated with RTC. Data channels are not supported for the Media-over-WebSockets protocol.
Note
About the code examples on this page:
- For .NET MAUI and Unity, use the C# code.
- For macOS, use the iOS code.
Platform Support and Interoperability
LiveSwitch supports data channels across all platforms except in the older version of Microsoft Edge which ran on the Trident engine.
Note
Edge Chromium offers full data channel support.
If you are targeting the Trident version of Microsoft Edge, you must detect unsupported browsers for data channels in your Web app code.
Detect Unsupported Browsers
if (fm.liveswitch.Util.isEdge())
{
// DataChannels are not supported as this is the older version of Edge ...
}
If you have a peer offering a data stream as part of the its SDP and a peer who does not, LiveSwitch’s MCU and SFU connections can establish a connection. The Media Server acts as a intermediary for MCU and SFU connections. For data channel interoperability, the Media Server negotiates a data stream for the peer that supports it. In addition, the Media Server negotiates no data stream for the peer that doesn't. Data doesn't flow between peers in this case, but the connection is established, and audio and video flows between the peers normally.
The following table lists connection types that can succeed between peers offering a data stream with the Trident version of Microsoft Edge.
Android (including .NET MAUI) |
iOS (including .NET MAUI) |
.NET | mac OS | Chrome | Firefox | Safari | IE | Edge Chromium | Edge Trident | |
---|---|---|---|---|---|---|---|---|---|---|
Edge Trident | MCU/SFU1 | MCU/SFU1 | MCU/SFU1 | MCU/SFU1 | MCU/SFU1 | MCU/SFU1 | MCU/SFU1 | MCU/SFU1 | MCU/SFU1 | MCU/SFU1 |
Edge Chromium | MCU/SFU/P2P | MCU/SFU/P2P | MCU/SFU/P2P | MCU/SFU/P2P | MCU/SFU/P2P | MCU/SFU/P2P | MCU/SFU/P2P | MCU/SFU/P2P | MCU/SFU/P2P | |
IE | MCU/SFU/P2P | MCU/SFU/P2P | MCU/SFU/P2P | MCU/SFU/P2P | MCU/SFU/P2P | MCU/SFU/P2P | MCU/SFU/P2P | MCU/SFU/P2P | ||
Safari | MCU/SFU/P2P | MCU/SFU/P2P | MCU/SFU/P2P | MCU/SFU/P2P | MCU/SFU/P2P | MCU/SFU/P2P | MCU/SFU/P2P | |||
Firefox | MCU/SFU/P2P | MCU/SFU/P2P | MCU/SFU/P2P | MCU/SFU/P2P | MCU/SFU/P2P | MCU/SFU/P2P | ||||
Chrome | MCU/SFU/P2P | MCU/SFU/P2P | MCU/SFU/P2P | MCU/SFU/P2P | MCU/SFU/P2P | |||||
mac OS | MCU/SFU/P2P | MCU/SFU/P2P | MCU/SFU/P2P | MCU/SFU/P2P | ||||||
.NET | MCU/SFU/P2P | MCU/SFU/P2P | MCU/SFU/P2P | |||||||
iOS (including .NET MAUI) |
MCU/SFU/P2P | MCU/SFU/P2P | ||||||||
Android (including .NET MAUI) |
MCU/SFU/P2P |
1: MCU/SFU: Connections are successful regardless of platform, but peers on the Trident version of Microsoft Edge can't send or receive data sent by others because of the lack of DataChannel
support. Audio or video behaves normally.
P2P Best Practice
P2P connection attempts to a peer on the Trident version of Edge that includes a data stream fail. The best practice is to separate your data stream into a separate P2P connection. This allows you to depend on your P2P audio/video connection when the data stream connection isn't possible.
Create Data Channels
Adding a data channel is straightforward. Create the data channel, wrap it in a data stream, and then provide that stream to your connection object like you would for an audio or video stream. You can have up to 65535 data channels in your data stream. For example, you can have one data stream for chat messages and another for sending spatial data.
If you use multiple channels on the same stream, LiveSwitch matches these channels according to their labels by the peer. You don't need to supply data channels in the same order for all peers.
Note
Data streams are also added to the connection but they aren't used for signalling. For more information, see Signaling Over Data Streams.
Important
Don't create a data channel with a label that starts with fm/
.
For dynamically created channels, if one peer hasn't declared a channel on which another peer attempts to communicate, you can still receive data on that channel by subscribing to the DataStream.OnChannel
and the OnReceive
events of that channel.
DataChannel dataChannel = new DataChannel("my-data-channel");
DataStream dataStream = new DataStream(dataChannel);
McuConnection connection = _Channel.CreateMcuConnection(..., dataStream); // or SFU
Send and Receive Data
A data channel has the following associated states:
- New
- Connecting
- Connected
- Closing
- Closed
- Failed
You can only send or receive data on a data channel that's in the DataChannelState.Connected
state. The other states are can be used to manage your data channel resources, but the Connected
state tells you whether you can use the data channel.
This code shows how to hook into the OnStateChange
event:
DataChannel dataChannel = new DataChannel("my-data-channel");
dataChannel.OnStateChange += (e) =>
{
// States are New, Connecting, Connected, Closing, Closed, Failed
if (e.State == DataChannelState.Connected)
{
...
}
...
};
To receive data on your channel, use the OnReceive
event:
DataChannel dataChannel = new DataChannel("my-data-channel")
{
OnReceive = (dataChannelReceiveArgs) => {
if (dataChannelReceiveArgs.DataString != null)
{
...
}
}
};
To send data on your channel, use the SendDataString
method:
if (dataChannel.State == DataChannelState.Connected)
{
dataChannel.SendDataString("Hello world!");
}
Convert a file into data bytes to send it. To send data bytes, do the following to use the SendDataBytes
method:
- Use
DataBuffer.Wrap
to convert a byte array to aDataBuffer
. - Use
SendDataBytes
to send theDataBuffer
.
if (dataChannel.State == DataChannelState.Connected)
{
byte[] byteArray = { 1, 2, 3 };
dataChannel.SendDataBytes(DataBuffer.Wrap(byteArray));
}
Do the following after receiving files from a DataChannel
:
- Access the
Data
property of theDataBuffer
to get the byte array. - Use these attributes in the
DataBuffer
to get the content relevant to you:- The
Index
attribute, which is the offset to get the actual content. - The
Length
attribute, which is the length of the original byte array.
- The
channel.OnReceive += (messageArgs) =>
{
var dataBytes = messageArgs.DataBytes;
if (dataBytes != null)
{
var bytes = dataBytes.Data; // The payload byte[] might contain extra bytes that are not part of the payload.
var index = dataBytes.Index; // Starting index of the payload’s bytes you want.
var length = dataBytes.Length; // Length of the payload’s bytes you want.
var firstByte = dataBytes.Data[index]; // An example of acccessing the first byte.
}
};