I have been reading the Android documentation on "Audio Focus", and the best-practices they lay out, but one thing alludes me...
Games need music pretty much the whole time, so it makes sense to request Audio Focus OnStart, but this can lead to a bad user experience.
If my App requests Audio Focus, and something is currently playing music already (eg. Samsung Music Player), my request will forcefully stop their music. The only special case I know of is if you request Audio Focus while the user is in a Phone Conversation.
I think what the user expects to happen, is if they are not already listening to music (or podcast, or whatever), then the game music should play. However, if they are already listening to their own music, then the game should not play music (but still play sound effects).
This is how things work on Xbox, Windows Phone, PS3, etc.
Is this just how it is on Android? Has anyone come up with a nice work around?
Note: I am familiar with AudioManager.IOnAudioFocusChangeListener. I am speaking specifically about the initial request for Audio Focus.
The other special case to avoid stopping something from playing when requesting audio focus is to allow it to duck, but that applies to transient loss which isn't what you would be doing. There's no way to know if another app is playing audio unfortunately so you will either take the audio and kill the music or you can not request the audio and hope for the best.
It might be worth prompting the user on launch if they are listening to their own music and if so then your game music will remain silent.
Related
On the newest FireTV OS for the Fire Stick Lite 2020 I noticed that when we play a third party app like Spotify for example music keeps playing when we press the home button. This is normal behavior, however when I launch my app I request the audio focus using the AudioManager and OnAudioFocusChangeListener (because I'm also playing music and don't want it to be noisy) so the 3rd party music stops playing. However, when I press play on the FireTV to control my media(Using ExoPlayer) it pauses my app, takes me back to the Spotify app and I lose focus of my own application.
Youtube and Twitch handle this well, so I was wondering if there is anything I am missing or any documentation I should refer to.
Any help is appreciated.
Found the answer. Seems like I wasn't Media Session... According to
https://developer.android.com/guide/topics/media-apps/working-with-a-media-session
We would need to use Media Session to tell the System that there is a media session happening in your app and each time you tell the system that your player is active or playing then your application would have priority over the media controllers on the remote and no other application can access it unless you state that your media session is no longer active.
This helped too! https://developer.android.com/codelabs/supporting-mediasession
Hope this helps anyone else!
I basically have an audio application that will be playing some music. I want to be able to pause/stop/mute the music when there is an interrupt.
These interrupts include: GPS directions, Phone Call, GPS, etc. (if there are more audio interupts, please let me know)
I already implemented the phone call interrupt, stops the music when phone call received and plays after phone call ends.
How would I do the other interrupts?
EDIT:
I noticed that Android's Play Music application does this. But I am unable to find the source code of that, not sure if that would be helpful.
Make sure you correctly ask for and release Audio Focus as described here:
http://developer.android.com/training/managing-audio/audio-focus.html
With multiple apps potentially playing audio it's important to think about how they should interact. To avoid every music app playing at the same time, Android uses audio focus to moderate audio playback—only apps that hold the audio focus should play audio.
Basically this allows the framework to handle interrupts properly as you cannot specifically code for every situation.
I'm writing an Android music player, and is stuck on audio focus issue.
It seems like audio focus mainly affects media button receiving, but after reading the document I have no idea about when to gain and give up focus.
My music app will run in background, and need to detect play/pause button every time. That is, even when my app is not running, a user should be able to press headset's play button and start music.
It seems I should never give up audio focus, so why should I implement it?
Does anyone know practically how audio focus should be used? Thank you!
It seems like audio focus mainly affects media button receiving, but
after reading the document I have no idea about when to gain and give
up focus.
They both are separate functionalities, and thus have separate listeners. You may have audio focus taken away from you but you may still choose to respond to play pause hardware keys
That is, even when my app is not running, a user should be able to
press headset's play button and start music.
I am assuming that you meant by the above line is that you are still playing music but not showing an activity. To keep listening to hardware button press, dont unregister your media button receiver(dont call audioManager.unregisterMediaButtonEventReceiver(receiver) yet).
It seems I should never give up audio focus, so why should I implement
it?
you dont give up the focus , it gets taken from you. To handle that gracefully you have AudioFocus listener. For ex, consider an incoming phone call. Would you still like to continue playing your music?
I am just messing around with an app that streams audio and I wanted to give it a feature similar to Pandora/Google Music/etc where if you press home or lock the screen the audio continues to play in the background.
How exactly can I accomplish this? Is it through a broadcast receiver or a service? If I knew more closely what I was looking for Google would be more helpful.
Thanks!
It's a service. Anytime you want to do something that takes a lot of time like playing music, downloading a lot of data from a server, etc. it should be a service. The basic technique is to always have the service play the music and then have your activity connect to it to show the status and update the tracks, etc.
I am trying to figure out what is the correct (new) approach for handling the Intent.ACTION_MEDIA_BUTTON in Froyo. In pre 2.2 days we had to register a BroadcastReceiver (either permanently or at run-time) and the Media Button events would arrive, as long as no other application intercepts them and aborts the broadcast.
Froyo seems to still somewhat support that model (at least for the wired headset), but it also introduces the registerMediaButtonEventReceiver, and unregisterMediaButtonEventReceiver methods that seem to control the "transport focus" between applications.
During my experiments, using registerMediaButtonEventReceiver does cause both the bluetooth and the wired headset button presses to be routed to the application's broadcast receiver (the app gets the "transport focus"), but it looks like any change in the audio routing (for example unplugging the headset) shits the focus back to the default media player.
What is the logic behind the implementation in Android 2.2? What is correct way to handle transport controls? Do we have to detect the change in the audio routing and try to re-gain the focus?
This is an issue that any 3rd party media player on the Android platform has to deal with, so I hope that somebody (probably a Google Engineer) can provide some guidelines that we can all follow. Having a standard approach may make headset button controls a bit more predictable for the end users.
Stefan
Google has a detailed blog post on implementing the newer 2.2 AudioManager media button event receiver while maintaining backwards compatibility with older devices.
http://android-developers.blogspot.com/2010/06/allowing-applications-to-play-nicer.html
After some experiments, I was able to get a working solution with the new transport and audio focus infrastructure in Android 2.2.
What I end up doing is requesting both the Audio Focus (using AudioManager.requestAudioFocus) and the Trasport Focus (using AudioManagter.registerMediaButtonEventReceiver) every time my application starts playback.
requestAudioFocus takes a callback that is called when the audio focus is taken away from you (for example the internal player starts a playback). In my case I just pause the playback in my application if the focus is taken permanently. Same callback also now tells you that the focus is taken only temporary (for example the Nav system is talking) so you can "duck" your playback - lower the volume or pause and resume after it is done talking.
The only issue remaining is that the built in Music Player takes the transport focus every time you connect a Bluetooth headset. This has the effect where the first press of the Play button on the headset after connecting it, always starts the playback in the default Music Player.
There is probably a way to detect the headset connection and "hijack" the transport focus. In my case, I decided to not "fight" the default player, and get the transport focus back when the user manually starts the playback in my application.
If somebody has more insight or knows of a better way of handling the transport/audio focus, please share it.
I also have this same issue with the media button registration.
Periodically the Android returns the media button registration to the default music player. I have not been able to figure out why. This can happen while may application is actively playing as well as while my application playback is paused.
After a number of users complained that their Bluetooth pause and play control buttons would periodically stop working to control my application, I implemented code that re-registers my application by calling registerMediaButtonEventReceiver every 2 seconds. This allows me to get the button registration back and for the most part avoids the time window where where the user presses a Bluetooth media button and the default media player ends up responding.
My application is holding the audio focus during this entire time period, but still loses the Bluetooth button events periodically while it has audio focus. My application always unregisters the media button event receiver if it is called with a notification that it is losing the audio focus, and then registers again if it is later called when a temporary audio focus loss returns the audio focus.
The work around to keep the 2 second timer running and re-registering has been working, but I would like to get rid of this 2 second timer if someone has found a work around for the media button registration periodically switching back to the default media player.