i wrote a podcast audio player and included the audio focus principle.
This is my method, which is called in the onPrepared() method of the media player:
private boolean requestAudioFocus(){
AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {
public void onAudioFocusChange(int focusChange) {
if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT){
pause();
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
play();
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
Log.d("MYAUDIOSERVICE","Audio Focus lost");
finish();
}
}
};
// Request audio focus for playback
int result = am.requestAudioFocus(afChangeListener,
// Use the music stream.
AudioManager.STREAM_MUSIC,
// Request permanent focus.
AudioManager.AUDIOFOCUS_GAIN);
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
return true;
}
else{
return false;
}
}
The problem is:
Everything works finde when starting the app and playing the first podcast. Audiofocus is gained and the podcast keeps playing.
When i stop playback and start another podcast the audiofocus is gained again, but shortly after AudioManager.AUDIOFOCUS_LOSS is receiver by the onAudioFocusChangeListener.
I guess thats the case because my app has the focus, request it again, gains it but at the same time loses the "old" one.
Am i right, and if if thats correct, can i just give up the audio focus when ending playback on the old podcast ?
Thx in advance
Related
I want to stop media player when some other media player applications start.
I don't know how to do this.
You'll need to add listener for AudioFocusChange.
Refer: https://developer.android.com/reference/android/media/AudioManager.OnAudioFocusChangeListener.html
I've done the similar thing in a project where when my app starts playing, Google Play Music pause and vice versa.
AudioManager am = null;
// Request focus for music stream and pass AudioManager.OnAudioFocusChangeListener
// implementation reference
int result = am.requestAudioFocus(this, AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN);
if(result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED)
{
// Play
}
// Implements AudioManager.OnAudioFocusChangeListener
#Override
public void onAudioFocusChange(int focusChange)
{
if(focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT)
{
// Pause
}
else if(focusChange == AudioManager.AUDIOFOCUS_GAIN)
{
// Resume
}
else if(focusChange == AudioManager.AUDIOFOCUS_LOSS)
{
// Stop or pause depending on your need
}
}
I have seen many Android Player online that as soon it start playing other app loses the focus and stop playing.
At other hand, as soon the gained focused app stop playing, focus Loosed app start playing again.
can any one suggest what am i missing here to achieve the same in my app? I want as soon other app stop playing my app should GAIN focus and start playing..
private void setupAudioManager() {
audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
audioManager.requestAudioFocus(audioFocusListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
audioFocusListener = new OnAudioFocusChangeListener() {
#Override
public void onAudioFocusChange(int focusChange) {
switch (focusChange) {
case AUDIOFOCUS_GAIN:
if (mediaPlayer == null) setupMediaPlayer();
else if (!mediaPlayer.isPlaying()) {
play();
}
mediaPlayer.setVolume(MEDIA_PLAYER_LEFT_VOLUME, MEDIA_PLAYER_RIGHT_VOLUME);
break;
case AUDIOFOCUS_LOSS:
if (isPlaying()) {
Intent intent = new Intent("HomeActivity");
intent.putExtra("playerState", "pause");
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
}
break;
case AUDIOFOCUS_LOSS_TRANSIENT:
if (isPlaying()) pause();
break;
case AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
if (isPlaying()) mediaPlayer.setVolume(MEDIA_PLAYER_LEFT_VOLUME_LOW,
MEDIA_PLAYER_RIGHT_VOLUME_LOW);
break;
}
}
};
}
Looking for you suggestion.
Here are my findings
In case of Permanent loss of focus
If the audio focus loss is permanent (AUDIOFOCUS_LOSS), another application is playing audio. Your app should pause play immediately. At this point your app will never receive an AUDIOFOCUS_GAIN callback. To restart playback the user must take an explicit action, like pressing the play transport control in a notification or app UI.
After pausing your app should wait a short interval and then stop its media session to release resources and abandon audio focus. Delaying the stop call gives the user the opportunity to restart your app's playback. This can be useful if your app goes silent because the user accidentally started a different app that requested the audio focus.
The following code snippet demonstrates how to implement the
OnAudioFocusChangeListener and its onAudioFocusChange() callback.
Notice the use of a Handler to delay the stop callback on a permanent
loss of audio focus.
private Handler mHandler = new Handler();
AudioManager.OnAudioFocusChangeListener afChangeListener =
new AudioManager.OnAudioFocusChangeListener() {
public void onAudioFocusChange(int focusChange) {
if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
// Permanent loss of audio focus
// Pause playback immediately
mediaController.getTransportControls().pause();
// Wait 30 seconds before stopping playback
mHandler.postDelayed(mDelayedStopRunnable,
TimeUnit.SECONDS.toMillis(30));
}
else if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT) {
// Pause playback
} else if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
// Lower the volume, keep playing
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
// Your app has been granted audio focus again
// Raise volume to normal, restart playback if necessary
}
}
};
The handler uses a Runnable that looks like this:
private Runnable mDelayedStopRunnable = new Runnable() {
#Override
public void run() {
mediaController.getTransportControls().stop();
}
};
To ensure the delayed stop does not kick in if the user restarts
playback, call mHandler.removeCallbacks(mDelayedStopRunnable) in
response to any state changes. For example, call removeCallbacks() in
your Callback's onPlay(), onSkipToNext(), etc. You should also call
this method in your service's onDestroy() callback when cleaning up
the resources used by your service.
I am a bit confused because of this question AUDIOFOCUS_GAIN doesn't called after AUDIOFOCUS_LOSS_TRANSIENT after a phone call
I don't believe in "Busy Waiting" solution. I think that AudioManager changes the state to AUDIOFOCUS_GAIN
And this question supports my viewpoint AUDIOFOCUS_LOSS called after a phone call in android
but when I tried, it never occurs to have the case of AUDIOFOCUS_GAIN
AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
the request sent by
am.requestAudioFocus(af, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
and
OnAudioFocusChangeListener af = this;
and
public void onAudioFocusChange(int i) {
Log.d("AudioChanged", i + "");
if (i == AudioManager.AUDIOFOCUS_LOSS) {
am.abandonAudioFocus(this);
sendBroadcast(new Intent(Constants.ACTION.PLAY_ACTION));
} else if (i == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
am.abandonAudioFocus(this);
sendBroadcast(new Intent(Constants.ACTION.PLAY_ACTION));
Log.d("loss transient", "AUDIOFOCUS_LOSS_TRANSIENT");
} else if (i == AudioManager.AUDIOFOCUS_GAIN) {
Log.d("gain ", "AUDIOFOCUS_GAIN");
startPlaying();
}
}
You shouldn't abandonAudioFocus() when AudioManager.AUDIOFOCUS_LOSS_TRANSIENT or when AudioManager.AUDIOFOCUS_LOSS, it happens automatically (the audio focus is passed to the new application that request audio focus, you just get the callback and you shoudn't abandon the request for audio focus becuase in case of a phone call you want to play again your music, what you should do is in case of AudioManager.AUDIOFOCUS_LOSS, stop your MediaPlayer and that's all and in case of AudioManager.AUDIOFOCUS_LOSS_TRANSIENT pause your MediaPlayer and when the phone call ends you automatically will get a call to AudioManager.AUDIOFOCUS_GAIN and then you should play again your MediaPlayer.
I'm building a media player and implementing onAudioFocusChange() in a way similar to the docs:
OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {
public void onAudioFocusChange(int focusChange) {
if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT
// Pause playback
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
// Resume playback
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
am.abandonAudioFocus(afChangeListener);
// Stop playback
}
}
};
The only weird issue: when leaving my phone sitting with the app in the background and the mediaplayer paused, the service will randomly start playing. When I remove the above code, it doesn't happen. So, onAudioFocusChange() is being called with AUDIO_FOCUS_GAIN as the argument seemingly randomly. Has anyone else dealt with this issue?
onAudioFocusChange() will be called everytime an app request or release the audio focus. This can come from any app, not just yours.
In fact, every notification that plays a sound (eq. Text/mail/...) will gain the focus and then release it. Once another app release the audio focus, your app will gain the focus again thus your resume playback will be called.
To avoid playing when you dont want to, you can keep a boolean that indicates if your app should play:
boolean wantsMusic = true;
OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {
public void onAudioFocusChange(int focusChange) {
if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT
// Pause playback
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN && wantsMusic) {
// Resume playback
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
am.abandonAudioFocus(afChangeListener);
// Stop playback
}
}
};
How to pause the audio player when I launch the radio app that I develop?
And "vice-versa" , How to pause my app when the user launch the audioplayer when my app is running in background.
You App needs to request the Audio-Focus, more about that here. Once you no longer need it you can abandon the focus, which returns it to the Application which had it previously to yours.
Use OnAudioFocusChangeListener to detect if there are other apps requesting audio focus; if so, pause your audio player.
am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
afChangeListener = new OnAudioFocusChangeListener() {
public void onAudioFocusChange(int focusChange) {
if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT){
// Pause playback
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
// Resume playback
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
abandonAudioFocus();
}
}
};
Similar SO question is here