### Install Dependencies and Generate Changeset Source: https://github.com/livekit/client-sdk-android/blob/main/CONTRIBUTING.md Run these commands in the root folder to install project dependencies and create a changeset file for your PR. Follow the on-screen instructions to complete the changeset creation. ```bash pnpm install ``` ```bash pnpm changeset ``` -------------------------------- ### Enable Camera and Microphone Publishing Source: https://github.com/livekit/client-sdk-android/blob/main/README.md Enable the local participant's camera and microphone to start publishing audio and video streams. ```kotlin room.localParticipant.setCameraEnabled(true) room.localParticipant.setMicrophoneEnabled(true) ``` -------------------------------- ### Create and Publish Video Track with Processor Source: https://github.com/livekit/client-sdk-android/blob/main/livekit-android-track-processors/README.md Create a local video track, passing the configured video processor. Start capture and then publish the track to the room. ```kotlin val videoTrack = room.localParticipant.createVideoTrack( options = LocalVideoTrackOptions(position = CameraPosition.FRONT), videoProcessor = processor, ) videoTrack.startCapture() room.localParticipant.publishVideoTrack(videoTrack) ``` -------------------------------- ### Configure and Register CameraProvider with ImageCapture Source: https://github.com/livekit/client-sdk-android/blob/main/livekit-android-camerax/README.md Initialize a CameraProvider that includes the ImageCapture use case, configured for maximum quality. This setup is necessary for taking high-resolution pictures. ```kotlin // Pass in the imageCapture use case when creating the camera provider val imageCapture = ImageCapture.Builder() .setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY) .build() CameraXHelper.createCameraProvider(lifecycleOwner, arrayOf(imageCapture)).let { if (it.isSupported(application)) { CameraCapturerUtils.registerCameraProvider(it) // Save cameraProvider for unregistration later. cameraProvider = it } } ``` -------------------------------- ### Publish Processed Video Track Source: https://github.com/livekit/client-sdk-android/wiki/Post‐Processing-Local-Video Create a local video track with a custom `VideoProcessor` and publish it to the room. Ensure the track capture is started before publishing. ```kotlin fun publishProcessedVideo() { val videoTrack = localParticipant.createVideoTrack( videoProcessor = ExampleVideoProcessor(), ) videoTrack.startCapture() localParticipant.publishVideoTrack( track = videoTrack, ) } ``` -------------------------------- ### Install LiveKit Android Track Processors Source: https://github.com/livekit/client-sdk-android/blob/main/livekit-android-track-processors/README.md Add the track processors library to your app's build.gradle file. Replace `` with the actual version. ```groovy implementation "io.livekit:livekit-android-track-processors:" ``` -------------------------------- ### Implement Monochrome Video Processor Source: https://github.com/livekit/client-sdk-android/wiki/Post‐Processing-Local-Video Implement the `VideoProcessor` interface to create a custom video filter. This example shows a monochrome filter by manipulating the UV planes of an I420 frame. Ensure processed frames are released after use. ```kotlin class MonochromeVideoProcessor : VideoProcessor { // Where the processed frames should be outputted to. private var sink: VideoSink? = null // Initialize any resources for video processing here. override fun onCapturerStarted(success: Boolean) { } // Release any resources associated with this capturer. override fun onCapturerStopped() { } // Called for each frame captured. override fun onFrameCaptured(frame: VideoFrame) { val processedFrame = monochromeFilter(frame) sink?.onFrame(processedFrame) // Make sure to release when you're done with frame. processedFrame.release() } // A basic monochrome filter can be achieved by setting the UV planes // to zero on an I420 image. private fun monochromeFilter(frame: VideoFrame): VideoFrame { val buffer = frame.buffer.toI420() ?: return frame fun clearUV(byteBuffer: ByteBuffer) { // In I420, 0x00 represents -128, so need to use 0x80 for proper zero. val zeroArray = ByteArray(1024) { 0x80.toByte() } while (byteBuffer.remaining() > 1024) { byteBuffer.put(zeroArray) } if (byteBuffer.remaining() > 0) { val lastZeroArray = ByteArray(byteBuffer.remaining()) { 0x80.toByte() } byteBuffer.put(lastZeroArray) } byteBuffer.rewind() } clearUV(buffer.dataU) clearUV(buffer.dataV) return VideoFrame(buffer, frame.rotation, frame.timestampNs) } override fun setSink(sink: VideoSink?) { this.sink = sink } } ``` -------------------------------- ### Initialize and Connect to LiveKit Room Source: https://github.com/livekit/client-sdk-android/blob/main/README.md Sets up the Room object, initializes the video renderer, and connects to the LiveKit server. It also configures event handling and enables local audio/video publishing. ```kotlin class MainActivity : AppCompatActivity() { lateinit var room: Room override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Create Room object. room = LiveKit.create(applicationContext) // Setup the video renderer room.initVideoRenderer(findViewById(R.id.renderer)) connectToRoom() } private fun connectToRoom() { val url = "wss://your_host" val token = "your_token" lifecycleScope.launch { // Setup event handling. launch { room.events.collect { event -> when (event) { is RoomEvent.TrackSubscribed -> onTrackSubscribed(event) else -> {} } } } // Connect to server. room.connect( url, token, ) // Turn on audio/video recording. val localParticipant = room.localParticipant localParticipant.setMicrophoneEnabled(true) localParticipant.setCameraEnabled(true) } } private fun onTrackSubscribed(event: RoomEvent.TrackSubscribed) { val track = event.track if (track is VideoTrack) { attachVideo(track) } } private fun attachVideo(videoTrack: VideoTrack) { videoTrack.addRenderer(findViewById(R.id.renderer)) findViewById(R.id.progress).visibility = View.GONE } } ``` -------------------------------- ### Initialize VirtualBackgroundVideoProcessor Source: https://github.com/livekit/client-sdk-android/blob/main/livekit-android-track-processors/README.md Instantiate VirtualBackgroundVideoProcessor. If no background image is set, it will blur the background. You can optionally set a BitmapDrawable as the background image. ```kotlin val processor = VirtualBackgroundVideoProcessor(eglBase).apply { // Optionally set a background image. // Will blur the background of the video if none is set. val drawable = AppCompatResources.getDrawable(application, R.drawable.background) as BitmapDrawable backgroundImage = drawable.bitmap } ``` -------------------------------- ### Initiate Screen Sharing Capture Source: https://github.com/livekit/client-sdk-android/blob/main/README.md Launches an intent to capture the screen for sharing. This requires registering an ActivityResultLauncher before onCreate and handling the result to enable screen sharing. ```kotlin // create an intent launcher for screen capture // this *must* be registered prior to onCreate(), ideally as an instance val val screenCaptureIntentLauncher = registerForActivityResult( ActivityResultContracts.StartActivityForResult() ) { result -> val resultCode = result.resultCode val data = result.data if (resultCode != Activity.RESULT_OK || data == null) { return@registerForActivityResult } lifecycleScope.launch { room.localParticipant.setScreenShareEnabled(true, data) } } // when it's time to enable the screen share, perform the following val mediaProjectionManager = getSystemService(MEDIA_PROJECTION_SERVICE) as MediaProjectionManager screenCaptureIntentLauncher.launch(mediaProjectionManager.createScreenCaptureIntent()) ``` -------------------------------- ### Format Code with Spotless Source: https://github.com/livekit/client-sdk-android/blob/main/CONTRIBUTING.md Apply code formatting to your changes using the Spotless Gradle plugin. This ensures code consistency across the project. ```bash ./gradlew spotlessApply ``` -------------------------------- ### Register Image Analyzer with CameraProvider Source: https://github.com/livekit/client-sdk-android/blob/main/livekit-android-track-processors/README.md Create an ImageAnalysis use case and set the VirtualBackgroundVideoProcessor's image analyzer. Then, register this provider with CameraX. ```kotlin val imageAnalysis = ImageAnalysis.Builder().build() .apply { setAnalyzer(Dispatchers.IO.asExecutor(), processor.imageAnalyzer) } CameraXHelper.createCameraProvider(ProcessLifecycleOwner.get(), arrayOf(imageAnalysis)).let { if (it.isSupported(application)) { CameraCapturerUtils.registerCameraProvider(it) } } ``` -------------------------------- ### Register CameraProvider with LifecycleOwner Source: https://github.com/livekit/client-sdk-android/blob/main/livekit-android-camerax/README.md Create and register a CameraProvider using CameraXHelper, ensuring it's supported by the application. This allows LiveKit to default to CameraX for video tracks. ```kotlin CameraXHelper.createCameraProvider(lifecycleOwner).let { if (it.isSupported(application)) { CameraCapturerUtils.registerCameraProvider(it) // Save cameraProvider for unregistration later. cameraProvider = it } } ``` -------------------------------- ### JitPack Repository Configuration Source: https://github.com/livekit/client-sdk-android/blob/main/README.md Ensure your `settings.gradle` file includes the JitPack repository to resolve LiveKit dependencies. ```groovy dependencyResolutionManagement { repositories { google() mavenCentral() //... maven { url 'https://jitpack.io' } // For SNAPSHOT access // maven { url 'https://central.sonatype.com/repository/maven-snapshots/' } } } ``` -------------------------------- ### Tagging a Release with Git Source: https://github.com/livekit/client-sdk-android/blob/main/release-instructions.md Tag the release using git. Ensure the tag has a 'v' prefix to indicate a release tag for CI. ```bash git tag v[VERSION_NAME] ``` -------------------------------- ### Configure Room for Media Playback Audio Source: https://github.com/livekit/client-sdk-android/blob/main/README.md Creates a Room object with AudioType set to MediaAudioType for livestreaming or media playback applications, optimizing audio quality for these use cases. System handles audio routing automatically. ```kotlin val room = LiveKit.create( appContext = application, overrides = LiveKitOverrides( audioOptions = AudioOptions( audioOutputType = AudioType.MediaAudioType() ) ) ) ``` -------------------------------- ### Configure Gradle for Apple Silicon (Mac) Source: https://github.com/livekit/client-sdk-android/blob/main/README.md For Mac users with Apple silicon (M1, M2, etc.), add this property to your $HOME/.gradle/gradle.properties file to ensure correct platform detection. ```properties protoc_platform=osx-x86_64 ``` -------------------------------- ### Clone LiveKit Android SDK Repository Source: https://github.com/livekit/client-sdk-android/blob/main/README.md Clone the official LiveKit Android SDK repository and navigate into the project directory. ```bash git clone https://github.com/livekit/client-sdk-android.git cd client-sdk-android git submodule update --init ``` -------------------------------- ### Android SDK Dependencies Source: https://github.com/livekit/client-sdk-android/blob/main/README.md Add these dependencies to your app's `build.gradle` file to include the LiveKit Android SDK and optional modules. ```groovy def livekit_version = "2.26.0" implementation "io.livekit:livekit-android:$livekit_version" // CameraX support with pinch to zoom, torch control, etc. implementation "io.livekit:livekit-android-camerax:$livekit_version" // Track processors, such as virtual background implementation "io.livekit:livekit-android-track-processors:$livekit_version" // Snapshots of the latest development version are available at: // implementation "io.livekit:livekit-android:2.26.1-SNAPSHOT" ``` -------------------------------- ### Implementing @FlowObservable Property Delegate Source: https://github.com/livekit/client-sdk-android/blob/main/AGENTS.md Shows how to use the flowDelegate property delegate to create a class member that is both a regular variable and observable as a Flow. ```kotlin @FlowObservable @get:FlowObservable var identity: Identity? by flowDelegate(identity) ``` -------------------------------- ### Pushing Git Tags Source: https://github.com/livekit/client-sdk-android/blob/main/release-instructions.md Push all tags to the remote repository. ```bash git push --tags ``` -------------------------------- ### Add CameraX Dependency Source: https://github.com/livekit/client-sdk-android/blob/main/livekit-android-camerax/README.md Include the CameraX library in your app's build.gradle file to enable advanced camera functionalities. ```groovy dependencies { implementation "io.livekit:livekit-android-camerax:" } ``` -------------------------------- ### Capture Local Microphone Audio Data Source: https://github.com/livekit/client-sdk-android/wiki/Capturing-Audio-Data Use `setSamplesReadyCallback` on `JavaAudioDeviceModule.Builder` to capture local microphone audio. The audio data is provided as a ByteArray. ```kotlin val room = LiveKit.create( appContext = application, overrides = LiveKitOverrides( audioOptions = AudioOptions( javaAudioDeviceModuleCustomizer = { builder: JavaAudioDeviceModule.Builder -> // Listen to the local microphone's audio builder.setSamplesReadyCallback { audioSamples: JavaAudioDeviceModule.AudioSamples -> processAudioData(audioSamples.data) } } ) ) ) ``` -------------------------------- ### Capture Mixed Remote Audio Data Source: https://github.com/livekit/client-sdk-android/wiki/Capturing-Audio-Data Capture mixed remote audio by setting `setPlaybackSamplesReadyCallback` on `JavaAudioDeviceModule.Builder`. This callback receives audio data for all remote participants. ```kotlin val room = LiveKit.create( appContext = application, options = RoomOptions(adaptiveStream = true, dynacast = true), overrides = LiveKitOverrides( audioOptions = AudioOptions( javaAudioDeviceModuleCustomizer = { builder: JavaAudioDeviceModule.Builder -> builder.setPlaybackSamplesReadyCallback { audioSamples : JavaAudioDeviceModule.AudioSamples -> // Process audio data... processAudioData(audioSamples.data) } } ) ) ) ``` -------------------------------- ### Take a High-Quality Picture Source: https://github.com/livekit/client-sdk-android/blob/main/livekit-android-camerax/README.md Capture a high-quality image and save it to a specified file. This function uses the pre-configured ImageCapture use case. ```kotlin fun takeHighQualityPicture() { val outputOptions = ImageCapture.OutputFileOptions.Builder( File(getApplication().filesDir, "high_quality_picture.jpg") ).build() imageCapture.takePicture( outputOptions, ContextCompat.getMainExecutor(getApplication()), object : ImageCapture.OnImageSavedCallback { override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) { Log.d(TAG, "Image saved successfully: ${outputFileResults.savedUri}") } override fun onError(exception: ImageCaptureException) { Log.e(TAG, "Error capturing image", exception) } } ) } ``` -------------------------------- ### Process 16-bit PCM Audio Data Source: https://github.com/livekit/client-sdk-android/wiki/Capturing-Audio-Data This function processes raw audio data, assuming 16-bit PCM encoding. It wraps the byte array in a ByteBuffer to handle endianness and extracts 16-bit short values. ```kotlin fun processAudioData(audioData: ByteArray) { // Wrap in a ByteBuffer to handle endianness val byteBuffer = ByteBuffer .wrap(audioData) .order(ByteOrder.nativeOrder()) while (byteBuffer.hasRemaining() && byteBuffer.remaining() >= 2) { // Short is 16-bits val value = byteBuffer.getShort() // ... } } ``` -------------------------------- ### Add Sink to Remote Audio Track Source: https://github.com/livekit/client-sdk-android/wiki/Capturing-Audio-Data Access individual remote track audio by adding an `AudioTrackSink` to a `RemoteAudioTrack`. The `onData` callback provides detailed audio buffer information. ```kotlin val audioTrackSink = object: AudioTrackSink { override fun onData( audioData: ByteBuffer?, bitsPerSample: Int, sampleRate: Int, numberOfChannels: Int, numberOfFrames: Int, absoluteCaptureTimestampMs: Long ) { handleAudioData(audioData) } } remoteAudioTrack.addSink(audioTrackSink) ``` -------------------------------- ### Observe Active Speakers using Kotlin Flow Source: https://github.com/livekit/client-sdk-android/blob/main/README.md Accesses the 'activeSpeakers' property as a Kotlin Flow to observe changes in the list of active speakers in real-time. ```kotlin coroutineScope.launch { room::activeSpeakers.flow.collectLatest { speakersList -> /*...*/ } } ``` -------------------------------- ### Accessing Participant Identity as Flow and State Source: https://github.com/livekit/client-sdk-android/blob/main/AGENTS.md Demonstrates how to access a participant's identity as a regular variable, a Kotlin Flow, and a Compose State object using the @FlowObservable annotation and the flow extension. ```kotlin val identity = participant.identity // regular access val identityFlow = participant::identity.flow // as a flow val identityState = participant::identity.flow.collectAsState() // as a state ``` -------------------------------- ### Process Remote Audio Track Data Source: https://github.com/livekit/client-sdk-android/wiki/Capturing-Audio-Data This function processes audio data received from a remote track sink. It assumes the data is in a ByteBuffer and extracts 16-bit short values. ```kotlin fun processAudioData(audioData: ByteBuffer) { while (byteBuffer.hasRemaining() && byteBuffer.remaining() >= 2) { val value = byteBuffer.getShort() // ... } } ``` -------------------------------- ### Control Camera Zoom Source: https://github.com/livekit/client-sdk-android/blob/main/livekit-android-camerax/README.md Adjust the camera's zoom level programmatically. This function scales the current zoom ratio by a given factor, clamping it within the camera's supported zoom range. ```kotlin fun zoom(factor: Float) { val camera = localVideoTrack.capturer.getCameraX()?.value ?: return val zoomState = camera.cameraInfo.zoomState.value ?: return val currentZoom = zoomState.zoomRatio val newZoom = (currentZoom * factor).coerceIn(zoomState.minZoomRatio, zoomState.maxZoomRatio) if (newZoom != currentZoom) { camera.cameraControl.setZoomRatio(newZoom) } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.