Skip to main content
Version: 0.1.x

Invite Guest on Stage - Android

In this guide, we will see how you can request a viewer to join your livestream by using the changeMode().

note

Before going forward in this guide, do make sure all the attendees join the meeting with mode as VIEWER and the host joins with mode as CONFERENCE

Let's first have a look at how we will be using the PubSub mechanism to acheive the requesting and switching of the participant's mode.

invite-guest-pubsub

Step 1: Loading Viewer List

The host will see a list of participants who have joined as VIEWER along with a button that, when selected, will invite that user to join the livestream.

Here we are using RecyclerView to display viewer list with button.

layout_viewers_list_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#2B3034"
android:id="@+id/layout_participants">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingVertical="15sp"
android:text="Viewer List"
android:textSize="20sp"
android:textColor="@color/white"/>

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvViewersLinearView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="15sp" />

</LinearLayout>
item_viewer_list_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:gravity="center"
android:orientation="horizontal"
android:padding="12dp">


<TextView
android:id="@+id/viewerName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="20sp"
android:textColor="@color/white"/>

<Button
android:id="@+id/btnRequest"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Request to join Stage"
android:textAllCaps="false" />


</LinearLayout>
  • Create a recycler view adapter named ViewerListAdapter which will show the viewer list. Create PeerViewHolder in the adapter which will extend RecyclerView.ViewHolder.
class ViewerListAdapter(items: ArrayList<Participant?>?, private val meeting: Meeting) :
RecyclerView.Adapter<ViewerListAdapter.ViewHolder?>() {
private var viewers = ArrayList<Participant?>()

init {
viewers.addAll(items!!)

// adding Meeting Event listener to get the participant join/leave and panticipant mode change event in the meeting.
meeting.addEventListener(object : MeetingEventListener() {
override fun onParticipantJoined(participant: Participant) {
super.onParticipantJoined(participant)
viewers = ArrayList()
viewers.addAll(allViewers)
notifyDataSetChanged()
}

override fun onParticipantLeft(participant: Participant) {
super.onParticipantLeft(participant)
viewers = ArrayList()
viewers.addAll(allViewers)
notifyDataSetChanged()
}

override fun onParticipantModeChanged(data: JSONObject) {
viewers = ArrayList()
viewers.addAll(allViewers)
notifyDataSetChanged()
}
})
}

private val allViewers: ArrayList<Participant?>
private get() {
val viewerList: ArrayList<Participant?> = ArrayList()
val participants: Iterator<Participant> = meeting.participants.values.iterator()
for (i in 0 until meeting.participants.size) {
val participant = participants.next()
if (participant.mode == "VIEWER") {
viewerList.add(participant)
}
}
return viewerList
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.item_viewer_list_layout, parent, false)
)
}

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val participant = viewers[position]
holder.viewerName.text = viewers[position]!!.displayName
}

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

class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var viewerName: TextView
var btnRequest: Button

init {
viewerName = itemView.findViewById(R.id.viewerName)
btnRequest = itemView.findViewById(R.id.btnRequest)
}
}
}
  • Set this adapter to RecyclerView
btnViewerList.setOnClickListener { openViewerList() }

fun openViewerList() {
val viewerListView: RecyclerView
val bottomSheetDialog = BottomSheetDialog(mContext!!)
val layout_participants = findViewById(R.id.layout_participants)
val v3 = LayoutInflater.from(mContext)
.inflate(R.layout.layout_viewers_list_view, layout_participants)
bottomSheetDialog.setContentView(v3)
viewerListView = v3.findViewById(R.id.rvViewersLinearView)
viewerListView.minimumHeight = 400
bottomSheetDialog.show()
val viewerList: ArrayList<*> = ArrayList<Any?>()
val participants: Iterator<Participant> = meeting!!.participants.values.iterator()
for (i in 0 until meeting!!.participants.size) {
val participant = participants.next()
if (participant.mode == "VIEWER")
viewerList.add(participant)
}
viewerListView.layoutManager = LinearLayoutManager(mContext)
viewerListView.adapter = ViewerListAdapter(viewerList, meeting!!)
viewerListView.setHasFixedSize(true)
}

Step 2: Requesting a Viewer to Join Livestream

We have a Viewer list ready. Now, let us handle the click event for the btnRequest.

We will be using CHANGE_MODE_ + participantId as the topic for PubSub.

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
//...

holder.btnRequest.setOnClickListener { v: View? ->
val pubSubPublishOptions = PubSubPublishOptions()
pubSubPublishOptions.isPersist = false
meeting.pubSub.publish(
"CHANGE_MODE_" + participant!!.id,
participant.id,
pubSubPublishOptions
)
}
}

Step 3: Showing Viewer Request Dialog

After implementing the Host requesting viewer to join the livestream, let's display the viewer's request dialogue and switch the VIEWER mode to CONFERENCE.

meeting!!.addEventListener(object : MeetingEventListener() {
override fun onMeetingJoined() {
val changeModeListener =
PubSubMessageListener { pubSubMessage: PubSubMessage ->
if (pubSubMessage.message == meeting!!.localParticipant.id) {
showRequestDialog(pubSubMessage.senderName)
}
}
meeting!!.pubSub.subscribe("CHANGE_MODE_" + meeting!!.localParticipant.id, changeModeListener)
}
})

private fun showRequestDialog(name: String) {
val builder = AlertDialog.Builder(
mContext!!
)
builder.setMessage("$name has request you to go on stage")
builder.setTitle("Change mode Request")
builder.setCancelable(false)
builder.setPositiveButton("Yes") { dialog: DialogInterface, _: Int ->
meeting!!.changeMode("CONFERENCE")
//...
dialog.dismiss()
}
builder.setNegativeButton(
"No"
) { dialog: DialogInterface, which: Int -> dialog.dismiss() }
val alertDialog = builder.create()
alertDialog.show()
}

Step 4: Pin the participant

We need to pin the participant so that he/she can appears on the livestream. To achieve this, we will listen to the callback on the onParticipantModeChanged of Meeting class.

class ParticipantListAdapter(
items: ArrayList<Participant?>?,
private val meeting: Meeting,
private val context: Context
) : RecyclerView.Adapter<ParticipantListAdapter.ViewHolder>() {
// ...

init {
//...
meeting.addEventListener(object : MeetingEventListener() {
override fun onParticipantJoined(participant: Participant) {
//...
}

override fun onParticipantLeft(participant: Participant) {
// ...
}

override fun onParticipantModeChanged(data: JSONObject) {
//...
val participant = meeting.participants[data.getString("participantId")]
if (data.getString("mode") == "CONFERENCE") {
participant!!.pin("SHARE_AND_CAM")
} else {
participant!!.unpin("SHARE_AND_CAM")
}
}
})
}

//...
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
//...
}
}

API Reference

The API references for all the methods utilized in this guide are provided below.

Got a Question? Ask us on discord