I want to play some audio with volume lvl adjusted to ear aka. "phone call mode". For this purpose I'm using well-known and commonly advised
audioManager.setMode(audioNormalState ?
AudioManager.MODE_NORMAL : AudioManager.MODE_IN_COMMUNICATION);
The problem is that I'm not always playing audio just after mode switching, I have to wait and can't be shure how long, it may be even minutes. I've made some looped logging and MODE_IN_COMMUNICATION mode is kept as long as user is in "phone call mode" in my app on some Motorola with Android 9, but on Pixel 3 with Android 12 after 6 seconds mode is auto-switching back to MODE_NORMAL, when nothing is played. No additional code executed (like some listener), no additional (system) logs. When I start playing audio 1 sec after switching to MODE_IN_COMMUNICATION mode it won't auto-switch as long as audio is played (even more than 6 secs), but right after finishing mode gets also auto-switched to MODE_NORMAL.
My app makes sort-of real-time voice calls (commands), but can also "beep" few signals-patterns, and there is also history feature providing all chronological sound-making actions to be played again in order. If this would be only voice then switching to MODE_IN_COMMUNICATION and back only during call might be sufficient, but what to do with highly-important SoundPool jingles, do I have to switch mode also for them? (or for history play, which is a mix) AFAIK mode switching isn't fast (even few secs on some devices), so I may apply some significant delay for short hundreds-of-ms signals (no way, every ms is crucial!) or I'm risking playing out loud signal/voice even in "phone call mode", when mode doesn't change "fast enough" (user won't be happy). I was relying on setting fixed (but configured according to app state and settings) MODE_IN_COMMUNICATION, which was working till Android 12... (can confirm new/wrong behavior on Pixels and Samsungs)
currently used method for switching audio mode + configuration below, worth noting that setSpeakerphoneOn method also doesn't work always on Android 12. At least not when on MODE_NORMAL, which is default auto-switch-back-to mode now, also isSpeakerphoneOn is false on very first start, but all my audio sources are in fact played loud...
// forceAudioNormalState = true only when app exit!
public static void resolveLoudState(AudioManager audioManager, boolean forceAudioNormalState) {
boolean silentPhoneCallMode = isPhoneCallModeEnabled(); // phone call GUI, only ear-friendly volume!!
boolean silentHeadset = HeadsetPlugReceiver.isHeadsetPlugged &&
!HeadsetPlugReceiver.forceSpeakerWhenHeadsetOn; // headset plugged, but "muted", force speaker
boolean silentBluetooth = BluetoothController.isAudioDeviceConnected() &&
!audioManager.isBluetoothScoOn(); // bt headset plugged, but "muted", force speaker
boolean loud = true; // by default
if (silentPhoneCallMode || silentHeadset || silentBluetooth) loud = false;
String log = String.format("resolveLoudState play loud: %s," +
" silentPhoneCallMode: %s, silentHeadset: %s, silentBluetooth: %s",
loud, silentPhoneCallMode, silentHeadset, silentBluetooth);
Timber.i(log);
audioManager.setMode(forceAudioNormalState ?
AudioManager.MODE_NORMAL : AudioManager.MODE_IN_COMMUNICATION);
audioManager.setSpeakerphoneOn(loud);
// even if deprecated this still works! fake wired headset on even for bt
audioManager.setWiredHeadsetOn(!loud && (silentHeadset || silentBluetooth));
// not loud and any headset connected and "muted"
}
note that in above snippet there is no flag/information about current playing state, only apps state/config
I want to manage these modes by myself and decide which audio output will be used or maybe there is any other way for forcing playing all audio (AudioTrack, SoundPool, MediaPlayer, ExoPlayer etc.) with ear-friendly adjusted volume?
edit: Just noticed when mode auto-switches to MODE_NORMAL and I will start playing STREAM_VOICE_CALL it will auto switch to MODE_IN_COMMUNICATION (with some small but significant delay) and reset back again just after finishing audio... This is some new undocumented behavior of system overal, become very unfriendly, bugged and unclear API...
edit2: this looks like related issue
PS. I've noticed that MediaSession apps (e.g. music players) on Android 12 device got new option straight on Notification for picking speaker/headphones when wired/bt headset/earphones connected, but I'm not using session API at all. bonus question: is there an API for that?
from AudioManager auto switching own mode + not respecting setSpeakerphoneOn()
No comments:
Post a Comment