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
}
}
};
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.
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
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
I am writing an app with TTS, I am able to use UtteranceProgressListener (don't worry about older version on this topic) to gain Audio focus from Music players, and give focus back to Music players after the speech is done. But the app TTS still overlaps with Google Maps (navigator) voices.
Is there anyway I can tell when Map is speaking, and my voice can be queued, or even flushed (because right now, I cannot discern/understand either of them when both of them are talking).
Or someone can point me to the source of Google Map (or hidden APIs that I can use), I understand that Google map is not part of the Android open source.
Below is snippet of my code:
#TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
private class utteranceListener extends UtteranceProgressListener {
private OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {
public void onAudioFocusChange(int focusChange) {
if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
// Pause playback
audioManager.abandonAudioFocus(afChangeListener);
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK){
// we don't duck, just abandon focus
audioManager.abandonAudioFocus(afChangeListener);
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
// Resume playback
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
audioManager.abandonAudioFocus(afChangeListener);
}
}
};
#Override
public void onDone(String utteranceId)
{
audioManager.abandonAudioFocus(afChangeListener);
}
#Override
public synchronized void onError(String utteranceId)
{
audioManager.abandonAudioFocus(afChangeListener);
}
#Override
public void onStart(String utteranceId)
{
int result = audioManager.requestAudioFocus(afChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
}
}
By the way, on music and TTS, I like old-fashion AUDIOFOCUS_LOSS_TRANSIENT better than AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK, a 'ducked' music still makes (TTS) speech hard to listen, especially when playing Rap music, which sometimes is just 'a speech/talk'.
I've got it mostly resolved, with one exception, when Google Map is talking, my code (below) still returns AUDIOFOCUS_REQUEST_GRANTED, so I still have overlapping here.
audioManager.requestAudioFocus(afChangeListener, AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
On the things that work, two different concepts, UtterancePrograssListener is for events triggered by your own app, like whenever your speech is done or your speech is about to start; and OnAudioFocusChangeListener is for events triggered by other apps, like google maps grabbed audio focus from you.
So in case that I want to have my own app stop talking when Google Map is about to announce driving directions, below code would stop my talking:
public void onAudioFocusChange(int focusChange) {
if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
// Someone else has taken over the audio focus,
// abandonAudioFocus() would not do anything.
// you can only stop(), or lower your voice.
tts.stop();
audioManager.abandonAudioFocus(afChangeListener);
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK){
// this is what Google Map actually triggers
tts.stop();
audioManager.abandonAudioFocus(afChangeListener);
}
.....