davidliu
Committed by GitHub

Add mirror parameter to VideoRenderer (#218)

... ... @@ -7,6 +7,7 @@
</inspection_tool>
<inspection_tool class="PreviewApiLevelMustBeValid" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true">
<option name="composableFile" value="true" />
... ... @@ -14,6 +15,7 @@
</inspection_tool>
<inspection_tool class="PreviewFontScaleMustBeGreaterThanZero" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewMultipleParameterProviders" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
... ... @@ -29,6 +31,7 @@
</inspection_tool>
<inspection_tool class="PreviewNotSupportedInUnitTestFiles" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewPickerAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
... ...
package io.livekit.android.compose
import android.graphics.Matrix
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.onGloballyPositioned
... ... @@ -18,12 +19,20 @@ import io.livekit.android.room.track.video.ComposeVisibility
fun VideoRenderer(
room: Room,
videoTrack: VideoTrack,
modifier: Modifier = Modifier
modifier: Modifier = Modifier,
mirror: Boolean = false,
) {
val videoSinkVisibility = remember(room, videoTrack) { ComposeVisibility() }
var boundVideoTrack by remember { mutableStateOf<VideoTrack?>(null) }
var view: TextureViewRenderer? by remember { mutableStateOf(null) }
var videoScale by remember { mutableStateOf(1f) }
videoScale = if (mirror) {
-1f
} else {
1f
}
fun cleanupVideoTrack() {
view?.let { boundVideoTrack?.removeRenderer(it) }
... ... @@ -45,6 +54,11 @@ fun VideoRenderer(
}
}
DisposableEffect(view, videoScale) {
view?.scaleX = videoScale
onDispose { }
}
DisposableEffect(room, videoTrack) {
onDispose {
videoSinkVisibility.onDispose()
... ...
... ... @@ -13,28 +13,42 @@ import io.livekit.android.room.participant.Participant
import io.livekit.android.room.track.Track
import io.livekit.android.room.track.VideoTrack
import io.livekit.android.util.flow
import kotlinx.coroutines.flow.*
/**
* This widget primarily serves as a way to observe changes in [videoTracks].
* This widget primarily serves as a way to observe changes in [Participant.videoTracks].
*/
@Composable
fun VideoItemTrackSelector(
room: Room,
participant: Participant,
modifier: Modifier = Modifier
modifier: Modifier = Modifier,
mirror: Boolean = false,
) {
val videoTrackMap by participant::videoTracks.flow.collectAsState(initial = emptyList())
val videoPubs = videoTrackMap.filter { (pub) -> pub.subscribed }
.map { (pub) -> pub }
val videoTrack = videoPubs.firstOrNull { pub -> pub.source == Track.Source.SCREEN_SHARE }?.track as? VideoTrack
?: videoPubs.firstOrNull { pub -> pub.source == Track.Source.CAMERA }?.track as? VideoTrack
?: videoPubs.firstOrNull()?.track as? VideoTrack
if (videoTrack != null) {
// Find the most appropriate video stream to show
// Prioritize screen share, then camera, then any video stream.
val videoPub = videoPubs.firstOrNull { pub -> pub.source == Track.Source.SCREEN_SHARE }
?: videoPubs.firstOrNull { pub -> pub.source == Track.Source.CAMERA }
?: videoPubs.firstOrNull()
val videoTrack = videoPub?.track as? VideoTrack
val videoMuted by
if (videoPub != null) {
videoPub::muted.flow.collectAsState()
} else {
remember(videoPub) {
derivedStateOf { false }
}
}
if (videoTrack != null && !videoMuted) {
VideoRenderer(
room = room,
videoTrack = videoTrack,
mirror = mirror,
modifier = modifier
)
} else {
... ...