davidliu
Committed by GitHub

Turn off audio routing for non communication audio modes (#261)

* Turn off audio routing for non communication audio modes

* update audioswitch commit

* update audioswitch
@@ -140,7 +140,7 @@ dependencies { @@ -140,7 +140,7 @@ dependencies {
140 implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.1.0' 140 implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.1.0'
141 api 'io.github.webrtc-sdk:android:104.5112.10' 141 api 'io.github.webrtc-sdk:android:104.5112.10'
142 api "com.squareup.okhttp3:okhttp:4.10.0" 142 api "com.squareup.okhttp3:okhttp:4.10.0"
143 - api 'com.github.davidliu:audioswitch:7b55cec426227a75be25b0d7ad8537d4aede2a2a' 143 + api 'com.github.davidliu:audioswitch:d18e3e31d427c27f1593030e024b370bf24480fd'
144 implementation "androidx.annotation:annotation:1.4.0" 144 implementation "androidx.annotation:annotation:1.4.0"
145 implementation "androidx.core:core:${versions.androidx_core}" 145 implementation "androidx.core:core:${versions.androidx_core}"
146 implementation "com.google.protobuf:protobuf-javalite:${versions.protobuf}" 146 implementation "com.google.protobuf:protobuf-javalite:${versions.protobuf}"
@@ -58,13 +58,16 @@ class AudioOptions( @@ -58,13 +58,16 @@ class AudioOptions(
58 * This affects the audio routing and how the audio is handled. Default is [AudioType.CallAudioType]. 58 * This affects the audio routing and how the audio is handled. Default is [AudioType.CallAudioType].
59 * 59 *
60 * Note: if [audioHandler] is also passed, the values from [audioOutputType] will not be reflected in it, 60 * Note: if [audioHandler] is also passed, the values from [audioOutputType] will not be reflected in it,
61 - * and must be set manually. 61 + * and must be set yourself.
62 */ 62 */
63 val audioOutputType: AudioType? = null, 63 val audioOutputType: AudioType? = null,
64 /** 64 /**
65 * Override the default [AudioHandler]. 65 * Override the default [AudioHandler].
66 * 66 *
67 - * Use [NoAudioHandler] to turn off automatic audio handling. 67 + * Default is [AudioSwitchHandler].
  68 + *
  69 + * Use [NoAudioHandler] to turn off automatic audio handling or
  70 + * [AudioFocusHandler] to get simple audio focus handling.
68 */ 71 */
69 val audioHandler: AudioHandler? = null, 72 val audioHandler: AudioHandler? = null,
70 73
@@ -81,20 +84,22 @@ class AudioOptions( @@ -81,20 +84,22 @@ class AudioOptions(
81 val javaAudioDeviceModuleCustomizer: ((builder: JavaAudioDeviceModule.Builder) -> Unit)? = null, 84 val javaAudioDeviceModuleCustomizer: ((builder: JavaAudioDeviceModule.Builder) -> Unit)? = null,
82 ) 85 )
83 86
84 -sealed class AudioType(val audioMode: Int, val audioAttributes: AudioAttributes, val audioStreamType: Int) { 87 +sealed class AudioType(
  88 + val audioMode: Int,
  89 + val audioAttributes: AudioAttributes,
  90 + val audioStreamType: Int
  91 +) {
85 /** 92 /**
86 * An audio type for general media playback usage (i.e. listener-only use cases). 93 * An audio type for general media playback usage (i.e. listener-only use cases).
87 * 94 *
88 * Audio routing is handled automatically by the system in normal media mode, 95 * Audio routing is handled automatically by the system in normal media mode,
89 * and bluetooth microphones may not work on some devices. 96 * and bluetooth microphones may not work on some devices.
90 - *  
91 - * The default [AudioHandler] for this type is [AudioFocusHandler].  
92 */ 97 */
93 class MediaAudioType : AudioType( 98 class MediaAudioType : AudioType(
94 AudioManager.MODE_NORMAL, 99 AudioManager.MODE_NORMAL,
95 AudioAttributes.Builder() 100 AudioAttributes.Builder()
96 .setUsage(AudioAttributes.USAGE_MEDIA) 101 .setUsage(AudioAttributes.USAGE_MEDIA)
97 - .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) 102 + .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
98 .build(), 103 .build(),
99 AudioManager.STREAM_MUSIC 104 AudioManager.STREAM_MUSIC
100 ) 105 )
@@ -103,8 +108,6 @@ sealed class AudioType(val audioMode: Int, val audioAttributes: AudioAttributes, @@ -103,8 +108,6 @@ sealed class AudioType(val audioMode: Int, val audioAttributes: AudioAttributes,
103 * An audio type for calls (i.e. participating in the call or publishing local microphone). 108 * An audio type for calls (i.e. participating in the call or publishing local microphone).
104 * 109 *
105 * Audio routing can be manually controlled. 110 * Audio routing can be manually controlled.
106 - *  
107 - * The default [AudioHandler] for this type is [AudioSwitchHandler].  
108 */ 111 */
109 class CallAudioType : AudioType( 112 class CallAudioType : AudioType(
110 AudioManager.MODE_IN_COMMUNICATION, 113 AudioManager.MODE_IN_COMMUNICATION,
@@ -117,8 +120,6 @@ sealed class AudioType(val audioMode: Int, val audioAttributes: AudioAttributes, @@ -117,8 +120,6 @@ sealed class AudioType(val audioMode: Int, val audioAttributes: AudioAttributes,
117 120
118 /** 121 /**
119 * An audio type that takes in a user-defined [AudioAttributes] and audio stream type. 122 * An audio type that takes in a user-defined [AudioAttributes] and audio stream type.
120 - *  
121 - * The default [AudioHandler] for this type is [AudioFocusHandler].  
122 */ 123 */
123 class CustomAudioType(audioMode: Int, audioAttributes: AudioAttributes, audioStreamType: Int) : 124 class CustomAudioType(audioMode: Int, audioAttributes: AudioAttributes, audioStreamType: Int) :
124 AudioType(audioMode, audioAttributes, audioStreamType) 125 AudioType(audioMode, audioAttributes, audioStreamType)
@@ -35,6 +35,7 @@ import javax.inject.Singleton @@ -35,6 +35,7 @@ import javax.inject.Singleton
35 class AudioSwitchHandler 35 class AudioSwitchHandler
36 @Inject 36 @Inject
37 constructor(private val context: Context) : AudioHandler { 37 constructor(private val context: Context) : AudioHandler {
  38 +
38 /** 39 /**
39 * Toggle whether logging is enabled for [AudioSwitch]. By default, this is set to false. 40 * Toggle whether logging is enabled for [AudioSwitch]. By default, this is set to false.
40 */ 41 */
@@ -124,6 +125,15 @@ constructor(private val context: Context) : AudioHandler { @@ -124,6 +125,15 @@ constructor(private val context: Context) : AudioHandler {
124 */ 125 */
125 var audioAttributeContentType: Int = AudioAttributes.CONTENT_TYPE_SPEECH 126 var audioAttributeContentType: Int = AudioAttributes.CONTENT_TYPE_SPEECH
126 127
  128 + /**
  129 + * On certain Android devices, audio routing does not function properly and bluetooth microphones will not work
  130 + * unless audio mode is set to [AudioManager.MODE_IN_COMMUNICATION] or [AudioManager.MODE_IN_CALL].
  131 + *
  132 + * AudioSwitchHandler by default will not handle audio routing in those cases to avoid audio issues.
  133 + *
  134 + * If this set to true, AudioSwitchHandler will attempt to do audio routing, though behavior is undefined.
  135 + */
  136 + var forceHandleAudioRouting = false
127 137
128 private var audioSwitch: AbstractAudioSwitch? = null 138 private var audioSwitch: AbstractAudioSwitch? = null
129 139
@@ -156,6 +166,7 @@ constructor(private val context: Context) : AudioHandler { @@ -156,6 +166,7 @@ constructor(private val context: Context) : AudioHandler {
156 switch.audioStreamType = audioStreamType 166 switch.audioStreamType = audioStreamType
157 switch.audioAttributeUsageType = audioAttributeUsageType 167 switch.audioAttributeUsageType = audioAttributeUsageType
158 switch.audioAttributeContentType = audioAttributeContentType 168 switch.audioAttributeContentType = audioAttributeContentType
  169 + switch.forceHandleAudioRouting = forceHandleAudioRouting
159 170
160 audioSwitch = switch 171 audioSwitch = switch
161 switch.start(audioDeviceChangeListener ?: defaultAudioDeviceChangeListener) 172 switch.start(audioDeviceChangeListener ?: defaultAudioDeviceChangeListener)
@@ -20,7 +20,6 @@ import android.media.AudioAttributes @@ -20,7 +20,6 @@ import android.media.AudioAttributes
20 import dagger.Module 20 import dagger.Module
21 import dagger.Provides 21 import dagger.Provides
22 import io.livekit.android.AudioType 22 import io.livekit.android.AudioType
23 -import io.livekit.android.audio.AudioFocusHandler  
24 import io.livekit.android.audio.AudioHandler 23 import io.livekit.android.audio.AudioHandler
25 import io.livekit.android.audio.AudioSwitchHandler 24 import io.livekit.android.audio.AudioSwitchHandler
26 import javax.inject.Named 25 import javax.inject.Named
@@ -49,25 +48,15 @@ object AudioHandlerModule { @@ -49,25 +48,15 @@ object AudioHandlerModule {
49 @Singleton 48 @Singleton
50 fun audioHandler( 49 fun audioHandler(
51 audioSwitchHandler: Provider<AudioSwitchHandler>, 50 audioSwitchHandler: Provider<AudioSwitchHandler>,
52 - audioFocusHandler: Provider<AudioFocusHandler>,  
53 @Named(InjectionNames.OVERRIDE_AUDIO_HANDLER) 51 @Named(InjectionNames.OVERRIDE_AUDIO_HANDLER)
54 audioHandlerOverride: AudioHandler?, 52 audioHandlerOverride: AudioHandler?,
55 audioOutputType: AudioType, 53 audioOutputType: AudioType,
56 ): AudioHandler { 54 ): AudioHandler {
57 - return audioHandlerOverride ?: when (audioOutputType) {  
58 - is AudioType.CallAudioType -> {  
59 - audioSwitchHandler.get().apply {  
60 - audioMode = audioOutputType.audioMode  
61 - audioAttributeContentType = audioOutputType.audioAttributes.contentType  
62 - audioAttributeUsageType = audioOutputType.audioAttributes.usage  
63 - audioStreamType = audioOutputType.audioStreamType  
64 - }  
65 - }  
66 -  
67 - is AudioType.MediaAudioType,  
68 - is AudioType.CustomAudioType -> {  
69 - audioFocusHandler.get()  
70 - } 55 + return audioHandlerOverride ?: audioSwitchHandler.get().apply {
  56 + audioMode = audioOutputType.audioMode
  57 + audioAttributeContentType = audioOutputType.audioAttributes.contentType
  58 + audioAttributeUsageType = audioOutputType.audioAttributes.usage
  59 + audioStreamType = audioOutputType.audioStreamType
71 } 60 }
72 } 61 }
73 } 62 }