Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Turn off audio routing for non communication audio modes #261

Merged
merged 3 commits into from
Sep 8, 2023
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
2 changes: 1 addition & 1 deletion livekit-android-sdk/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,

Expand All @@ -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
)
Expand All @@ -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,
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -49,25 +48,15 @@ object AudioHandlerModule {
@Singleton
fun audioHandler(
audioSwitchHandler: Provider<AudioSwitchHandler>,
audioFocusHandler: Provider<AudioFocusHandler>,
@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
}
}
}