I am playing an audio using MediaPlayer class. I have a requirement where audio played by my app should automatically stop when some other songs started playing on the device by the user. How to get notified that some other audio has started playing on the device in my app? Please advise.
UPDATED:
I tried this code, it works for the first time. I.e, when I launch my app and play an audio in my app, my app is playing an audio. Then, When I open some music player and play some other audio there, My app detects notification in "AUDIOFOCUS_LOSS". I am stopping my audio here. Then when again play audio in my app, and then coming back to music player and play some other audio there, this time my app doesn't get detected for this notification, so I couldn't do stop again my audio. This is my issue now.
Could someone help me to solve this please?
public class MyActivity extends ActionBarActivity implements OnCompletionListener, OnPreparedListener, OnErrorListener, OnBufferingUpdateListener, AudioManager.OnAudioFocusChangeListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_hclsquad_fm);
audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
}
#Override
public void onAudioFocusChange(int focusChange) {
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN:
Toast.makeText(MyActivity.this, "Focus GAINED", Toast.LENGTH_LONG).show();
break;
case AudioManager.AUDIOFOCUS_LOSS:
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
Toast.makeText(MyActivity.this, "Focus LOSS", Toast.LENGTH_LONG).show();
if(mediaPlayer != null)
killMediaPlayer();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
Toast.makeText(MyActivity.this, "Focus LOSS TRANSIENT", Toast.LENGTH_LONG).show();
break;
default:
}
}
Try this code below. I found this answer here
OnAudioFocusChangeListener listener = new OnAudioFocusChangeListener() {
public void onAudioFocusChange(int focusChange) {
if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK){
// Lower the volume
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
// Raise it back to normal
}
}
};
AudioManager am = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
int request = am.requestAudioFocus(listener,
AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN);
Responsible apps will always get audio focus before playing audio. I don't think it is possible for you to detect when another app plays audio if it does not request audio focus.
Instead of requesting audio focus in your onCreate, do it before you start to play audio:
private void play(){
requestAudioFocus();
}
You are loosing audio focus. You should call
requestAudioFocus();
to get control back.
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;
}
}
};
How do applications like Soundcloud stop another app's MediaPlayer? For example, when I am playing a song through Google Music and I open SoundCloud, the song from Google Music stops playing as soon as the Soundcloud song starts. I might be missing something obvious but I have always wondered how this is achieved.
Thanks,
Justin
Use Audio Focus. See Request the Audio Focus
AudioManager am = mContext.getSystemService(Context.AUDIO_SERVICE);
...
// 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) {
am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
// Start playback.
}
Adding on to #TCA's answer:
There is only one AudioManager. So, Audio focus is assigned to each application that requests it one by one. This means that if another application requests audio focus, your application will lose it. You will be notified of the loss of audio focus through the onAudioFocusChange handler of the Audio Focus Change Listener (afChangeListener in TCA's answer) you registered when requesting the audio focus.
private OnAudioFocusChangeListener focusChangeListener =
new OnAudioFocusChangeListener() {
public void onAudioFocusChange(int focusChange) {
AudioManager am =(AudioManager)getSystemService(Context.AUDIO_SERVICE);
switch (focusChange) {
case (AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) :
//Transient audio loss
break;
case (AudioManager.AUDIOFOCUS_LOSS) :
//Audio focus loss. Stop playback.
break;
case (AudioManager.AUDIOFOCUS_GAIN) :
//Audio focus gain. Start playback.
break;
default: break;
}
}
};
Im using this code to get AudioFocus and it works ok with
Android Music app ( the one preinstalled )
int result = audioManager.requestAudioFocus(meService, AudioManager.STREAM_MUSIC,AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
However when i release it with this code
audioManager.abandonAudioFocus(meService);
The Android Music app ( the one preinstalled ) does not continue playing.
if i use the AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK it works
but Android Music app is not lowering the volume enough.
Any ides why Android Music app is not resuming playback?
im using api8 and using the onAudioFocusChange
You should release it in MediaPlay.onCompleteListener(){}
After trying 4 players non of them are ducking. I might be doing something wrong and would like to see that. I answer my own question that we have to live with this.
This way works fine for me.
public class HomeActivity extends Activity implements AudioManager.OnAudioFocusChangeListener {
// Other stuff
#Override
public void onAudioFocusChange(int focusChange) {
if (focusChange == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
Log.i("HomeActivity", "Audio focus granted.");
}else if (focusChange == AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
Log.i("HomeActivity", "Audio focus failed.");
}
}
}
Request AudioFocus:
private void requestAudioFocus(){
AudioManager am = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
// Request audio focus for playback
am.requestAudioFocus(this,
// Use the music stream.
AudioManager.STREAM_MUSIC,
// Request permanent focus.
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
}
Abandon AudioFocus:
private void abandonAudioFocus(){
AudioManager am = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
am.abandonAudioFocus(this);
}
Hope this would help you.
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.