Data Channel - Android
The data channel sends a text or binary message to everyone else in the room. Messages have no topic and are not saved, which makes the data channel lighter than PubSub. It suits frequent updates that only matter at the moment they are sent, such as cursor positions, drawing strokes or game state.
Data channel or PubSub
| Data channel | PubSub | |
|---|---|---|
| Who receives a message | Everyone else in the room | Everyone subscribed to the topic, or only the participants you choose with sendOnly |
| Topics | None | Every message is published to a topic |
| History | None. Participants who join later don't receive earlier messages | Messages published with persist = true are delivered to participants who join later |
| Content | Text or bytes, up to 15 KiB | Text, with an optional JSONObject payload |
| Your own messages | Not delivered back to you | Also delivered to you |
Use PubSub for chat, and for anything a participant who joins later must see. Use the data channel for short-lived updates.
Sending messages
room.send() sends a message to every other participant in the room.
- Pass a
Stringto send text, or aByteArrayto send bytes. A message can be up to 15 KiB. reliabledefaults totrue: the message is resent until it arrives, and messages arrive in the order you sent them. Withreliable = false, the message is sent once. That is faster on a poor network, but the message can be lost, and nothing reports the loss.- It is a
suspendfunction, so call it from a coroutine. It throwsVideoSDKExceptionwhen the message can't be sent. - Only participants in
SEND_AND_RECVmode can send.
private fun sendCursorPosition(x: Float, y: Float) {
val update = JSONObject().put("x", x).put("y", y)
lifecycleScope.launch {
try {
// a lost cursor update is soon replaced by the next one
room.send(update.toString(), reliable = false)
} catch (e: VideoSDKException) {
Log.e("DataChannel", "send failed: ${e.code} ${e.name}")
}
}
}
To send bytes, pass a ByteArray. The receiver gets them as bytes, not as text.
private fun sendStroke(points: FloatArray) {
val buffer = ByteBuffer.allocate(points.size * Float.SIZE_BYTES)
points.forEach { buffer.putFloat(it) }
lifecycleScope.launch {
try {
room.send(buffer.array())
} catch (e: VideoSDKException) {
if (e.error == VideoSDKError.ERROR_PAYLOAD_TOO_LARGE) {
Log.w("DataChannel", "The stroke is larger than 15 KiB. Send it in parts.")
} else {
Log.e("DataChannel", "send failed: ${e.code} ${e.name}")
}
}
}
}
Receiving messages
Messages from other participants arrive on onDataReceived() of your RoomEventListener, one call per message, on the main thread. Each message is a DataMessage that carries either text or bytes, so check isBinary first.
senderId: the participant who sent the message.isBinary:truefor bytes,falsefor text.text: the text, ornullwhenisBinaryistrue.data: the bytes, ornullwhenisBinaryisfalse.reliable:truewhen the sender sent it reliably,falsewhen it was sent once.timestamp: when this device received the message, in milliseconds since the epoch. The sender's clock is not involved, so don't compare it across devices.
private val roomEventListener = object : RoomEventListener() {
override fun onDataReceived(data: DataMessage) {
if (data.isBinary) {
val bytes = data.data ?: return
Log.d("DataChannel", "${data.senderId} sent ${bytes.size} bytes")
} else {
Log.d("DataChannel", "${data.senderId}: ${data.text}")
}
}
}
Errors
send() throws a VideoSDKException with one of these codes:
| Code | Name | When |
|---|---|---|
3035 | ERROR_ACTION_PERFORMED_BEFORE_ROOM_JOINED | The room is not joined. |
3065 | ERROR_ROOM_RECONNECTING | The room is reconnecting. |
3066 | ERROR_ACTION_NOT_SUPPORTED_IN_MODE | The participant is not in SEND_AND_RECV mode. |
3072 | ERROR_PAYLOAD_TOO_LARGE | The message is larger than 15 KiB. |
3048 | ERROR_MEDIA_NOT_READY | There is no connection to send the message on yet. |
3079 | ERROR_OPERATION_TIMED_OUT | The data channel didn't open in time. |
3070 | ERROR_SEND_FAILED | Sending the message failed. |
3035, 3079 and 3070 are also reported on onError(). For more on handling these errors, see Coroutines and Error Handling.
API Reference
The API references for all the methods and events utilized in this guide are provided below.
Got a Question? Ask us on discord

