Rendering a single track

To demonstrate how to build a UI to render a single video stream, imagine this scenario:

We have a LiveKit Room with three Participants who are constantly streaming a camera feed into the room. In our example, the Participants are not human, but webcams streaming from "Berlin", "New York" and "Tokyo". For unknown reasons, we only want to see the stream from "Tokyo".

We start by creating a new composable and get all the camera tracks with rememberTracks([Track.Source.Camera]). In the returned array of TrackReferences we look for the Tokyo stream. Since we know that all webcam participants are named after their cities, we look for the tokyo participant.

import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import io.livekit.android.compose.state.rememberTracks
import io.livekit.android.room.track.Track
import io.livekit.android.util.flow
@Composable
fun CityVideoRenderer() {
val trackRefs = rememberTracks(listOf(Track.Source.CAMERA))
val tokyoCamTrackRef = trackRefs.find { trackRef ->
trackRef.participant::name.flow.collectAsState().value == "tokyo"
}
// ...
}

Now that we have found the correct stream, we can move on to building the UI to display it. We can do this by using the VideoTrackView composable and passing it the track reference. If the Tokyo track reference is not found, we will display a UI to indicate this instead.

import androidx.compose.foundation.text.BasicText
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import io.livekit.android.compose.state.rememberTracks
import io.livekit.android.compose.ui.VideoTrackView
import io.livekit.android.room.track.Track
import io.livekit.android.util.flow
@Composable
fun CityVideoRenderer() {
val trackRefs = rememberTracks(listOf(Track.Source.CAMERA))
val tokyoCamTrackRef = trackRefs.find { trackRef ->
trackRef.participant::name.flow.collectAsState().value == "tokyo"
}
if (tokyoCamTrackRef != null) {
VideoTrackView(trackReference = tokyoCamTrackRef)
} else {
BasicText(text = "Tokyo is offline")
}
}

With our UI in place, we need to provide rememberTracks with the proper scope to return the tracks of a LiveKit Room. We do this by nesting everything inside a RoomScope.

import androidx.compose.foundation.text.BasicText
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import io.livekit.android.compose.local.RoomScope
import io.livekit.android.compose.state.rememberTracks
import io.livekit.android.compose.ui.VideoTrackView
import io.livekit.android.room.track.Track
import io.livekit.android.util.flow
@Composable
fun CityVideoRenderer() {
val trackRefs = rememberTracks(listOf(Track.Source.CAMERA))
val tokyoCamTrackRef = trackRefs.find { trackRef ->
trackRef.participant::name.flow.collectAsState().value == "tokyo"
}
if (tokyoCamTrackRef != null) {
VideoTrackView(trackReference = tokyoCamTrackRef)
} else {
BasicText(text = "Tokyo is offline")
}
}
@Composable
fun MyPage() {
RoomScope {
CityVideoRenderer()
}
}