Skip to main content
Version: 3.x.x

Selective Subscription - Android

By default, your app receives every participant's mic and webcam as soon as they turn them on. In a large room, most of those webcams are never on screen, yet each one still costs download bandwidth and battery.

With selective subscription, your app receives a participant's mic or webcam only when you ask for it. The participant keeps sending as usual, and everyone else in the room is unaffected.

How it works​

  • Join with autoConsume = false in createRoom(). Your app then receives no participant's mic or webcam until you ask for it.
  • onMediaStatusChanged() tells you when a participant turns their mic, webcam or screen share on or off, even when your app isn't receiving it.
  • consumeMicStreams() and consumeWebcamStreams() start receiving a participant's mic or webcam on this device. When the media arrives, onStreamEnabled() fires as usual.
  • stopConsumingMicStreams() and stopConsumingWebcamStreams() stop receiving it on this device. The participant is not muted, and everyone else still receives them.
  • The four consume methods take effect only when the room was created with autoConsume set to false.

autoConsume covers the mic and the webcam. There is no consume method for screen shares.

Step 1: Join without receiving media​

Pass autoConsume = false to createRoom().

room = VideoSDK.createRoom(
roomId = roomId,
token = token,
participantName = "John Doe",
autoConsume = false,
)

Step 2: Receive the participants you show​

Ask for the media you want from onParticipantJoined(). This event also fires for the participants who were already in the room when you joined. A consume method called while the join is still running waits for the join to finish.

A consume method starts receiving media that is on. If the participant turns their mic or webcam on later, call it again from onMediaStatusChanged(). Ask once per participant and kind: skip a kind that is already arriving in participant.streams or already requested.

The example below receives everyone's mic, so nobody goes unheard, and receives a webcam only while that participant's tile is on screen.

private val roomEventListener = object : RoomEventListener() {
override fun onParticipantJoined(participant: Participant) {
receive(participant, MediaType.AUDIO)
if (isOnScreen(participant)) receive(participant, MediaType.VIDEO)

participant.addEventListener(object : ParticipantEventListener() {
override fun onMediaStatusChanged(participantId: String, kind: MediaType, newStatus: Boolean) {
// they turned their mic or webcam on
if (!newStatus) return
if (kind == MediaType.AUDIO || (kind == MediaType.VIDEO && isOnScreen(participant))) {
receive(participant, kind)
}
}
})
}
}

// one request per participant and kind: skip media already arriving or already asked for
private val requesting = mutableSetOf<Pair<String, MediaType>>()

private fun receive(participant: Participant, kind: MediaType) {
val key = participant.id to kind
if (participant.streams.values.any { it.kind == kind } || !requesting.add(key)) return
lifecycleScope.launch {
try {
when (kind) {
MediaType.AUDIO -> participant.consumeMicStreams()
MediaType.VIDEO -> participant.consumeWebcamStreams()
else -> Unit
}
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Could not receive $kind from ${participant.id}: ${e.code} ${e.name}")
} finally {
requesting.remove(key)
}
}
}

Step 3: Stop receiving media you no longer show​

When a tile scrolls off the screen, stop receiving that participant's webcam. When it comes back, receive it again.

// a tile scrolled off the screen
private fun onTileHidden(participant: Participant) {
lifecycleScope.launch {
try {
participant.stopConsumingWebcamStreams()
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Could not stop receiving video from ${participant.id}: ${e.code} ${e.name}")
}
}
}

// the tile is back on screen
private fun onTileShown(participant: Participant) {
receive(participant, MediaType.VIDEO)
}

When you stop receiving a participant's media, their stream stops arriving on this device, so it looks the same as when they turn it off. To show whether a participant's mic or webcam is on, keep track of onMediaStatusChanged() instead of the streams you receive.

note
  • All four methods are suspend functions. Call them from a coroutine. They throw VideoSDKException when the request fails.
  • Called before join(), or while the room is reconnecting, they report 3035 (ERROR_ACTION_PERFORMED_BEFORE_ROOM_JOINED) or 3065 (ERROR_ROOM_RECONNECTING) on onError and return without throwing. Called while a join is still running, they wait for the join to finish first.
  • They only change what this device receives. To turn a participant's mic or webcam off for everyone, see Remote Participant Media.

Selective subscription works well together with adaptive subscriptions and the other techniques for large rooms.

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