Skip to main content
Version: 3.x.x

Manage Participants - Android

1. Local Participant (self)​

The local participant is you: it sends your video and audio streams. It contains information about the local participant such as displayName, id, quality and streams Map.

You can access localParticipant from the meeting object.

Participant object properties​

Property NameTypeDescription
idStringUnique id of the participant.
displayNameStringThe name you define during the meeting initialization.
isLocalBooleanIndicates the participant is local or not.
qualityStringIndicates the participant streams quality.
streamsMap<String, Stream>Returns Video & Audio Streams.

Stream Object properties​

Property NameTypeDescription
idStringUnique id
kindStringStream Kind: audio, video, share or shareAudio.
trackMediaStreamTrack?The videosdk.org.webrtc track. For video and share, it is a VideoTrack.

2. Other Participants (Except You)​

Other participants Map is used to get all the participants (except you) in the meeting at any given time.

Other participants Map contains same properties as LocalParticipant.

Local And Other Participants​

activity_main.xml
<live.videosdk.rtc.android.VideoView
android:id="@+id/localView"
android:layout_width="80dp"
android:layout_height="100dp"
android:layout_gravity="end" />

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvParticipants"
android:layout_width="match_parent"
android:layout_height="match_parent" />
info
  • Here the participant's video is displayed using VideoView. Render video tracks with VideoView.addTrack().
  • Your own camera is shown in one VideoView at a time. If you add your video track to a second VideoView, the first one stops updating.
  • The SDK does not bring in RecyclerView. Add androidx.recyclerview:recyclerview to your app's dependencies.
  • To know more about VideoView, please visit here
MainActivity.kt
import live.videosdk.rtc.android.VideoView
import videosdk.org.webrtc.VideoTrack

private fun displayLocalParticipant() {
var localView: VideoView = findViewById(R.id.localView)

// display local video when stream available
meeting!!.localParticipant.addEventListener(
object : ParticipantEventListener() {
override fun onStreamEnabled(stream: Stream) {
if (stream.kind.equals("video", ignoreCase = true)) {
val videoTrack = stream.track as? VideoTrack ?: return
localView.addTrack(videoTrack)
}
}
}
)
}

private fun displayRemoteParticipants() {
val rvParticipants = findViewById<RecyclerView>(R.id.rvParticipants)
rvParticipants.layoutManager = GridLayoutManager(this, 2)
rvParticipants.adapter = ParticipantAdapter(meeting!!)
}

item_remote_peer.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<live.videosdk.rtc.android.VideoView
android:id="@+id/participantView"
android:layout_width="match_parent"
android:layout_height="match_parent" />

</FrameLayout>
ParticipantAdapter.kt
import videosdk.org.webrtc.VideoTrack

class ParticipantAdapter(meeting: Meeting) : RecyclerView.Adapter<ParticipantAdapter.PeerViewHolder>() {
private val participants: MutableList<Participant> = ArrayList()
private var containerHeight = 0

init {
meeting.addEventListener(object : MeetingEventListener() {
override fun onParticipantJoined(participant: Participant) {
participants.add(participant)
notifyItemInserted(participants.size - 1)
}

override fun onParticipantLeft(participant: Participant, reason: LeaveReason) {
// remove participant from grid
}
})
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PeerViewHolder {
containerHeight = parent.height
return PeerViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.item_remote_peer, parent, false)
)
}

override fun onBindViewHolder(holder: PeerViewHolder, position: Int) {
val participant = participants[position]

val layoutParams = holder.itemView.layoutParams
layoutParams.height = containerHeight / 3
holder.itemView.layoutParams = layoutParams

// Also called right away for each stream the participant already has
participant.addEventListener(object : ParticipantEventListener() {
override fun onStreamEnabled(stream: Stream) {
if (stream.kind.equals("video", ignoreCase = true)) {
val videoTrack = stream.track as? VideoTrack ?: return
holder.participantView.addTrack(videoTrack)
}
}
})
}

override fun getItemCount(): Int {
return participants.size
}

class PeerViewHolder(view: View) : RecyclerView.ViewHolder(view) {
var participantView: VideoView = view.findViewById(R.id.participantView)
}
}

  1. onParticipantJoined - Whenever a new participant joins the meeting, the onParticipantJoined event is triggered. For example, the meeting is running with Alice and Bob, then Eve joins that meeting, after that the onParticipantJoined event is triggered and returns the participant object.

  2. onParticipantLeft - Whenever a participant leaves the meeting, the onParticipantLeft event is triggered. For example, the meeting is running with Alice and Bob, then Bob leaves that meeting, after that the onParticipantLeft event is triggered and returns the participant object and a LeaveReason.

  3. onPresenterChanged - Whenever a participant starts sharing their screen in the meeting, the onPresenterChanged event is triggered and returns the presenter participantId. It returns null when the screen share stops.

  4. onStreamEnabled - Whenever a participant enables their mic or webcam in the meeting, the onStreamEnabled event is triggered and returns Stream.

  5. onStreamDisabled - Whenever a participant disables their mic or webcam in the meeting, the onStreamDisabled event is triggered and returns Stream.

meeting!!.addEventListener(object : MeetingEventListener() {
override fun onParticipantJoined(participant: Participant) {
participant.addEventListener(object : ParticipantEventListener() {
override fun onStreamEnabled(stream: Stream) {
if (stream.kind.equals("video", ignoreCase = true)) {
// participant video enabled
} else if (stream.kind.equals("audio", ignoreCase = true)) {
// participant mic enabled
}
}
override fun onStreamDisabled(stream: Stream) {
if (stream.kind.equals("video", ignoreCase = true)) {
// participant video disabled
} else if (stream.kind.equals("audio", ignoreCase = true)) {
// participant mic disabled
}
}
})
}

override fun onParticipantLeft(participant: Participant, reason: LeaveReason) {
Toast.makeText(this@MainActivity, participant.displayName + " left", Toast.LENGTH_SHORT).show()
}

override fun onPresenterChanged(presenterId: String?) {
if (presenterId != null) {
Toast.makeText(this@MainActivity, presenterId + " started presenting", Toast.LENGTH_SHORT).show()
}
}
})

Got a Question? Ask us on discord