### Receive Data Message Example Source: https://github.com/livekit/components-android/blob/main/_autodocs/data-handlers.md Example of collecting the messageFlow to receive and process incoming data messages. ```kotlin LaunchedEffect(dataHandler.messageFlow) { dataHandler.messageFlow.collect { val text = it.payload.decodeToString() println("Received: $text") } } ``` -------------------------------- ### TrackSource Usage Examples Source: https://github.com/livekit/components-android/blob/main/_autodocs/types.md Shows how to create TrackSource instances for camera tracks and named tracks. ```kotlin val cameraTrack = TrackSource( participant = remoteParticipant, source = Track.Source.CAMERA ) val namedTrack = TrackSource( participant = remoteParticipant, name = "custom-screen" ) ``` -------------------------------- ### Basic VideoTrackView Usage Example Source: https://github.com/livekit/components-android/blob/main/_autodocs/video-display.md Example of how to use VideoTrackView in a Jetpack Compose UI. It renders the first available track reference with specified dimensions and rendering settings. ```kotlin @Composable fun VideoDisplay() { val trackRefs by rememberTracks() if (trackRefs.isNotEmpty()) { VideoTrackView( trackReference = trackRefs[0], modifier = Modifier .fillMaxWidth() .height(300.dp), scaleType = ScaleType.Fill, rendererType = RendererType.Texture, onFirstFrameRendered = { println("Video frame rendered") } ) } } ``` -------------------------------- ### TrackReference Usage Example Source: https://github.com/livekit/components-android/blob/main/_autodocs/types.md Demonstrates how to check if a track is available and subscribed before using it. ```kotlin val trackRef: TrackReference = tracks[0] if (!trackRef.isPlaceholder() && trackRef.isSubscribed()) { // Track is available and subscribed val videoTrack = rememberTrack(trackRef) } ``` -------------------------------- ### Example Usage of SessionScope Source: https://github.com/livekit/components-android/blob/main/_autodocs/room-scope-and-session.md Demonstrates how to use SessionScope to provide a session instance and conditionally render UI based on connection status. ```kotlin @Composable fun SessionContent() { val tokenSource = remember { FixedTokenSource(...) } val session = rememberSession(tokenSource) SessionScope(session) { if (session.isConnected) { AgentUI(session.room) } } } ``` -------------------------------- ### Basic Video Call Setup Source: https://github.com/livekit/components-android/blob/main/_autodocs/quick-reference.md Establishes a room connection and displays video tracks. Ensure you have a valid user token and the correct WebSocket URL. ```kotlin import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.foundation.layout.aspectRatio import livekit.components.compose.room.RoomScope import livekit.components.compose.state.rememberParticipants import livekit.components.compose.state.rememberTracks import livekit.components.compose.ui.video.VideoTrackView @Composable fun SimpleVideoCall() { RoomScope( url = "wss://livekit.example.com", token = userToken, audio = true, video = true ) { val participants by rememberParticipants() val trackRefs by rememberTracks() LazyColumn { items(trackRefs.size) { VideoTrackView(trackRefs[idx]) } } } } ``` -------------------------------- ### Example Usage of RoomScope Source: https://github.com/livekit/components-android/blob/main/_autodocs/room-scope-and-session.md Demonstrates how to use RoomScope to connect to a LiveKit server, handle connection events, and display participants in a LazyColumn. Connection and error callbacks are shown. ```kotlin @Composable fun MyVideoApp() { RoomScope( url = "wss://livekit.example.com", token = userToken, audio = true, video = true, connect = true, onConnected = { println("Connected to room: ${room.name}") }, onError = { println("Connection error: ${error?.message}") } ) { val participants by rememberParticipants(room) LazyColumn { items(participants.size) { ParticipantCard(participants[index]) } } } } ``` -------------------------------- ### AudioBarVisualizer Example Source: https://github.com/livekit/components-android/blob/main/_autodocs/audio-visualization.md Displays an animated bar visualization of audio levels for a given track reference. Requires a TrackReference and optionally accepts a Room context. ```kotlin @Composable fun AgentAudioVisualizer() { val agent = rememberAgent() if (agent.audioTrack != null) { AudioBarVisualizer( trackReference = agent.audioTrack!!, modifier = Modifier .fillMaxWidth() .height(100.dp) ) } } ``` -------------------------------- ### BarVisualizer Example Source: https://github.com/livekit/components-android/blob/main/_autodocs/audio-visualization.md A lower-level composable for creating custom bar-based audio visualizations. It takes a list of audio levels and the desired number of bars. ```kotlin @Composable fun CustomAudioVisualization() { val audioLevels = remember { mutableStateOf(emptyList()) } BarVisualizer( modifier = Modifier .fillMaxWidth() .height(80.dp), barCount = 20, audioLevels = audioLevels.value ) } ``` -------------------------------- ### Send Custom Data Example Source: https://github.com/livekit/components-android/blob/main/_autodocs/data-handlers.md Example of sending a custom data message using the sendMessage method. ```kotlin val payload = "Custom data".toByteArray() dataHandler.sendMessage(payload) ``` -------------------------------- ### VoiceAssistant UI Example Source: https://github.com/livekit/components-android/blob/main/_autodocs/types.md A composable function demonstrating how to use the VoiceAssistant state to render UI elements. It shows conditional rendering based on the agent's current state. ```kotlin @Composable fun VoiceAssistantUI() { val assistant = rememberVoiceAssistant() when (assistant.state) { AgentState.LISTENING -> Text("Agent is listening...") AgentState.SPEAKING -> { Text("Agent is speaking") for (transcription in assistant.agentTranscriptions) { Text(transcription.text) } } AgentState.THINKING -> Text("Agent is thinking...") else -> Text("Agent: ${assistant.state}") } } ``` -------------------------------- ### Custom Data Messaging Composable Example Source: https://github.com/livekit/components-android/blob/main/_autodocs/data-handlers.md Example of using rememberDataMessageHandler to set up custom data messaging in a Jetpack Compose UI. ```kotlin @Composable fun CustomDataMessaging() { val handler = rememberDataMessageHandler(topic = "custom-data") LaunchedEffect(handler.messageFlow) { handler.messageFlow.collect { val text = it.payload.decodeToString() println("Custom message: $text from ${it.fromParticipant?.name}") } } Button( onClick = { handler.sendMessage("Hello".toByteArray()) } ) { Text("Send Custom Message") } } ``` -------------------------------- ### RoomEvent LocalTrackPublished Example Source: https://github.com/livekit/components-android/blob/main/_autodocs/event-handling.md Demonstrates accessing the track publication object from a `RoomEvent.LocalTrackPublished` event. ```kotlin val event: RoomEvent.LocalTrackPublished val publication = event.trackPublication ``` -------------------------------- ### VoiceAssistantBarVisualizer Example Source: https://github.com/livekit/components-android/blob/main/_autodocs/audio-visualization.md A specialized visualizer for voice assistant interactions, adapting its appearance based on the agent's state (listening, speaking, thinking). It can visualize a specific track or use the Room context. ```kotlin @Composable fun VoiceAssistantUI() { val assistant = rememberVoiceAssistant() VoiceAssistantBarVisualizer( trackReference = assistant.audioTrack, state = assistant.state, modifier = Modifier .fillMaxWidth() .height(100.dp) ) Text(when (assistant.state) { AgentState.LISTENING -> "🎤 Listening..." AgentState.SPEAKING -> "🔊 Speaking..." AgentState.THINKING -> "🤔 Thinking..." else -> "Agent: ${assistant.state}" }) } ``` -------------------------------- ### ParticipantEvent ConnectionQualityChanged Example Source: https://github.com/livekit/components-android/blob/main/_autodocs/event-handling.md Demonstrates accessing the connection quality from a `ParticipantEvent.ConnectionQualityChanged` event. ```kotlin val event: ParticipantEvent.ConnectionQualityChanged val quality = event.quality // ConnectionQuality enum ``` -------------------------------- ### RoomEvent LocalTrackUnpublished Example Source: https://github.com/livekit/components-android/blob/main/_autodocs/event-handling.md Demonstrates accessing the track publication object from a `RoomEvent.LocalTrackUnpublished` event. ```kotlin val event: RoomEvent.LocalTrackUnpublished val publication = event.trackPublication ``` -------------------------------- ### LiveKit Initialization Source: https://github.com/livekit/components-android/blob/main/_autodocs/video-display.md Initializes the LiveKit SDK. This should be called once when your application starts, typically in the Application class's onCreate() method. ```kotlin import android.app.Application import io.livekit.android.LiveKIt // In Application.onCreate() class MyApplication : Application() { override fun onCreate() { super.onCreate() LiveKit.init(applicationContext) } } ``` -------------------------------- ### TrackEvent StreamStateChanged Example Source: https://github.com/livekit/components-android/blob/main/_autodocs/event-handling.md Demonstrates accessing the stream state from a `TrackEvent.StreamStateChanged` event. ```kotlin val event: TrackEvent.StreamStateChanged val streamState = event.streamState ``` -------------------------------- ### ParticipantEvent TrackSubscribed Example Source: https://github.com/livekit/components-android/blob/main/_autodocs/event-handling.md Demonstrates accessing the track and track publication objects from a `ParticipantEvent.TrackSubscribed` event. ```kotlin val event: ParticipantEvent.TrackSubscribed val track = event.track val publication = event.trackPublication ``` -------------------------------- ### Advanced VideoTrackView Usage with Manual Track Source: https://github.com/livekit/components-android/blob/main/_autodocs/video-display.md Example demonstrating VideoTrackView with a manually provided VideoTrack. This version uses FitInside scaling, mirroring, and SurfaceView rendering, with clipping applied via modifiers. ```kotlin @Composable fun ManualVideoDisplay(videoTrack: VideoTrack?) { VideoTrackView( videoTrack = videoTrack, modifier = Modifier .fillMaxSize() .clip(RoundedCornerShape(8.dp)), mirror = true, scaleType = ScaleType.FitInside, rendererType = RendererType.Surface ) } ``` -------------------------------- ### Monitor and Display Connection Quality for Participants Source: https://github.com/livekit/components-android/blob/main/_autodocs/event-handling.md This example shows how to monitor and display the connection quality of remote participants. It uses 'rememberEventSelector' to react to 'ParticipantEvent.ConnectionQualityChanged' events and updates the UI with a color-coded quality status. ```kotlin @Composable fun ConnectionQualityMonitor() { val participants by rememberParticipants() Column { for (participant in participants) { if (participant !is LocalParticipant) { QualityIndicator(participant) } } } } @Composable fun QualityIndicator(participant: Participant) { var quality by remember { mutableStateOf("unknown") } val qualityEvents = rememberEventSelector(participant) LaunchedEffect(qualityEvents) { qualityEvents.collect { event -> quality = event.quality.toString() } } Row( modifier = Modifier .fillMaxWidth() .padding(8.dp) ) { Text(participant.name, modifier = Modifier.weight(1f)) Text( quality, color = when (quality) { "EXCELLENT" -> Color.Green "GOOD" -> Color.Yellow "POOR" -> Color.Red else -> Color.Gray } ) } } ``` -------------------------------- ### RoomEvent TrackSubscribed Example Source: https://github.com/livekit/components-android/blob/main/_autodocs/event-handling.md Demonstrates accessing the track publication and participant objects from a `RoomEvent.TrackSubscribed` event. ```kotlin val event: RoomEvent.TrackSubscribed val publication = event.trackPublication val participant = event.participant ``` -------------------------------- ### Handle Session Connection Result Source: https://github.com/livekit/components-android/blob/main/_autodocs/quick-reference.md Determine if a session start attempt was successful or retrieve the exception if it failed. ```kotlin val result = session.start() if (result.isSuccess) { // Connected } else { val error = result.exceptionOrNull() } ``` -------------------------------- ### Manage LiveKit Session with TokenSource Source: https://github.com/livekit/components-android/blob/main/_autodocs/room-scope-and-session.md Shows how to use rememberSession to manage a LiveKit session, including automatic token handling and connection lifecycle. This example uses FixedTokenSource and custom SessionOptions. ```kotlin import androidx.compose.runtime.* import androidx.compose.material3.Text import io.livekit.session.rememberSession import io.livekit.session.token.FixedTokenSource import io.livekit.session.SessionOptions import io.livekit.session.encryption.E2EEOptions import kotlinx.coroutines.launch @Composable fun ManageSession() { val tokenSource = remember { FixedTokenSource( url = "wss://livekit.example.com", token = "your-token" ) } val session = rememberSession( tokenSource = tokenSource, options = SessionOptions( agentConnectTimeout = 30.seconds, encryption = E2EEOptions(sharedKey = "my-key") ) ) LaunchedEffect(session) { val result = session.start() if (result.isSuccess) { println("Session connected") } } Text("Connected: ${session.isConnected}") } ``` -------------------------------- ### Agent Chat with Transcription UI Source: https://github.com/livekit/components-android/blob/main/_autodocs/transcriptions.md This composable function sets up the main UI for agent transcription and chat. It initializes the session, agent, and chat components, and arranges them vertically with the transcription panel at the top and the chat panel below. Ensure the session is started before rendering child components. ```kotlin @Composable fun AgentChatWithTranscription() { val tokenSource = remember { FixedTokenSource(...) } val session = rememberSession(tokenSource) LaunchedEffect(Unit) { session.start() } SessionScope(session) { val agent = rememberAgent(session) val chat = rememberChat() Column(modifier = Modifier.fillMaxSize()) { // Agent transcription at top if (agent.audioTrack != null) { AgentTranscriptionPanel( trackRef = agent.audioTrack!!, modifier = Modifier .fillMaxWidth() .weight(0.3f) ) } Divider() // Chat messages in middle ChatPanel( chat = chat, modifier = Modifier .fillMaxWidth() .weight(0.7f) ) } } } @Composable fun AgentTranscriptionPanel( trackRef: TrackReference, modifier: Modifier = Modifier ) { val transcriptions by rememberTranscriptions(trackRef) Box( modifier = modifier .background(Color.LightGray.copy(alpha = 0.2f)) .padding(12.dp) ) { Column { Text( "Agent Response:", style = MaterialTheme.typography.labelSmall ) Text( text = transcriptions.joinToString(" ") { it.text }, style = MaterialTheme.typography.bodyLarge, modifier = Modifier.padding(top = 8.dp) ) } } } @Composable fun ChatPanel( chat: Chat, modifier: Modifier = Modifier ) { Column(modifier = modifier) { LazyColumn(modifier = Modifier.weight(1f)) { items(chat.messages.value) { ChatBubble(message) } } ChatInputBar( chat = chat, modifier = Modifier.fillMaxWidth() ) } } @Composable fun ChatBubble(message: ReceivedChatMessage) { Box( modifier = Modifier .fillMaxWidth() .padding(8.dp), contentAlignment = if (message.fromParticipant == RoomLocal.current.localParticipant) { Alignment.CenterEnd } else { Alignment.CenterStart } ) { Surface( shape = RoundedCornerShape(8.dp), color = if (message.fromParticipant == RoomLocal.current.localParticipant) { MaterialTheme.colorScheme.primary } else { MaterialTheme.colorScheme.surface } ) { Column(modifier = Modifier.padding(8.dp)) { Text(message.message) Text( SimpleDateFormat("HH:mm").format(Date(message.timestamp)), style = MaterialTheme.typography.labelSmall ) } } } } @Composable fun ChatInputBar( chat: Chat, modifier: Modifier = Modifier ) { var messageText by remember { mutableStateOf("") } val scope = rememberCoroutineScope() Row( modifier = modifier .fillMaxWidth() .padding(8.dp), verticalAlignment = Alignment.CenterVertically ) { TextField( value = messageText, onValueChange = { messageText = it }, modifier = Modifier.weight(1f), placeholder = { Text("Type message...") } ) Button( onClick = { scope.launch { chat.send(messageText) messageText = "" } }, enabled = messageText.isNotBlank() ) { Text("Send") } } } ``` -------------------------------- ### Binary Messaging Example Source: https://github.com/livekit/components-android/blob/main/_autodocs/data-handlers.md This snippet demonstrates sending and receiving raw binary data, specifically a Float. It uses `java.nio.ByteBuffer` to convert the float to a byte array for sending and to read the float from received bytes. Use this for protocols that are not JSON-based. ```kotlin @Composable fun BinaryMessageingScreen() { val handler = rememberDataMessageHandler(topic = "binary-data") var lastValue by remember { mutableStateOf(0f) } LaunchedEffect(handler.messageFlow) { handler.messageFlow.collect { if (message.payload.size >= 4) { // Read float from bytes val buffer = java.nio.ByteBuffer.wrap(message.payload) lastValue = buffer.float println("Received value: $lastValue") } } } Column { Text("Last Value: $lastValue") Button( onClick = { // Send float as binary val buffer = java.nio.ByteBuffer.allocate(4) buffer.putFloat(42.5f) handler.sendMessage(buffer.array()) } ) { Text("Send 42.5") } } } ``` -------------------------------- ### Monitor Participant Connections and Disconnections in a Room Source: https://github.com/livekit/components-android/blob/main/_autodocs/event-handling.md This example demonstrates how to monitor participant connections and disconnections within a LiveKit room using Jetpack Compose. It updates a list of events displayed to the user. ```kotlin @Composable fun RoomEventMonitor() { val room = requireRoom() var events by remember { mutableStateOf>(emptyList()) } // Monitor participant connections val participantJoined = rememberEventSelector(room) LaunchedEffect(participantJoined) { participantJoined.collect { event -> events = events + "Participant joined: ${event.participant.name}" } } // Monitor participant disconnections val participantLeft = rememberEventSelector(room) LaunchedEffect(participantLeft) { participantLeft.collect { event -> events = events + "Participant left: ${event.participant.name}" } } // Monitor track subscriptions val trackSubscribed = rememberEventSelector(room) LaunchedEffect(trackSubscribed) { trackSubscribed.collect { event -> val source = event.trackPublication.source events = events + "${event.participant.name} published $source" } } Column(modifier = Modifier.fillMaxSize()) { Text("Room Events", style = MaterialTheme.typography.headlineSmall) LazyColumn { items(events) { Text(it, modifier = Modifier.padding(4.dp)) } } } } ``` -------------------------------- ### Retrieve Room from Composition Context Source: https://github.com/livekit/components-android/blob/main/_autodocs/room-scope-and-session.md Shows how to use the requireRoom() utility function to get the current Room instance from the composition context. This function throws an IllegalStateException if no Room is available. ```kotlin import androidx.compose.runtime.* import androidx.compose.material3.Text import io.livekit.room.requireRoom import io.livekit.room.rememberConnectionState import io.livekit.room.Room @Composable fun VideoDisplay() { val room = requireRoom() // Gets room from RoomLocal val state by rememberConnectionState(room) if (state == Room.State.CONNECTED) { Text("Connected") } } ``` -------------------------------- ### Custom JSON Messaging Example Source: https://github.com/livekit/components-android/blob/main/_autodocs/data-handlers.md Use this snippet to send and receive custom JSON messages. It requires defining a serializable data class and uses `rememberDataMessageHandler` to manage the message flow. Ensure the `app-data` topic is correctly configured. ```kotlin @Composable fun CustomJSONMessaging() { val handler = rememberDataMessageHandler(topic = "app-data") var receivedMessages by remember { mutableStateOf>(emptyList()) } LaunchedEffect(handler.messageFlow) { handler.messageFlow.collect { try { val text = message.payload.decodeToString() val json = Json.decodeFromString(text) receivedMessages = receivedMessages + "From ${message.fromParticipant?.name}: ${json.content}" } catch (e: Exception) { println("Failed to parse message: ${e.message}") } } } Column(modifier = Modifier.fillMaxSize()) { LazyColumn(modifier = Modifier.weight(1f)) { items(receivedMessages) { Text(it, modifier = Modifier.padding(8.dp)) } } Row(modifier = Modifier.fillMaxWidth().padding(8.dp)) { var messageText by remember { mutableStateOf("") } TextField( value = messageText, onValueChange = { messageText = it }, modifier = Modifier.weight(1f), placeholder = { Text("Enter message...") } ) Button( onClick = { val msg = CustomMessage(content = messageText) val json = Json.encodeToString(msg) handler.sendMessage( json.toByteArray(), DataSendOptions(reliability = DataPublishReliability.RELIABLE) ) messageText = "" } ) { Text("Send") } } } } @Serializable data class CustomMessage( val content: String, val timestamp: Long = System.currentTimeMillis() ) ``` -------------------------------- ### DataTopic Usage Example Source: https://github.com/livekit/components-android/blob/main/_autodocs/data-handlers.md Example of accessing the string value of a DataTopic enum member. ```kotlin val topic = DataTopic.CHAT.value // "livekit-chat" ``` -------------------------------- ### Agent Interaction with Chat and Audio Visualization Source: https://github.com/livekit/components-android/blob/main/_autodocs/quick-reference.md Sets up a session with agent interaction, displaying listening or speaking states. Requires a token source and session management. ```kotlin import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import livekit.components.compose.agent.AgentState import livekit.components.compose.agent.rememberAgent import livekit.components.compose.chat.rememberChat import livekit.components.compose.session.SessionScope import livekit.components.compose.session.rememberSession import livekit.components.compose.state.rememberParticipants import livekit.components.compose.ui.audio.AudioBarVisualizer @Composable fun AgentChat() { val tokenSource = remember { FixedTokenSource(...) } val session = rememberSession(tokenSource) LaunchedEffect(Unit) { session.start() } SessionScope(session) { val agent = rememberAgent() val chat = rememberChat() when (agent.agentState) { AgentState.LISTENING -> Text("Agent listening...") AgentState.SPEAKING -> { agent.audioTrack?.let { AudioBarVisualizer(it) } } else -> {} } } } ``` -------------------------------- ### ParticipantEvent MetadataChanged Example Source: https://github.com/livekit/components-android/blob/main/_autodocs/event-handling.md Demonstrates accessing the metadata from a `ParticipantEvent.MetadataChanged` event. ```kotlin val event: ParticipantEvent.MetadataChanged val metadata = event.metadata ``` -------------------------------- ### RoomScope Parameters Configuration Source: https://github.com/livekit/components-android/blob/main/_autodocs/quick-reference.md Set up parameters for RoomScope, including connection details, callbacks, and content composables. ```kotlin RoomScope( url: String?, token: String?, audio: Boolean = false, video: Boolean = false, connect: Boolean = true, roomOptions: RoomOptions? = null, liveKitOverrides: LiveKitOverrides? = null, connectOptions: ConnectOptions? = null, onConnected: (suspend CoroutineScope.(Room) -> Unit)? = null, onDisconnected: (suspend CoroutineScope.(Room) -> Unit)? = null, onError: ((Room, Exception?) -> Unit)? = null, passedRoom: Room? = null, disconnectOnDispose: Boolean = true, content: @Composable (room: Room) -> Unit ) ``` -------------------------------- ### Basic Agent UI Source: https://github.com/livekit/components-android/blob/main/_autodocs/agent.md Displays the agent's current state with corresponding UI elements like text, progress indicators, and media views. Requires session management and agent initialization. ```kotlin import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp @Composable fun AgentScreen() { val tokenSource = remember { FixedTokenSource(...) } // Replace with actual token source val session = rememberSession(tokenSource) LaunchedEffect(Unit) { session.start() } SessionScope(session) { val agent = rememberAgent(session) Column(modifier = Modifier.fillMaxSize()) { when (agent.agentState) { AgentState.CONNECTING -> { Text("Connecting to agent...") CircularProgressIndicator() } AgentState.LISTENING -> { Text("Agent is listening") if (agent.audioTrack != null) { AudioVisualizerForTrack(agent.audioTrack!!) } } AgentState.SPEAKING -> { Text("Agent is speaking") VideoTrackView( trackReference = agent.videoTrack, modifier = Modifier .fillMaxWidth() .height(300.dp) ) } AgentState.THINKING -> { Text("Agent is thinking...") ProgressBar() } else -> { Text("Agent state: ${agent.agentState}") } } } } } ``` -------------------------------- ### LiveKit Compose Imports for UI Components Source: https://github.com/livekit/components-android/blob/main/_autodocs/quick-reference.md Import UI components for displaying video tracks, camera previews, and audio visualizers. ```kotlin import io.livekit.android.compose.ui.VideoTrackView import io.livekit.android.compose.ui.CameraPreview import io.livekit.android.compose.ui.AudioBarVisualizer ``` -------------------------------- ### ParticipantEvent SpeakingChanged Example Source: https://github.com/livekit/components-android/blob/main/_autodocs/event-handling.md Demonstrates accessing the speaking status from a `ParticipantEvent.SpeakingChanged` event. ```kotlin val event: ParticipantEvent.SpeakingChanged val isSpeaking = event.isSpeaking // true if speaking ``` -------------------------------- ### RoomEvent ParticipantMetadataChanged Example Source: https://github.com/livekit/components-android/blob/main/_autodocs/event-handling.md Demonstrates accessing the participant object from a `RoomEvent.ParticipantMetadataChanged` event. ```kotlin val event: RoomEvent.ParticipantMetadataChanged val participant = event.participant ``` -------------------------------- ### RoomEvent ParticipantDisconnected Example Source: https://github.com/livekit/components-android/blob/main/_autodocs/event-handling.md Demonstrates accessing the participant object from a `RoomEvent.ParticipantDisconnected` event. ```kotlin val event: RoomEvent.ParticipantDisconnected val participant = event.participant // The participant who left ``` -------------------------------- ### RoomEvent ParticipantConnected Example Source: https://github.com/livekit/components-android/blob/main/_autodocs/event-handling.md Demonstrates accessing the participant object from a `RoomEvent.ParticipantConnected` event. ```kotlin val event: RoomEvent.ParticipantConnected val participant = event.participant // The participant who joined ``` -------------------------------- ### Performance Tip: Choose Renderer Type Wisely Source: https://github.com/livekit/components-android/blob/main/_autodocs/quick-reference.md Select the appropriate renderer type for video display. Use `Surface` for simpler layouts for better performance, and `Texture` when applying Compose transforms. ```kotlin // Use Surface for simple layouts (better performance) // Use Texture when applying Compose transforms ``` -------------------------------- ### AgentState State Machine Source: https://github.com/livekit/components-android/blob/main/_autodocs/00_START_HERE.md Illustrates the state transitions for the AgentState machine, including states like CONNECTING, LISTENING, THINKING, SPEAKING, and DISCONNECTED/FAILED, as well as pre-buffering. ```text CONNECTING → LISTENING ↔ THINKING ↔ SPEAKING → DISCONNECTED/FAILED ↓ PRECONNECT_BUFFERING → LISTENING (audio pre-buffering) ``` -------------------------------- ### ParticipantEvent TrackUnsubscribed Example Source: https://github.com/livekit/components-android/blob/main/_autodocs/event-handling.md Demonstrates accessing the track and track publication objects from a `ParticipantEvent.TrackUnsubscribed` event. ```kotlin val event: ParticipantEvent.TrackUnsubscribed val track = event.track val publication = event.trackPublication ``` -------------------------------- ### Interactive Audio Visualizer Source: https://github.com/livekit/components-android/blob/main/_autodocs/audio-visualization.md Displays a list of participants and allows selection to visualize their audio. Requires participants and their audio tracks to be available. ```kotlin import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import livekit.rtc.Participant import livekit.rtc.Track import livekit.components.compose.rememberParticipants import livekit.components.compose.rememberParticipantTrackReferences import livekit.components.compose.AudioBarVisualizer @Composable fun InteractiveAudioVisualizer() { val room = requireRoom() val participants by rememberParticipants(room) var selectedParticipant by remember { mutableStateOf(null) } Column(modifier = Modifier.fillMaxSize()) { // Participant selector LazyRow(modifier = Modifier.fillMaxWidth()) { items(participants) { ParticipantButton( participant = participant, selected = selectedParticipant == participant, onClick = { selectedParticipant = participant } ) } } // Audio visualizer if (selectedParticipant != null) { val audioTracks by rememberParticipantTrackReferences( sources = listOf(Track.Source.MICROPHONE), passedParticipant = selectedParticipant!! ) if (audioTracks.isNotEmpty()) { AudioBarVisualizer( trackReference = audioTracks[0], modifier = Modifier .fillMaxWidth() .height(150.dp) .padding(16.dp) ) } } } } @Composable fun ParticipantButton( participant: Participant, selected: Boolean, onClick: () -> Unit ) { Button( onClick = onClick, colors = ButtonDefaults.buttonColors( containerColor = if (selected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.surface ), modifier = Modifier.padding(4.dp) ) { Text(participant.name) } } ``` -------------------------------- ### RoomEvent TrackUnsubscribed Example Source: https://github.com/livekit/components-android/blob/main/_autodocs/event-handling.md Demonstrates accessing the track publication and participant objects from a `RoomEvent.TrackUnsubscribed` event. ```kotlin val event: RoomEvent.TrackUnsubscribed val publication = event.trackPublication val participant = event.participant ``` -------------------------------- ### Connection Flow Diagram Source: https://github.com/livekit/components-android/blob/main/_autodocs/README.md Illustrates the connection flow from the LiveKit Server to UI Components. ```text LiveKit Server ↓ RoomScope/rememberLiveKitRoom ↓ Room (from livekit-android SDK) ↓ Local & Remote Participants ← Tracks, State, Events ↓ State Composables ← Observation & Updates ↓ UI Components ← Rendering ``` -------------------------------- ### Architecture Overview Source: https://github.com/livekit/components-android/blob/main/_autodocs/00_START_HERE.md Visualizes the architecture of LiveKit Components Android, showing the flow from Room Connection to UI Components and Features, including an optional Session-based flow for agents. ```text ┌─ ROOM CONNECTION ──────────────────────────────┐ │ │ │ RoomScope (url, token, audio, video) │ │ ↓ │ │ Room Instance (from livekit-android) │ │ ↓ │ │ ┌─ STATE OBSERVATION ───────────┐ │ │ │ • rememberParticipants() │ │ │ │ • rememberTracks() │ │ │ │ • rememberConnectionState() │ │ │ │ • rememberLocalMedia() │ │ │ └───────────────────────────────┘ │ │ ↓ │ │ ┌─ UI COMPONENTS ────────────────┐ │ │ │ • VideoTrackView() │ │ │ │ • AudioBarVisualizer() │ │ │ │ • CameraPreview() │ │ │ └────────────────────────────────┘ │ │ ↓ │ │ ┌─ FEATURES ─────────────────────┐ │ │ │ • Chat (rememberChat) │ │ │ │ • Transcriptions │ │ │ │ • Custom Data (DataHandler) │ │ │ │ • Events (rememberEventSelector)│ │ │ └────────────────────────────────┘ │ └────────────────────────────────────────────────┘ Optional: SESSION-BASED FLOW (for agents) ┌─ SESSION ──────────────────────────────────┐ │ │ │ rememberSession(tokenSource) │ │ ↓ │ │ Session.start() │ │ ↓ │ │ Automatic Token Refresh + Agent Setup │ │ ↓ │ │ rememberAgent() → Agent with State │ │ ↓ │ │ LISTENING ↔ SPEAKING ↔ THINKING │ └────────────────────────────────────────────┘ ``` -------------------------------- ### Session Connect Options Configuration Source: https://github.com/livekit/components-android/blob/main/_autodocs/quick-reference.md Define options for connecting a session, including track settings and general room connection parameters. ```kotlin SessionConnectOptions( tracks: SessionConnectTrackOptions = default, roomConnectOptions: ConnectOptions = ConnectOptions() ) SessionConnectTrackOptions( microphoneEnabled: Boolean = true, usePreconnectBuffer: Boolean = true, microphoneCaptureOptions: LocalAudioTrackOptions = default, microphonePublishOptions: AudioTrackPublishOptions = default ) ``` -------------------------------- ### Agent State Property Source: https://github.com/livekit/components-android/blob/main/_autodocs/agent.md Gets the current state of the agent, such as connecting, listening, speaking, or thinking. ```kotlin abstract val agentState: AgentState ``` -------------------------------- ### Performance Tip: Configure Agent Timeouts Source: https://github.com/livekit/components-android/blob/main/_autodocs/quick-reference.md Configure agent timeouts appropriately for your specific use case to manage connection and responsiveness. ```kotlin SessionOptions(agentConnectTimeout = 30.seconds) ``` -------------------------------- ### Basic Chat UI Implementation Source: https://github.com/livekit/components-android/blob/main/_autodocs/chat.md A basic chat UI composable demonstrating how to use rememberChat, send messages, and display received messages in a LazyColumn. ```kotlin @Composable fun ChatScreen() { RoomScope( url = "wss://livekit.example.com", token = token ) { val chat = rememberChat() var messageText by remember { mutableStateOf("") } Column(modifier = Modifier.fillMaxSize()) { LazyColumn( modifier = Modifier .weight(1f) .fillMaxWidth() ) { items(chat.messages.value.size) { val msg = chat.messages.value[index] ChatMessage(msg) } } Row(modifier = Modifier.fillMaxWidth()) { TextField( value = messageText, onValueChange = { messageText = it }, modifier = Modifier.weight(1f), enabled = !chat.isSending.value ) Button( onClick = { val scope = rememberCoroutineScope() scope.launch { chat.send(messageText) messageText = "" } }, enabled = messageText.isNotEmpty() && !chat.isSending.value ) { Text("Send") } } } } } @Composable fun ChatMessage(message: ReceivedChatMessage) { Column(modifier = Modifier.padding(8.dp)) { Text( text = message.fromParticipant?.name ?: "Unknown", style = MaterialTheme.typography.labelSmall ) Text(message.message) Text( text = SimpleDateFormat("HH:mm").format(Date(message.timestamp)), style = MaterialTheme.typography.labelSmall, color = Color.Gray ) } } ``` -------------------------------- ### Session Options Configuration Source: https://github.com/livekit/components-android/blob/main/_autodocs/quick-reference.md Configure session connection parameters including room, timeouts, token requests, and end-to-end encryption. ```kotlin SessionOptions( room: Room? = null, agentConnectTimeout: Duration = 20.seconds, tokenRequestOptions: TokenRequestOptions = TokenRequestOptions(), encryption: E2EEOptions? = null ) ``` -------------------------------- ### Manually Connect to a LiveKit Room Source: https://github.com/livekit/components-android/blob/main/_autodocs/room-scope-and-session.md Demonstrates how to manually connect to a LiveKit room using rememberLiveKitRoom and LaunchedEffect for connection logic. Set 'connect' to false to manage connection manually. ```kotlin import androidx.compose.runtime.* import androidx.compose.material3.Text import io.livekit.room.rememberLiveKitRoom @Composable fun CustomRoomManagement() { val room = rememberLiveKitRoom( url = "wss://livekit.example.com", token = userToken, audio = true, video = true, connect = false // Manual connection ) var connectionError by remember { mutableStateOf(null) } LaunchedEffect(Unit) { try { room.connect("wss://livekit.example.com", userToken) } catch (e: Exception) { connectionError = e } } if (connectionError != null) { Text("Connection failed: ${connectionError?.message}") } } ``` -------------------------------- ### UI Rendering Source: https://github.com/livekit/components-android/blob/main/_autodocs/README.md Components for rendering video and audio visualizations. ```APIDOC ## UI Rendering ### Description Components for rendering video and audio visualizations. ### API - `VideoTrackView`: Display video with dual renderer support. - `CameraPreview`: Standalone camera without Room. - `AudioBarVisualizer`: Animated audio level visualization. - `BarVisualizer`: Low-level bar animation. - `VoiceAssistantBarVisualizer`: Agent-specific audio display. ``` -------------------------------- ### Performance Tip: Use State<> for Tracks Source: https://github.com/livekit/components-android/blob/main/_autodocs/quick-reference.md To optimize performance, use the State<> wrapper when accessing tracks. This avoids unnecessary recompositions by extracting the value only when needed. ```kotlin val tracks by rememberTracks() // Extracts value from State ``` -------------------------------- ### Session-Based Flow Diagram Source: https://github.com/livekit/components-android/blob/main/_autodocs/README.md Illustrates the session-based flow for agent interactions. ```text TokenSource → rememberSession → Session → Room ↓ Agent Detection & Setup ↓ rememberAgent → Agent Properties ↓ Tracks + State + Events → UI ``` -------------------------------- ### Observe Transcriptions for a Specific Track Source: https://github.com/livekit/components-android/blob/main/_autodocs/transcriptions.md Use rememberTranscriptions to get a State list of TextStreamData for a given track identifier. This is useful for displaying transcriptions associated with a particular participant's audio or video track. ```kotlin @Composable fun TranscriptionDisplay() { val trackRefs by rememberTracks() if (trackRefs.isNotEmpty()) { val transcriptions by rememberTranscriptions(trackRefs[0]) LazyColumn { items(transcriptions) { Text(it.text) } } } } ``` -------------------------------- ### Basic Composable for LiveKit Room Source: https://github.com/livekit/components-android/blob/main/README.md A composable function to create and connect to a LiveKit room, displaying video tracks. It uses RoomScope to manage the connection and rememberTracks to retrieve track references. ```kotlin @Composable fun exampleComposable() { // Create and connect to a room. RoomScope( url = wsURL, token = token, audio = true, video = true, connect = true, ) { // Get all the tracks in the room val trackRefs = rememberTracks() // Display the video tracks LazyColumn(modifier = Modifier.fillMaxSize()) { items(trackRefs.size) { VideoTrackView( trackReference = trackRefs[index], modifier = Modifier.fillParentMaxHeight(0.5f) ) } } } } ``` -------------------------------- ### Compose Multi-Participant Audio Monitor Source: https://github.com/livekit/components-android/blob/main/_autodocs/audio-visualization.md Displays a list of participants, highlighting who is currently speaking and visualizing their audio levels. Requires `requireRoom()` and participant data. ```kotlin import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Mic import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import io.livekit.android.compose.ui.audio.AudioBarVisualizer import io.livekit.android.compose.ui.rememberParticipantTrackReferences import io.livekit.android.compose.ui.rememberParticipants import io.livekit.android.room.Room import io.livekit.android.room.participant.Participant import io.livekit.android.tracks.Track @Composable fun MultiAudioMonitor() { val room = requireRoom() val participants by rememberParticipants(room) LazyColumn(modifier = Modifier.fillMaxSize()) { items(participants) { ParticipantAudioRow(it) } } } @Composable fun ParticipantAudioRow(participant: Participant) { val audioTracks by rememberParticipantTrackReferences( sources = listOf(Track.Source.MICROPHONE), passedParticipant = participant ) val isSpeaking by remember(participant) { derivedStateOf { participant.isSpeaking } } Column( modifier = Modifier .fillMaxWidth() .background( color = if (isSpeaking) Color.Cyan.copy(alpha = 0.2f) else Color.Transparent ) .padding(8.dp) ) { Row( modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically ) { Text( text = participant.name, modifier = Modifier.weight(1f), style = MaterialTheme.typography.bodyMedium ) if (isSpeaking) { Icon( imageVector = Icons.Default.Mic, contentDescription = "Speaking", tint = Color.Red, modifier = Modifier.size(16.dp) ) } } if (audioTracks.isNotEmpty() && isSpeaking) { AudioBarVisualizer( trackReference = audioTracks[0], modifier = Modifier .fillMaxWidth() .height(40.dp) .padding(top = 4.dp) ) } } } ``` -------------------------------- ### LiveKit Compose Imports for State Observation Source: https://github.com/livekit/components-android/blob/main/_autodocs/quick-reference.md Import components for observing and managing the state of participants, tracks, and connection status in LiveKit. ```kotlin import io.livekit.android.compose.state.rememberParticipants import io.livekit.android.compose.state.rememberTracks import io.livekit.android.compose.state.rememberConnectionState ``` -------------------------------- ### SessionOptions for Agent Configuration Source: https://github.com/livekit/components-android/blob/main/_autodocs/agent.md Configures session options when creating a session with an agent, including connection timeouts and encryption. ```kotlin SessionOptions( agentConnectTimeout = 30.seconds, // Timeout for agent to connect encryption = E2EEOptions(sharedKey = "key"), // Optional encryption tokenRequestOptions = TokenRequestOptions(...) // Token refresh config ) ``` -------------------------------- ### Wait Until Agent Camera Available Source: https://github.com/livekit/components-android/blob/main/_autodocs/agent.md Suspends execution until the agent's video track becomes available. ```kotlin abstract suspend fun waitUntilCamera() ``` -------------------------------- ### Voice Assistant UI Source: https://github.com/livekit/components-android/blob/main/_autodocs/agent.md A simplified UI for voice interactions with an agent, displaying its state, transcriptions, and audio visualizer. It uses a `VoiceAssistant` composable which abstracts session management. ```kotlin import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp @Composable fun VoiceAssistantScreen() { val assistant = rememberVoiceAssistant() // Assumes VoiceAssistant is remembered Column { Text("State: ${assistant.state}") if (assistant.state == AgentState.SPEAKING) { LazyColumn { items(assistant.agentTranscriptions.size) { index -> Text(assistant.agentTranscriptions[index].text) } } } AudioBarVisualizer( trackReference = assistant.audioTrack, modifier = Modifier .fillMaxWidth() .height(100.dp) ) } } ```