-
Notifications
You must be signed in to change notification settings - Fork 108
Description
Describe the bug
I have a class which sets a TtsNavigator through
val ttsNavigator = ttsNavigatorFactory?.createNavigator(
this,
initialLocator = locator,
initialPreferences = preferencesManager.value
)
When I play it, I request the audio focus because I want to control what happens when there's a gain/loss of audio focus (with incoming messages, calls etc).
However, whenever I run ttsNavigator.play()
and request the focus, it's immediately lost. This is the code related to audio focusing:
private val focusRequest
@RequiresApi(Build.VERSION_CODES.O)
get() = AudioFocusRequest.Builder(AUDIOFOCUS_GAIN).run {
setAudioAttributes(AudioAttributes.Builder().run {
setUsage(AudioAttributes.USAGE_MEDIA)
setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
setWillPauseWhenDucked(true)
build()
})
setAcceptsDelayedFocusGain(true)
setOnAudioFocusChangeListener(afChangeListener)
build()
}
private val afChangeListener = AudioManager.OnAudioFocusChangeListener { focusChange ->
when (focusChange) {
AUDIOFOCUS_LOSS -> {
abandonAudioFocusRequest()
navigatorNow.value?.pause()
}
AUDIOFOCUS_LOSS_TRANSIENT, AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> navigatorNow.value?.pause()
AUDIOFOCUS_GAIN -> navigatorNow.value?.play()
}
}
@Suppress("DEPRECATION")
private fun abandonAudioFocusRequest() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
audioManager?.abandonAudioFocusRequest(focusRequest)
} else {
audioManager?.abandonAudioFocus(afChangeListener)
}
}
@Suppress("DEPRECATION")
private fun requestAudioFocus(): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
audioManager?.requestAudioFocus(focusRequest) == AUDIOFOCUS_REQUEST_GRANTED
} else {
audioManager?.requestAudioFocus(
afChangeListener,
AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN
) == AUDIOFOCUS_REQUEST_GRANTED
}
}
fun play() {
navigatorNow.value?.play()
requestAudioFocus()
}
As mentioned, when I start playing the TTS, I get AUDIOFOCUS_LOSS
here:
when (focusChange) {
AUDIOFOCUS_LOSS -> {
abandonAudioFocusRequest()
navigatorNow.value?.pause()
}
AUDIOFOCUS_LOSS_TRANSIENT, AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> navigatorNow.value?.pause()
AUDIOFOCUS_GAIN -> navigatorNow.value?.play()
}
}
Once I lose the audio focus, I can't do anything with the listener anymore.
One thing that I noticed in the logs is that it seems that Readium "steals" the focus when I hit play. I find this a bit weird, because Readium is being executed in my application, and so it should not steal the focus.
I saw in the Readium code that there is audio focus management.
Here are some logs that I found:
requestAudioFocus() from uid/pid 11799/7267 AA=USAGE_MEDIA/CONTENT_TYPE_SPEECH clientId=android.media.AudioManager@becd5abee.<my class>$$ExternalSyntheticLambda0@a334408 callingPack=<package> req=1 flags=0x3 sdk=34
requestAudioFocus() from uid/pid 11799/7267 AA=USAGE_MEDIA/CONTENT_TYPE_SPEECH clientId=android.media.AudioManager@becd5aborg.readium.navigator.media.tts.session.AudioFocusManager$AudioFocusListener@b212187 callingPack=<package> req=1 flags=0x2 sdk=34
dispatching onAudioFocusChange(-1) to android.media.AudioManager@becd5abee.<my class>$$ExternalSyntheticLambda0@a334408
abandonAudioFocus() from uid/pid 11799/7267 clientId=android.media.AudioManager@becd5abee.<my class>$$ExternalSyntheticLambda0@a334408
abandonAudioFocus, clientId = android.media.AudioManager@becd5abee.<my class>$$ExternalSyntheticLambda0@a334408
dispatching onAudioFocusChange(1) to android.media.AudioManager@becd5aborg.readium.navigator.media.tts.session.AudioFocusManager$AudioFocusListener@b212187
You can see that after my class requests the audio focus, Readium gets it soon after, I don't know why. Once that happens my app never gets the focus back.
It's curious that callingPack
for both is my app's package, so I don't understand why my app loses the focus.
I don't know if I'm missing something, or if this is a bug, but please let me know what's the right way to manage audio focus so that I have full control over it while I'm using TTS.
How to reproduce?
- Open any book
- Initiate the TTS and start playing it
- Perform any interruption with sound (notification, message, incoming call)
- The TTS will not stop when the interruption happens, and it is not possible to set an audio focus listener for that either
Readium version
3.0.0
Android API version
12 (API 32), 13 (API 33), 14 (API 34)