davidliu
Committed by GitHub

Audio changes (#579)

* Explicitly expose AudioSwitchHandler

* Default prioritizing speaker over earpiece
  1 +---
  2 +"client-sdk-android": minor
  3 +---
  4 +
  5 +Default prioritizing speaker over earpiece
  1 +---
  2 +"client-sdk-android": minor
  3 +---
  4 +
  5 +Explicitly expose AudioSwitchHandler from Room for easier audio handling
1 /* 1 /*
2 - * Copyright 2023-2024 LiveKit, Inc. 2 + * Copyright 2023-2025 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -27,7 +27,8 @@ import javax.inject.Inject @@ -27,7 +27,8 @@ import javax.inject.Inject
27 import javax.inject.Singleton 27 import javax.inject.Singleton
28 28
29 /** 29 /**
30 - * An [AudioHandler] built on top of [AudioSwitch]. 30 + * An [AudioHandler] built on top of [AudioSwitch]. This handles things such as
  31 + * getting the audio focus as needed, as well as automatic audio output device management.
31 * 32 *
32 * The various settings should be set before connecting to a [Room] and [start] is called. 33 * The various settings should be set before connecting to a [Room] and [start] is called.
33 */ 34 */
@@ -222,8 +223,8 @@ constructor(private val context: Context) : AudioHandler { @@ -222,8 +223,8 @@ constructor(private val context: Context) : AudioHandler {
222 listOf( 223 listOf(
223 AudioDevice.BluetoothHeadset::class.java, 224 AudioDevice.BluetoothHeadset::class.java,
224 AudioDevice.WiredHeadset::class.java, 225 AudioDevice.WiredHeadset::class.java,
225 - AudioDevice.Earpiece::class.java,  
226 AudioDevice.Speakerphone::class.java, 226 AudioDevice.Speakerphone::class.java,
  227 + AudioDevice.Earpiece::class.java,
227 ) 228 )
228 } 229 }
229 } 230 }
@@ -26,10 +26,13 @@ import dagger.assisted.Assisted @@ -26,10 +26,13 @@ import dagger.assisted.Assisted
26 import dagger.assisted.AssistedFactory 26 import dagger.assisted.AssistedFactory
27 import dagger.assisted.AssistedInject 27 import dagger.assisted.AssistedInject
28 import io.livekit.android.ConnectOptions 28 import io.livekit.android.ConnectOptions
  29 +import io.livekit.android.LiveKit
  30 +import io.livekit.android.LiveKitOverrides
29 import io.livekit.android.RoomOptions 31 import io.livekit.android.RoomOptions
30 import io.livekit.android.Version 32 import io.livekit.android.Version
31 import io.livekit.android.audio.AudioHandler 33 import io.livekit.android.audio.AudioHandler
32 import io.livekit.android.audio.AudioProcessingController 34 import io.livekit.android.audio.AudioProcessingController
  35 +import io.livekit.android.audio.AudioSwitchHandler
33 import io.livekit.android.audio.AuthedAudioProcessingController 36 import io.livekit.android.audio.AuthedAudioProcessingController
34 import io.livekit.android.audio.CommunicationWorkaround 37 import io.livekit.android.audio.CommunicationWorkaround
35 import io.livekit.android.dagger.InjectionNames 38 import io.livekit.android.dagger.InjectionNames
@@ -77,6 +80,17 @@ constructor( @@ -77,6 +80,17 @@ constructor(
77 private val defaultDispatcher: CoroutineDispatcher, 80 private val defaultDispatcher: CoroutineDispatcher,
78 @Named(InjectionNames.DISPATCHER_IO) 81 @Named(InjectionNames.DISPATCHER_IO)
79 private val ioDispatcher: CoroutineDispatcher, 82 private val ioDispatcher: CoroutineDispatcher,
  83 + /**
  84 + * The [AudioHandler] for setting up the audio as need.
  85 + *
  86 + * By default, this is an instance of [AudioSwitchHandler].
  87 + *
  88 + * This can be substituted for your own custom implementation through
  89 + * [LiveKitOverrides.audioOptions] when creating the room with [LiveKit.create].
  90 + *
  91 + * @see [audioSwitchHandler]
  92 + * @see [AudioSwitchHandler]
  93 + */
80 val audioHandler: AudioHandler, 94 val audioHandler: AudioHandler,
81 private val closeableManager: CloseableManager, 95 private val closeableManager: CloseableManager,
82 private val e2EEManagerFactory: E2EEManager.Factory, 96 private val e2EEManagerFactory: E2EEManager.Factory,
@@ -272,6 +286,14 @@ constructor( @@ -272,6 +286,14 @@ constructor(
272 val remoteParticipants: Map<Participant.Identity, RemoteParticipant> 286 val remoteParticipants: Map<Participant.Identity, RemoteParticipant>
273 get() = mutableRemoteParticipants 287 get() = mutableRemoteParticipants
274 288
  289 + /**
  290 + * A convenience getter for the audio handler as a [AudioSwitchHandler].
  291 + *
  292 + * Will return null if [audioHandler] is not a [AudioSwitchHandler].
  293 + */
  294 + val audioSwitchHandler: AudioSwitchHandler?
  295 + get() = audioHandler as? AudioSwitchHandler
  296 +
275 private var sidToIdentity = mutableMapOf<Participant.Sid, Participant.Identity>() 297 private var sidToIdentity = mutableMapOf<Participant.Sid, Participant.Identity>()
276 298
277 private var mutableActiveSpeakers by flowDelegate(emptyList<Participant>()) 299 private var mutableActiveSpeakers by flowDelegate(emptyList<Participant>())