This documentation is for reference only. We are no longer onboarding new customers to Programmable Video. Existing customers can continue to use the product until December 5, 2026.
We recommend migrating your application to the API provided by our preferred video partner, Zoom. We've prepared this migration guide to assist you in minimizing any service disruption.
In this guide, we will show you how to use the DataTrack API to send messages between Participants connected to a Room. With the DataTrack API you will be able to build powerful collaboration features such as whiteboarding, screen annotations, shared augmented reality apps and more. Use this guide along with our example app Android DataTrack Example to learn about the DataTrack API.
The DataTrack API lets you create a DataTrack channel which can be used to send low latency messages to zero or more receivers subscribed to the data. DataTracks have the following properties.
unidirectional
.
support reliable transmission
. Check out the section on
Configuring DataTrack reliability
.
16KiB
.
string
or
byte
data can be sent over the DataTrack.
In the next section we will show you how to use the DataTrack API with the Android SDK.
The LocalDataTrack is a Track that represents data that can be published to a Room by the LocalParticipant
_10LocalDataTrack localDataTrack = LocalDataTrack.create(context);
Next, we want to connect to a Room with the LocalDataTrack
we created earlier
_10ConnectOptions connectOptions = new ConnectOptions.Builder(token)_10 .dataTracks(Collections.singletonList(localDataTrack))_10 .build();_10Video.connect(context, connectOptions, roomListener);
After connecting to the Room, we now want to publish our LocalDataTrack
to it.
_10LocalParticipant localParticipant = room.getLocalParticipant();_10localParticipant.publish(localDataTrack);
The DataTrack API supports sending string
as well as byte
data.
You can use one of the two variants of send to send a string
or byte
to the Room. DataTracks behave similarly to audio and video Tracks in the sense that, Participants will only receive data that was sent after:
For example, if Alice starts sending a stream of consecutive natural numbers (one number per second), and Bob joins the Room and subscribes to Alice's DataTrack after 5 seconds while Charlie joins the Room and subscribes to Alice's DataTrack after 10 seconds, then Bob will receive all the numbers starting from 6, and Charlie will receive all the numbers starting from 11.
_15public class MyClass implements LocalParticipant.Listener {_15_15 // NOTE: Other LocalParticipant.Listener methods not implemented for brevity_15_15 @Override_15 public void onDataTrackPublished(@NonNull LocalParticipant localParticipant, @NonNull LocalDataTrackPublication localDataTrackPublication) {_15_15 // The data track has been published and is ready for use_15 string message = "hello DataTrack!"_15 localDataTrackPublication.getLocalDataTrack().send(message);_15_15 ByteBuffer messageBuffer = ByteBuffer.wrap(new byte[]{ 0xf, 0xe });_15 localDataTrackPublication.getLocalDataTrack().send(messageBuffer);_15 }_15}
The RemoteParticipant class provides a listener interface. You can implement this interface to listen to published and unpublished DataTrack events.
_23RemoteParticipant.Listener participantListener = new RemoteParticipant.Listener() {_23_23 // Participant has published data track_23 @Override public void onDataTrackPublished(RemoteParticipant_23 remoteParticipant, RemoteDataTrackPublication_23 remoteDataTrackPublication) {}_23_23 // Participant has unpublished data track_23 @Override public void onDataTrackUnpublished(RemoteParticipant_23 remoteParticipant, RemoteDataTrackPublication_23 remoteDataTrackPublication) {}_23_23 // Data track has been subscribed to and messages can be observed._23 @Override public void onDataTrackSubscribed(RemoteParticipant_23 remoteParticipant, RemoteDataTrackPublication_23 remoteDataTrackPublication,RemoteDataTrack remoteDataTrack) {}_23_23 // Data track has been unsubsubscribed from and messages cannot be_23 // observed._23 @Override public void onDataTrackUnsubscribed(RemoteParticipant_23 remoteParticipant, RemoteDataTrackPublication_23 remoteDataTrackPublication, RemoteDataTrack remoteDataTrack) {}_23};
_16RemoteDataTrack.Listener dataTrackListener = new RemoteDataTrack.Listener() {_16_16 @Override_16 public void onMessage(String message) {_16 // Should print "Hello DataTrack!"_16 Log.d(TAG, String.format("Received data track message: %s",_16 message));_16 }_16 }_16_16 @Override_16 public void onMessage(ByteBuffer message) {_16 Log.d(TAG, "Received message buffer on data track!");_16 }_16};_16remoteDataTrack.setListener(dataTrackListener);
Take a look at the Android Quickstart Application to learn more.
DataTracks are intended for low-latency communication between Participants. Importantly, to optimize for lowest latency possible, delivery of DataTrack messages is not guaranteed. You can think of them more like UDP messages, rather than TCP.
You can configure the retry parameters
for your DataTrack with the following options:
maxPacketLifeTime
sets the time in milliseconds during which the DataTrack will transmit or retransmit a message until that message is acknowledged.
maxRetransmits
sets the maximum number of retransmit attempts that will be made.
In Group Rooms, DataTrack connections are established between Participants via the media server. Under the hood, there is one connection between a local Participant to the Media server and a second connection from the Media server to the remote Participant. Twilio's media server configures the same maxPacketLifeTime
value on each remote Participant's connection. Therefore you should set the maxPacketLifetime
to half the acceptable max lifetime for each message you send.