diff --git a/livekit-android-sdk/build.gradle b/livekit-android-sdk/build.gradle index f6980485..713ab4aa 100644 --- a/livekit-android-sdk/build.gradle +++ b/livekit-android-sdk/build.gradle @@ -140,7 +140,7 @@ dependencies { implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.1.0' api 'io.github.webrtc-sdk:android:104.5112.10' api "com.squareup.okhttp3:okhttp:4.10.0" - api 'com.github.davidliu:audioswitch:7b55cec426227a75be25b0d7ad8537d4aede2a2a' + api 'com.github.davidliu:audioswitch:d18e3e31d427c27f1593030e024b370bf24480fd' implementation "androidx.annotation:annotation:1.4.0" implementation "androidx.core:core:${versions.androidx_core}" implementation "com.google.protobuf:protobuf-javalite:${versions.protobuf}" diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/LiveKitOverrides.kt b/livekit-android-sdk/src/main/java/io/livekit/android/LiveKitOverrides.kt index a4979c73..1c7c4a04 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/LiveKitOverrides.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/LiveKitOverrides.kt @@ -58,13 +58,16 @@ class AudioOptions( * This affects the audio routing and how the audio is handled. Default is [AudioType.CallAudioType]. * * Note: if [audioHandler] is also passed, the values from [audioOutputType] will not be reflected in it, - * and must be set manually. + * and must be set yourself. */ val audioOutputType: AudioType? = null, /** * Override the default [AudioHandler]. * - * Use [NoAudioHandler] to turn off automatic audio handling. + * Default is [AudioSwitchHandler]. + * + * Use [NoAudioHandler] to turn off automatic audio handling or + * [AudioFocusHandler] to get simple audio focus handling. */ val audioHandler: AudioHandler? = null, @@ -81,20 +84,22 @@ class AudioOptions( val javaAudioDeviceModuleCustomizer: ((builder: JavaAudioDeviceModule.Builder) -> Unit)? = null, ) -sealed class AudioType(val audioMode: Int, val audioAttributes: AudioAttributes, val audioStreamType: Int) { +sealed class AudioType( + val audioMode: Int, + val audioAttributes: AudioAttributes, + val audioStreamType: Int +) { /** * An audio type for general media playback usage (i.e. listener-only use cases). * * Audio routing is handled automatically by the system in normal media mode, * and bluetooth microphones may not work on some devices. - * - * The default [AudioHandler] for this type is [AudioFocusHandler]. */ class MediaAudioType : AudioType( AudioManager.MODE_NORMAL, AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_MEDIA) - .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) + .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN) .build(), AudioManager.STREAM_MUSIC ) @@ -103,8 +108,6 @@ sealed class AudioType(val audioMode: Int, val audioAttributes: AudioAttributes, * An audio type for calls (i.e. participating in the call or publishing local microphone). * * Audio routing can be manually controlled. - * - * The default [AudioHandler] for this type is [AudioSwitchHandler]. */ class CallAudioType : AudioType( AudioManager.MODE_IN_COMMUNICATION, @@ -117,8 +120,6 @@ sealed class AudioType(val audioMode: Int, val audioAttributes: AudioAttributes, /** * An audio type that takes in a user-defined [AudioAttributes] and audio stream type. - * - * The default [AudioHandler] for this type is [AudioFocusHandler]. */ class CustomAudioType(audioMode: Int, audioAttributes: AudioAttributes, audioStreamType: Int) : AudioType(audioMode, audioAttributes, audioStreamType) diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/audio/AudioSwitchHandler.kt b/livekit-android-sdk/src/main/java/io/livekit/android/audio/AudioSwitchHandler.kt index f651e0b0..0789b5d4 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/audio/AudioSwitchHandler.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/audio/AudioSwitchHandler.kt @@ -35,6 +35,7 @@ import javax.inject.Singleton class AudioSwitchHandler @Inject constructor(private val context: Context) : AudioHandler { + /** * Toggle whether logging is enabled for [AudioSwitch]. By default, this is set to false. */ @@ -124,6 +125,15 @@ constructor(private val context: Context) : AudioHandler { */ var audioAttributeContentType: Int = AudioAttributes.CONTENT_TYPE_SPEECH + /** + * On certain Android devices, audio routing does not function properly and bluetooth microphones will not work + * unless audio mode is set to [AudioManager.MODE_IN_COMMUNICATION] or [AudioManager.MODE_IN_CALL]. + * + * AudioSwitchHandler by default will not handle audio routing in those cases to avoid audio issues. + * + * If this set to true, AudioSwitchHandler will attempt to do audio routing, though behavior is undefined. + */ + var forceHandleAudioRouting = false private var audioSwitch: AbstractAudioSwitch? = null @@ -156,6 +166,7 @@ constructor(private val context: Context) : AudioHandler { switch.audioStreamType = audioStreamType switch.audioAttributeUsageType = audioAttributeUsageType switch.audioAttributeContentType = audioAttributeContentType + switch.forceHandleAudioRouting = forceHandleAudioRouting audioSwitch = switch switch.start(audioDeviceChangeListener ?: defaultAudioDeviceChangeListener) diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/dagger/AudioHandlerModule.kt b/livekit-android-sdk/src/main/java/io/livekit/android/dagger/AudioHandlerModule.kt index 3593715b..bc4d075d 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/dagger/AudioHandlerModule.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/dagger/AudioHandlerModule.kt @@ -20,7 +20,6 @@ import android.media.AudioAttributes import dagger.Module import dagger.Provides import io.livekit.android.AudioType -import io.livekit.android.audio.AudioFocusHandler import io.livekit.android.audio.AudioHandler import io.livekit.android.audio.AudioSwitchHandler import javax.inject.Named @@ -49,25 +48,15 @@ object AudioHandlerModule { @Singleton fun audioHandler( audioSwitchHandler: Provider, - audioFocusHandler: Provider, @Named(InjectionNames.OVERRIDE_AUDIO_HANDLER) audioHandlerOverride: AudioHandler?, audioOutputType: AudioType, ): AudioHandler { - return audioHandlerOverride ?: when (audioOutputType) { - is AudioType.CallAudioType -> { - audioSwitchHandler.get().apply { - audioMode = audioOutputType.audioMode - audioAttributeContentType = audioOutputType.audioAttributes.contentType - audioAttributeUsageType = audioOutputType.audioAttributes.usage - audioStreamType = audioOutputType.audioStreamType - } - } - - is AudioType.MediaAudioType, - is AudioType.CustomAudioType -> { - audioFocusHandler.get() - } + return audioHandlerOverride ?: audioSwitchHandler.get().apply { + audioMode = audioOutputType.audioMode + audioAttributeContentType = audioOutputType.audioAttributes.contentType + audioAttributeUsageType = audioOutputType.audioAttributes.usage + audioStreamType = audioOutputType.audioStreamType } } } \ No newline at end of file