Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/eleven-mice-fry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"components-android": patch
---

Remove Immutable annotation from TrackReference as the contained objects are not immutable
5 changes: 5 additions & 0 deletions .changeset/eleven-phones-buy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"components-android": minor
---

Change the LocalMedia API to use setEnabled rather than start/stop methods to make clear that they are idempotent.
5 changes: 5 additions & 0 deletions .changeset/real-jars-wait.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"components-android": patch
---

Fix rememberLiveKitRoom disabling audio/video if enabled from outside the composable
5 changes: 5 additions & 0 deletions .changeset/small-ravens-help.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"components-android": patch
---

Fix isDeviceEnabled states not properly updating
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,9 @@ fun rememberLiveKitRoom(
val audioOnce = remember(connect, audio) {
var once = true
val ret: suspend CoroutineScope.(Room, Room.State) -> Unit = { r: Room, _: Room.State ->
if (once) {
if (once && audio) {
once = false
r.localParticipant.setMicrophoneEnabled(audio)
r.localParticipant.setMicrophoneEnabled(true)
}
}
return@remember ret
Expand All @@ -188,9 +188,9 @@ fun rememberLiveKitRoom(
val videoOnce = remember(connect, video) {
var once = true
val ret: suspend CoroutineScope.(Room, Room.State) -> Unit = { r: Room, _: Room.State ->
if (once) {
if (once && video) {
once = false
r.localParticipant.setCameraEnabled(video)
r.localParticipant.setCameraEnabled(true)
}
}
return@remember ret
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package io.livekit.android.compose.state
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
Expand All @@ -39,13 +40,17 @@ import io.livekit.android.room.track.Track
import io.livekit.android.room.track.screencapture.ScreenCaptureParams
import io.livekit.android.room.track.video.CameraCapturerUtils
import io.livekit.android.util.LKLog
import io.livekit.android.util.flow
import livekit.org.webrtc.CameraEnumerator

@Beta
internal class LocalMediaImpl(
microphoneTrackState: State<TrackReference?>,
cameraTrackState: State<TrackReference?>,
screenShareTrackState: State<TrackReference?>,
isMicrophoneEnabledState: State<Boolean>,
isCameraEnabledState: State<Boolean>,
isScreenShareEnabledState: State<Boolean>,
audioDevicesState: SnapshotStateList<AudioDevice>,
cameraDevicesState: SnapshotStateList<String>,
selectedAudioDeviceState: State<AudioDevice?>,
Expand All @@ -63,12 +68,9 @@ internal class LocalMediaImpl(
override val cameraTrack by cameraTrackState
override val screenShareTrack by screenShareTrackState

override val isMicrophoneEnabled: Boolean
get() = microphoneTrack?.isSubscribed() == true && microphoneTrack?.publication?.muted == false
override val isCameraEnabled: Boolean
get() = cameraTrack?.isSubscribed() == true && cameraTrack?.publication?.muted == false
override val isScreenShareEnabled: Boolean
get() = screenShareTrack?.isSubscribed() == true && screenShareTrack?.publication?.muted == false
override val isMicrophoneEnabled by isMicrophoneEnabledState
override val isCameraEnabled by isCameraEnabledState
override val isScreenShareEnabled by isScreenShareEnabledState

override val audioDevices = audioDevicesState
override val cameraDevices = cameraDevicesState
Expand All @@ -77,28 +79,16 @@ internal class LocalMediaImpl(
override val selectedCameraId by selectedCameraState
override val cameraCanSwitchPosition by canSwitchPositionState

override suspend fun startMicrophone() {
setMicrophoneFn(true)
override suspend fun setMicrophoneEnabled(enabled: Boolean) {
setMicrophoneFn(enabled)
}

override suspend fun stopMicrophone() {
setMicrophoneFn(false)
override suspend fun setCameraEnabled(enabled: Boolean) {
setCameraFn(enabled)
}

override suspend fun startCamera() {
setCameraFn(true)
}

override suspend fun stopCamera() {
setCameraFn(false)
}

override suspend fun startScreenShare(params: ScreenCaptureParams) {
setScreenShareFn(true, params)
}

override suspend fun stopScreenShare() {
setScreenShareFn(false, null)
override suspend fun setScreenShareEnabled(enabled: Boolean, params: ScreenCaptureParams?) {
setScreenShareFn(enabled, params)
}

override fun selectAudioDevice(audioDevice: AudioDevice) {
Expand Down Expand Up @@ -143,6 +133,10 @@ fun rememberLocalMedia(room: Room? = null): LocalMedia {
derivedStateOf { localScreenShareTrack.firstOrNull() }
}

val isMicrophoneEnabledState = room.localParticipant::isMicrophoneEnabled.flow.collectAsState()
val isCameraEnabledState = room.localParticipant::isCameraEnabled.flow.collectAsState()
val isScreenShareEnabledState = room.localParticipant::isScreenShareEnabled.flow.collectAsState()

// Audio
val selectedAudioDeviceState = remember {
mutableStateOf(room.audioSwitchHandler?.selectedAudioDevice)
Expand Down Expand Up @@ -258,6 +252,9 @@ fun rememberLocalMedia(room: Room? = null): LocalMedia {
selectCameraFn = selectCameraFn,
switchCameraFn = switchCameraFn,
cameraEnumerator = enumerator,
isMicrophoneEnabledState = isMicrophoneEnabledState,
isCameraEnabledState = isCameraEnabledState,
isScreenShareEnabledState = isScreenShareEnabledState,
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,37 +88,24 @@ abstract class LocalMedia {
internal abstract val cameraEnumerator: CameraEnumerator

/**
* Starts the microphone track and publishes it if needed.
* Enables/disables the microphone track and publishes it if needed.
*/
abstract suspend fun startMicrophone()
abstract suspend fun setMicrophoneEnabled(enabled: Boolean)

/**
* Stops the microphone.
* Enables/disables the camera track and publishes it if needed.
*/
abstract suspend fun stopMicrophone()
abstract suspend fun setCameraEnabled(enabled: Boolean)

/**
* Starts the camera track and publishes it if needed.
*/
abstract suspend fun startCamera()

/**
* Stops the camera.
*/
abstract suspend fun stopCamera()

/**
* Starts screensharing track and publishes it if needed. The result intent from starting a
* [android.media.projection.MediaProjectionManager.createScreenCaptureIntent] is required.
* Enables/disables screen share track and publishes it if needed.
*
* The result intent from starting
* [android.media.projection.MediaProjectionManager.createScreenCaptureIntent] is required for enabling this.
*
* @see android.media.projection.MediaProjectionManager.createScreenCaptureIntent
*/
abstract suspend fun startScreenShare(params: ScreenCaptureParams)

/**
* Stops screensharing.
*/
abstract suspend fun stopScreenShare()
abstract suspend fun setScreenShareEnabled(enabled: Boolean, params: ScreenCaptureParams? = null)

/**
* Selects the audio device to be used.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

package io.livekit.android.compose.types

import androidx.compose.runtime.Immutable
import io.livekit.android.room.participant.Participant
import io.livekit.android.room.track.Track
import io.livekit.android.room.track.TrackPublication
Expand Down Expand Up @@ -60,7 +59,6 @@ data class TrackSource(
/**
* A reference to a [Track], or a placeholder.
*/
@Immutable
data class TrackReference(
override val participant: Participant,
override val publication: TrackPublication?,
Expand Down
Loading