Skip to main content
Version: 3.x.x

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 channelPubSub
Who receives a messageEveryone else in the roomEveryone subscribed to the topic, or only the participants you choose with sendOnly
TopicsNoneEvery message is published to a topic
HistoryNone. Participants who join later don't receive earlier messagesMessages published with persist = true are delivered to participants who join later
ContentText or bytes, up to 15 KiBText, with an optional JSONObject payload
Your own messagesNot delivered back to youAlso 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 String to send text, or a ByteArray to send bytes. A message can be up to 15 KiB.
  • reliable defaults to true: the message is resent until it arrives, and messages arrive in the order you sent them. With reliable = 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 suspend function, so call it from a coroutine. It throws VideoSDKException when the message can't be sent.
  • Only participants in SEND_AND_RECV mode 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: true for bytes, false for text.
  • text: the text, or null when isBinary is true.
  • data: the bytes, or null when isBinary is false.
  • reliable: true when the sender sent it reliably, false when 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:

CodeNameWhen
3035ERROR_ACTION_PERFORMED_BEFORE_ROOM_JOINEDThe room is not joined.
3065ERROR_ROOM_RECONNECTINGThe room is reconnecting.
3066ERROR_ACTION_NOT_SUPPORTED_IN_MODEThe participant is not in SEND_AND_RECV mode.
3072ERROR_PAYLOAD_TOO_LARGEThe message is larger than 15 KiB.
3048ERROR_MEDIA_NOT_READYThere is no connection to send the message on yet.
3079ERROR_OPERATION_TIMED_OUTThe data channel didn't open in time.
3070ERROR_SEND_FAILEDSending 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