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.
Related
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 try to make simple mediaplayer app just for personal/educational purpose (play specific mp3 file) but i have a problem with others apps. I use services to play sound in background. Everything working fine but when i turn another media app i still can play simultaneously different song. How to "tell" to the system that my app is using mediaplayer and no ones can use mediaplayer till my services end. I use AudioManager STREAM_MUSIC and start playing my song when i get AUDIOFOCUS_GAIN checked by AUDIOFOCUS_REQUEST_GRANTED.
to play my music and set the foreground notification i use
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN);
if (AudioManager.AUDIOFOCUS_REQUEST_GRANTED == result) {
this.startForeground();
player.start();
}
You have to use media players audio focus implementations, detail documentation here:
http://developer.android.com/guide/topics/media/mediaplayer.html#audiofocus
Audio focus is one of the thing which assign to any application who request for that, means if you request for that, any other application using it will stop automatically & you;ll start using audio , same case while you are using it if any other app request for it, your audio will be stopped. You will be notifyed of the loss of audio focus through the onAudioFocusChange handler of the Audio Focus Change Listener you registered when requesting the audio focus
AudioManager am = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
// Request audio focus for playback
int result = am.requestAudioFocus(focusChangeListener,
// Use the music stream.
AudioManager.STREAM_MUSIC,
// Request permanent focus.
AudioManager.AUDIOFOCUS_GAIN);
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
// other app had stopped playing song now , so u can do u stuff now .
}
private OnAudioFocusChangeListener focusChangeListener =
new OnAudioFocusChangeListener() {
public void onAudioFocusChange(int focusChange) {
AudioManager am =(AudioManager)getSystemService(Context.AUDIO_SERVICE);
switch (focusChange) {
case (AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) :
// Lower the volume while ducking.
mediaPlayer.setVolume(0.2f, 0.2f);
break;
case (AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) :
pause();
break;
case (AudioManager.AUDIOFOCUS_LOSS) :
stop();
ComponentName component =new ComponentName(AudioPlayerActivity.this,MediaControlReceiver.class);
am.unregisterMediaButtonEventReceiver(component);
break;
case (AudioManager.AUDIOFOCUS_GAIN) :
// Return the volume to normal and resume if paused.
mediaPlayer.setVolume(1f, 1f);
mediaPlayer.start();
break;
default: break;
}
}
};
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'm trying to setup my audio playing app to stop playback if there is an interruption. I followed directions in Android SDK Developer notes about setting up an AudioFocusHelper like so:
public class AudioFocusHelper implements AudioManager.OnAudioFocusChangeListener {
AudioManager mAudioManager;
Media_Service mService;
Context mContext;
public AudioFocusHelper(Context ctx, Media_Service svc) {
mAudioManager = (AudioManager) ctx.getSystemService(Context.AUDIO_SERVICE);
mService = svc;
}
public boolean requestFocus() {
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED ==
mAudioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN);
}
public boolean abandonFocus() {
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED ==
mAudioManager.abandonAudioFocus(this);
}
#Override
public void onAudioFocusChange(int focusChange) {
// let your service know about the focus change
mService.AudioFocus(focusChange);
}
}
and I have my audio player running in a service as they suggest. I have this method in my audio service to respond to Audio Focus changes to pause the playback but its not working -- I don't know how to test this in the vm debugger so I can't really see what is happening on an incoming call. It doesn't appear to get called since I told it to popup toasts:
public void AudioFocus(int focusChange) {
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN: // resume playback
if (mMediaPlayer == null)
initMediaPlayer();
else if (!mMediaPlayer.isPlaying())
mMediaPlayer.start();
//mMediaPlayer.setVolume(1.0f, 1.0f);
break;
case AudioManager.AUDIOFOCUS_LOSS: // Lost focus for an unbounded amount of time: stop playback and release media player
if (mMediaPlayer.isPlaying()) {
Toast.makeText(this,
"Playback interrupted by focus loss", Toast.LENGTH_SHORT).show();
mMediaPlayer.stop();
}
mMediaPlayer.release();
mMediaPlayer = null;
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: // Lost focus for a short time, but we have to stop
// playback. We don't release the media player because playback
// is likely to resume
if (mMediaPlayer.isPlaying()) {
Toast.makeText(this,
"Playback paused by focus loss (transient)", Toast.LENGTH_SHORT).show();
mMediaPlayer.pause();
}
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: // Lost focus for a short time, but it's ok to keep playing
// at an attenuated level
if (mMediaPlayer.isPlaying()) {
Toast.makeText(this,
"Playback paused by focus loss (duck)", Toast.LENGTH_SHORT).show();
mMediaPlayer.pause();
//mMediaPlayer.setVolume(0.1f, 0.1f);
}
break;
}
}
I can post more of the code if necessary, it seems like I'm posting a lot of code already and I don't want to post an excessive amount. It looks to me like my onAudioFocusChange just isn't getting called. I am running this on Android 2.2 (minSDK 8) since these feature is not supported before 2.2. Searched hi and low for tips and I find very little about this topic at all so I'm hoping somebody out there can give me some clues.
I had this same issue, remember you need to call the requestFocus() method when you start playback and abandonFocus() when you are done.
I think this may help with generating incoming calls through DDMS: Fake Incoming Call Android
Hopefully, you can debug your application with this.
The AudioManager class has a method abandonAudioFocus() and another method requestAudioFocus(). I wonder what is audio focus? And what happens if an AudioManager object gets the audio focus or lost the audio focus?
Thank you!
It has to do with priority when using the speakers, to prevent playing many things at once or being overridden. If you requestAudioFocus(), you're declaring that you want control. You can then listen with onAudioFocusChange(int focusChange) to see if anything else tries to play a sound. You may forcefully lose focus (like during a phone call) but then you can gain it later. You should abandonAudioFocus() when you're finished.
AudioManager am = (AudioManager)getContext().getSystemService(AUDIO_SERVICE);
AudioManager.OnAudioFocusChangeListener focusChangeListener =
focusChange -> {
};
int result = am.requestAudioFocus(focusChangeListener,
AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
mp = new android.media.MediaPlayer();
mp.setOnCompletionListener(mediaPlayer -> {
am.abandonAudioFocus(focusChangeListener);
});
mp.setDataSource("/data/data/" + getContext().getPackageName() + "/rasa.wav");
mp.prepare();
mp.start();
}