grapefrukt
grapefrukt

Reputation: 27045

How can I detect if another app is playing music?

I'm making a game and I would like to detect if something else is already playing music (or starts to play music) as my game is running. If that's the case, I'll fade out the music in the game and keep playing the sound effects. I am using Unity and FMOD for audio playback.

As best I can tell Android provides two different ways to do this: AudioManager.isMusicActive and AudioManager.OnAudioFocusChangeListener.

AudioManager.isMusicActive does not work for my particular case since it seems the way Unity/FMOD registers itself will make this always return true.

AudioManager.OnAudioFocusChangeListener lets me detect if another App requests the audio focus, but provides no way of detecting if I can safely request it again.

I have no insight into how Unity/FMOD sets up the audio session, but the default is to play sounds regardless of anything else playing in the background. So, if I only knew if something else was playing this would be easy!

Is there a way to tell if something besides my own app is playing music?

Note: When I say music, it may also be an audiobook, podcast or closest equivalent.

There seems to be a possibility to look for any ongoing media playback notifications, but this requires escalated permissions which seems like too big of an ask for a feature this small.

Here's a few canditates for solutions:

Upvotes: 27

Views: 2718

Answers (1)

Atmas
Atmas

Reputation: 2393

To answer just your bold question first, you can try using requestAudioFocus with the AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE flag. Exclusive would imply nothing else CAN be playing and therefore should return AUDIOFOCUS_REQUEST_FAILED or AUDIOFOCUS_REQUEST_GRANTED which should give you a proxy answer to your question of "is something besides my own app playing music".

You are correct that the listeners are not intended to tell you if you can safely request access, but they can tell you when you can safely start playing.. Just make the request whenever your app is initially loaded or foregrounded (assuming it's not already playing music). If you're GRANTED, play, and don't play if not. Don't worry if you don't get immediate access, because you can have a listener that waits for when access is granted to you later (i.e. a few seconds later at the end of a map voicing out directions, or minutes later when the other long term audio source stops)..

Here's a longer take on the lifecycle as I understand it.

Once your app is launched (or whenever it is foregrounded), ask for AUDIOFOCUS_GAIN. If nothing is playing, you will be GRANTED audio focus and can start playing. If something is playing, you may not get immediate audio focus and should not start playing. If you did NOT start playing, make sure to listen for "AUDIOFOCUS_GAIN" in your FocusChangeListener. Receiving this message means you can start playing!

Don't worry about "locking out" others. As long as you made a reasonable request in asking for AUDIOFOCUS_GAIN (it's reasonable since you plan to use the audio for your game and you plan to use it for longer than 15 seconds) then taking over audio from another app makes sense because your App is being foregrounded and SHOULD take over primary audio. However, in your OnAudioFocusChangeListener you should be a good citizen and listen for LOSS events that may happen if the user switches back to the OTHER app or if other things transiently pop in, where you need to pause/mute or lower-volume/duck yourself accordingly.

In this way you're coding to whether your app is front and center or whether it's being told to be quiet and quiet for how long. That frees you from having to worry about who/what/why/how many other apps are out and about doing something with the audio and instead concentrate on simply coordinating and responding to the Audio Manager's directives until you don't care anymore (i.e. app exit, etc.).

I found these two links immensely useful in understanding the basics and how apps should be respectful of each other.

The last link is for Expo AV Manager. This is not to offer Expo as a solution, it's just I felt the Expo AV code worked well as a fully thought out example of the combinations of conditions one might encounter when navigating Audio management and what code/member variables might be useful to keep track of all of them. There's also a lot of "Expo-ey" framework things going on in that file which can be distracting and ignored, but if you just look at acquireAudioFocus and onAudioFocusChange I think there's some good inspiration to be had there.

For some code and a great overview

For the philosophy and rationale behind the lifecycle and how to be a good Audio citizen

Source from Expo AV Manager

Also as a final note, don't forget to be a good citizen and abandon focus when you don't need it. i.e. Backgrounding/Foregrounding, if your user turns off Music in game, etc.

Upvotes: 15

Related Questions