Chat during Live Stream - Android
Add real-time audience chat to your live stream with VideoSDK's PubSub class. Whether you’re streaming a webinar, online event, or an interactive session, integrating a chat system lets your viewers engage, ask questions, and react instantly. This guide shows how to build a group or private chat interface for a live stream using the Publish-Subscribe (PubSub) mechanism.
This guide focuses on using PubSub to implement Chat functionality. If you are not familiar with the PubSub mechanism and PubSub class, you can follow this guide.
publish(), subscribe() and unsubscribe() require a joined live stream. They are suspend functions, so call them from a coroutine. Each returns once the server has answered. It throws a VideoSDKException when the live stream is not joined yet (3035), is reconnecting (3065), or the server call fails. The examples below catch it, and open ChatActivity only after the live stream is joined. If you subscribe as part of your join flow, do it from onRoomJoined().
Implementing Chat
Group Chat
- Choose the topic every participant publishes and subscribes to for chat messages. This guide uses
CHAT. - On the send button, publish the message that the sender typed in the
EditTextfield.
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.widget.Toolbar
import live.videosdk.rtc.android.Room
import live.videosdk.rtc.android.lib.VideoSDKException
import live.videosdk.rtc.android.listeners.PubSubMessageListener
import live.videosdk.rtc.android.model.PubSubPublishOptions
import android.text.TextUtils
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
class ChatActivity : AppCompatActivity() {
private lateinit var etmessage: EditText
// Room
var liveStream: Room? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_chat)
etmessage = findViewById(R.id.etMessage)
/**
* Here, we have created 'MainApplication' class, which extends android.app.Application class.
* It has a Room property and getter and setter methods of the Room property.
* In your android manifest, you must declare the class implementing android.app.Application
* (add the android:name=".MainApplication" attribute to the existing application tag):
* In MainActivity.kt, we have set the Room property.
*
* For Example: (MainActivity.kt)
* val room = VideoSDK.createRoom(roomId = roomId, token = token, participantName = participantName, micEnabled = micEnabled, camEnabled = camEnabled)
* (this.application as MainApplication).room = room
*/
// Get Room
liveStream = (this.application as MainApplication).room
findViewById<View>(R.id.btnSend).setOnClickListener { sendMessage() }
}
private fun sendMessage() {
// get message from EditText
val message: String = etmessage.getText().toString()
if (!TextUtils.isEmpty(message)) {
val publishOptions = PubSubPublishOptions(persist = true)
// Sending the Message using the publish method
lifecycleScope.launch {
try {
liveStream!!.pubSub.publish("CHAT", message, publishOptions)
// Clearing the message input
etmessage.setText("")
} catch (e: VideoSDKException) {
Toast.makeText(
this@ChatActivity, "Can't send right now, please try again",
Toast.LENGTH_SHORT
).show()
}
}
} else {
Toast.makeText(
this@ChatActivity, "Please Enter Message",
Toast.LENGTH_SHORT
).show()
}
}
}
- Next step would be to display the messages others send. For this we have to
subscribeto that topic i.eCHATand display all the messages.
class ChatActivity : AppCompatActivity() {
// PubSubMessageListener
val pubSubMessageListener = object : PubSubMessageListener {
override fun onMessageReceived(message: PubSubMessage) {
Log.d("#message", "onMessageReceived: ${message.message}")
}
override fun onOldMessagesReceived(messages: List<PubSubMessage>, info: PubSubHistoryInfo) {
// Persisted message list, delivered in batches
Log.d("#message", "onOldMessagesReceived: $messages")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_chat)
//...
// Subscribe for 'CHAT' topic
lifecycleScope.launch {
try {
liveStream!!.pubSub.subscribe("CHAT", pubSubMessageListener)
} catch (e: VideoSDKException) {
Log.d("#message", "subscribe failed: ${e.code} ${e.message}")
}
}
}
}
- The final step is to unsubscribe from the topic once you no longer need it. Here we unsubscribe from the
CHATtopic when the activity is destroyed.lifecycleScopeis already cancelled whenonDestroy()runs, so the call runs on a scope that outlives the activity.
class ChatActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_chat)
//...
}
override fun onDestroy() {
super.onDestroy()
val room = liveStream ?: return
// Unsubscribe for 'CHAT' topic
MainScope().launch {
try {
room.pubSub.unsubscribe("CHAT", pubSubMessageListener)
} catch (e: VideoSDKException) {
Log.d("#message", "unsubscribe failed: ${e.code} ${e.message}")
}
}
}
}
Private Chat (1:1 between Host and Viewer)
Private messaging is ideal when a host or moderator needs to directly respond to a viewer’s question. This can be achieved using the sendOnly property.
class ChatActivity : AppCompatActivity() {
//..
private fun sendMessage() {
// get message from EditText
val message: String = etmessage.getText().toString()
if (!TextUtils.isEmpty(message)) {
// Pass the participantId of the participant to whom you want to send the message.
val sendOnly: Array<String> = arrayOf("xyz")
val publishOptions = PubSubPublishOptions(persist = true, sendOnly = sendOnly)
// Sending the Message using the publish method
lifecycleScope.launch {
try {
liveStream!!.pubSub.publish("CHAT", message, publishOptions)
// Clearing the message input
etmessage.setText("")
} catch (e: VideoSDKException) {
Log.d("#message", "publish failed: ${e.code} ${e.message}")
}
}
} else {
Toast.makeText(
this@ChatActivity, "Please Enter Message",
Toast.LENGTH_SHORT
).show()
}
}
}
Downloading Chat Messages
All the messages from the PubSub which were published with persist : true can be downloaded as a .csv file. This file will be available in the VideoSDK dashboard as well as through the Sessions API.
API Reference
The API references for all the methods and events utilised in this guide are provided below.
Got a Question? Ask us on discord

