Render Participant - Android
In this guide, we will take a look at how to render the participant's video on the screen.
- Here the participant's video is displayed using
VideoView. Don't render it with your ownSurfaceViewRendererandaddSink(): a remote participant's video may never be drawn that way. - To know more about
VideoView, please visit here
Steps to render participant
Step 1: Create a new layout for the participant view named item_participant.xml in the res/layout folder.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#616161"
tools:layout_height="200dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="#99000000"
android:contentDescription="webcam_turned_off"
android:gravity="center"
android:padding="4dp"
android:src="@drawable/ic_outline_videocam_off_24"
app:tint="@color/white" />
<live.videosdk.rtc.android.VideoView
android:id="@+id/participantView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="#99000000"
android:orientation="horizontal">
<TextView
android:id="@+id/tvName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:padding="4dp"
android:textColor="@color/white" />
</LinearLayout>
</FrameLayout>
Step 2: Now, create a recycler view adapter named ParticipantAdapter which will show the participant list. Create PeerViewHolder in the adapter which will extend RecyclerView.ViewHolder
The SDK does not bring in RecyclerView. Add androidx.recyclerview:recyclerview to your app's dependencies if your app doesn't have it.
class ParticipantAdapter(room: Room) : RecyclerView.Adapter<ParticipantAdapter.PeerViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PeerViewHolder {
return PeerViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.item_participant, parent, false)
)
}
override fun onBindViewHolder(holder: PeerViewHolder, position: Int) {
}
override fun getItemCount(): Int {
return 0
}
class PeerViewHolder(view: View) : RecyclerView.ViewHolder(view) {
// 'VideoView' to show Video Stream
var participantView: VideoView = view.findViewById(R.id.participantView)
var tvName: TextView = view.findViewById(R.id.tvName)
}
}
Step 3: Next, we will render a list of Participant for the room.
We will initialize this list in the constructor of the ParticipantAdapter
class ParticipantAdapter(room: Room) :
RecyclerView.Adapter<ParticipantAdapter.PeerViewHolder>() {
// creating an empty list which will store all participants
private val participants: MutableList<Participant> = ArrayList()
init {
// adding the local participant(You) to the list
participants.add(room.localParticipant)
// adding Room Event listener to get the participant join/leave event in the room.
room.addEventListener(object : RoomEventListener() {
override fun onParticipantJoined(participant: Participant) {
// add participant to the list
participants.add(participant)
notifyItemInserted(participants.size - 1)
}
override fun onParticipantLeft(participant: Participant, reason: LeaveReason) {
var pos = -1
for (i in participants.indices) {
if (participants[i].id == participant.id) {
pos = i
break
}
}
// remove participant from the list
participants.remove(participant)
if (pos >= 0) {
notifyItemRemoved(pos)
}
}
})
}
// replace getItemCount() method with following.
// this method returns the size of total number of participants
override fun getItemCount(): Int {
return participants.size
}
//...
}
Step 4: Now that the participants are listed, set up the view holder to display a participant video.
import videosdk.org.webrtc.VideoTrack
class ParticipantAdapter(room: Room) :
RecyclerView.Adapter<ParticipantAdapter.PeerViewHolder>() {
// replace onBindViewHolder() method with following.
override fun onBindViewHolder(holder: PeerViewHolder, position: Int) {
val participant = participants[position]
holder.tvName.text = participant.displayName
// add Listener to the participant which will update start or stop the video stream of that participant.
// Adding it also calls onStreamEnabled right away for the streams the participant already has,
// so it renders the participant's current video too.
participant.addEventListener(object : ParticipantEventListener() {
override fun onStreamEnabled(stream: RTCStream) {
if (stream.kind == MediaType.VIDEO) {
holder.participantView.visibility = View.VISIBLE
val videoTrack = stream.track as? VideoTrack
holder.participantView.addTrack(videoTrack)
}
}
override fun onStreamDisabled(stream: RTCStream) {
if (stream.kind == MediaType.VIDEO) {
holder.participantView.removeTrack()
holder.participantView.visibility = View.GONE
}
}
})
}
}
RecyclerView reuses holders, so one holder can show different participants as the list scrolls. Before you bind a holder to another participant, call removeTrack() on its VideoView and remove the listener you added for the previous participant with removeEventListener().
Step 5: Final step is to add this adapter to the RoomActivity
override fun onCreate(savedInstanceState: Bundle?) {
//Room setup...
//...
val rvParticipants = findViewById<RecyclerView>(R.id.rvParticipants)
rvParticipants.layoutManager = GridLayoutManager(this, 2)
rvParticipants.adapter = ParticipantAdapter(room!!)
}

Mirror Local Video View
If you wish to show the mirror view of the local participant, call setMirror() on its VideoView with participant.isLocal, so that other participants' tiles are not mirrored when RecyclerView reuses a holder.
It has no effect on your own camera while video effects are on.
class ParticipantAdapter(room: Room) :
RecyclerView.Adapter<ParticipantAdapter.PeerViewHolder>() {
override fun onBindViewHolder(holder: PeerViewHolder, position: Int) {
//...
holder.tvName.text = participant.displayName
holder.participantView.setMirror(participant.isLocal)
//...
}
}
Sample of mirror view video

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

