VideoItem.kt
3.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/*
* Copyright 2023 LiveKit, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.livekit.android.composesample
import androidx.compose.foundation.layout.Box
import androidx.compose.material.Icon
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import io.livekit.android.composesample.ui.VideoRenderer
import io.livekit.android.room.Room
import io.livekit.android.room.participant.Participant
import io.livekit.android.room.track.CameraPosition
import io.livekit.android.room.track.LocalVideoTrack
import io.livekit.android.room.track.Track
import io.livekit.android.room.track.VideoTrack
import io.livekit.android.sample.common.R
import io.livekit.android.util.flow
/**
* This widget primarily serves as a way to observe changes in [Participant.videoTracks].
*/
@Composable
fun VideoItemTrackSelector(
room: Room,
participant: Participant,
modifier: Modifier = Modifier,
) {
val videoTrackMap by participant::videoTracks.flow.collectAsState(initial = emptyList())
val videoPubs = videoTrackMap.filter { (pub) -> pub.subscribed }
.map { (pub) -> pub }
// 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
var videoMuted by remember { mutableStateOf(false) }
var cameraFacingFront by remember { mutableStateOf(false) }
// monitor muted state
LaunchedEffect(videoPub) {
if (videoPub != null) {
videoPub::muted.flow.collect { muted -> videoMuted = muted }
}
}
// monitor camera facing for local participant
LaunchedEffect(participant, videoTrack) {
if (room.localParticipant == participant && videoTrack as? LocalVideoTrack != null) {
videoTrack::options.flow.collect { options ->
cameraFacingFront = options.position == CameraPosition.FRONT
}
}
}
if (videoTrack != null && !videoMuted) {
VideoRenderer(
room = room,
videoTrack = videoTrack,
mirror = room.localParticipant == participant && cameraFacingFront,
modifier = modifier,
)
} else {
Box(modifier = modifier) {
Icon(
painter = painterResource(id = R.drawable.outline_videocam_off_24),
contentDescription = null,
tint = Color.White,
modifier = Modifier.align(Alignment.Center),
)
}
}
}