Android abandonAudioFocus doesn't trigger AudioManager.AUDIOFOCUS_LOSS - android

I abandon the audio focus in my onStop() method, but this doesn't lead to a loss of the focus in my OnAudioFocusChangeListener.
Abandoning doesn't even do any focus change.
What is my mistake?
How I get the focus:
private void startPlaying() {
int result = am.requestAudioFocus(afChangeListener,
AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
// Start playback.
mediaplayer.start();
if (am.isBluetoothA2dpOn()) {
// Adjust output for Bluetooth.
Log.i(AudioDemo.class.getName(), "Audio traget: BTHeadset");
} else if (am.isSpeakerphoneOn()) {
// Adjust output for Speakerphone.
Log.i(AudioDemo.class.getName(), "Audio traget: Speakerphone");
} else if (am.isWiredHeadsetOn()) {
// Adjust output for headsets
Log.i(AudioDemo.class.getName(), "Audio traget: WiredHeadset");
} else {
// If audio plays and noone can hear it, is it still playing?
Log.i(AudioDemo.class.getName(), "Audio traget: None");
}
isAudioPlaying = true;
tb = (ToggleButton) findViewById(R.id.toggle_audio);
tb.setChecked(true);
}
}
onStop():
#Override
protected void onStop() {
Log.i(AudioDemo.class.getName(), "onStop()");
// Abandon audio focus when playback complete, does nothing
int result = am.abandonAudioFocus(afChangeListener);
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
Log.i(AudioDemo.class.getName(), "Abandonning focus worked.");
} else {
Log.i(AudioDemo.class.getName(), "Abandonning focus failed.");
}
super.onStop();
}
My listener:
afChangeListener = new OnAudioFocusChangeListener() {
public void onAudioFocusChange(int focusChange) {
Log.i(AudioDemo.class.getName(), "focusChange: " + focusChange);
if ((focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT)
|| (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK)) {
if ((mediaplayer != null) && (mediaplayer.isPlaying())) {
// 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
mediaplayer.pause();
}
isAudioPlaying = false;
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
// Resume playback
if (mediaplayer == null) {
mediaplayer = MediaPlayer.create(AudioDemo.this, R.raw.song);
}
if (!mediaplayer.isPlaying()) {
mediaplayer.start();
}
isAudioPlaying = true;
// Lost focus for an unbounded amount of time: stop playback and
// release media player
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
// Stop listening for button presses
am.unregisterMediaButtonEventReceiver(audioDemoReceiver);
am.abandonAudioFocus(afChangeListener);
if (mediaplayer != null) {
if (mediaplayer.isPlaying()) {
// Stop playback
mediaplayer.stop();
}
isAudioPlaying = false;
mediaplayer.release();
mediaplayer = null;
}
}
tb.setChecked(isAudioPlaying);
}
};
Greetings

Related

How to pause video when other app play music and resume once the music stops?

When the video is playing and I resume the music from notification in the Music app, the video is still playing. Both music and video are playing concurrently. What I want is to pause the video when the music is started. Youtube app does what I am explaining here. When googled, I found that AudioFocus is used for MediaPlayer in such cases. Does VideoView support AudioFocus if yes then how to use that to achieve above goal?
You can call changeAudioFocus(true);
when you start playing media from your app. It will create an OnAudioFocusChangeListener and set it with AudioManager, and you will get a callback when you get AUDIOFOCUS_LOSS or AUDIOFOCUS_LOSS_TRANSIENT message.
You also get AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK, which is used to lower the volume of the player, which some media players do when you get a notification sound.
/**
* Used to indicate a transient loss of audio focus where the loser of the audio focus can
* lower its output volume if it wants to continue playing (also referred to as "ducking"), as
* the new focus owner doesn't require others to be silent.
* #see OnAudioFocusChangeListener#onAudioFocusChange(int)
*/
code
private final OnAudioFocusChangeListener mAudioFocusListener = createOnAudioFocusChangeListener();
private AudioManager mAudioManager = null;
private boolean mHasAudioFocus = false;
private void changeAudioFocus(boolean acquire) {
if (mAudioManager == null)
mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
if (mAudioManager == null)
return;
if (acquire) {
if (!mHasAudioFocus) {
final int result = mAudioManager.requestAudioFocus(mAudioFocusListener,
AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
mAudioManager.setParameters("bgm_state=true");
mHasAudioFocus = true;
}
}
} else if (mHasAudioFocus) {
mAudioManager.abandonAudioFocus(mAudioFocusListener);
mAudioManager.setParameters("bgm_state=false");
mHasAudioFocus = false;
}
}
private OnAudioFocusChangeListener createOnAudioFocusChangeListener() {
return new OnAudioFocusChangeListener() {
int audioDuckLevel = -1;
private int mLossTransientVolume = -1;
private boolean wasPlaying = false;
#Override
public void onAudioFocusChange(int focusChange) {
/*
* Pause playback during alerts and notifications
*/
switch (focusChange) {
case AudioManager.AUDIOFOCUS_LOSS:
if (BuildConfig.DEBUG) Log.i(TAG, "AUDIOFOCUS_LOSS");
// Pause playback
changeAudioFocus(false);
pause();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
if (BuildConfig.DEBUG) Log.i(TAG, "AUDIOFOCUS_LOSS_TRANSIENT");
// Pause playback
pausePlayback();
break;
case AudioManager.AUDIOFOCUS_GAIN:
if (BuildConfig.DEBUG) Log.i(TAG, "AUDIOFOCUS_GAIN: ");
// Resume playback
if (mLossTransientVolume != -1) {
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, mLossTransientVolume, 0);
mLossTransientVolume = -1;
}
if (mLossTransient) {
if (wasPlaying && mSettings.getBoolean("resume_playback", true))
play();
mLossTransient = false;
}
break;
}
}
private void pausePlayback() {
if (mLossTransient) return;
mLossTransient = true;
wasPlaying = isPlaying();
if (wasPlaying) pause();
}
};
}

Android MediaPlayer Streaming YouTube audio stream unexpected LOUD static

What I'm attempting:
I'm using youtube-dl in a Python Daemon on a remote server to get a URL.
That URL is fed into an Android App into a MediaPlayer instance.
What is happening:
Occasionally and unexpectedly the Media player will BLAST static and play at normal speed, sometimes it will blast static and play at 1.5 times speed.
Here's a video of what happens. HEADPHONE WARNING
YouTube Video
Observations:
If there is static it is for the whole song (it isn't intermittent).
I've taken the URLs it provides and they play fine in a PC browser with no static.
It happens on different phones, and it is not just my particular phone.
It takes longer to start tracks that end up being staticy.
Tracks that are staticy make my progress bar (seconds minutes display) just behave strangely. I've seen it count up and down in the first couple seconds, and there is the 1.5x speed I was talking about.
MediaHTTPConnection throws alot of exceptions that I don't know how to handle.
E/MediaHTTPConnectionEx: disconnecting
E/MediaHTTPConnectionEx: RuntimeException: Unbalanced enter/exit
mConnection.disconnect();
Below is the portion of my Python daemon that returns the URL
ydl_opts = {
'skip_download':True, # We just want to extract the info
'format':'bestaudio',
'forceurl':True,
'ignoreerrors':True,
'youtube_include_dash_manifest':False,
'restrict_filenames':True,
'source_address':'10.1.0.38',#we have to set this to force ipv4
'logger': MyLogger()
}
def ytdl(self, url):
url2 = "https://www.youtube.com/watch?v="+url
ydl.download([url2])
Here's the (basically boilerplate) MediaPlayer
public static Stack<Track> tracks = new Stack<>();
private static MediaPlayer mediaPlayer;
private String mediaFile;
private static int duration = 0;
private AudioManager audioManager;
private Boolean userPause = false;
// Binder given to clients
private final IBinder iBinder = new LocalBinder();
public static final String TAG = "Player";
#Override
public IBinder onBind(Intent intent) {
return iBinder;
}
class LocalBinder extends Binder {
Player getService() {
return Player.this;
}
}
public static void seekTo(int msec){
if(mediaPlayer != null){
mediaPlayer.seekTo(msec);
}
}
//The system calls this method when an activity, requests the service be started
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
boolean success = true;
//An audio file is passed to the service through putExtra();
if(intent.hasExtra("uri")){
mediaFile = intent.getStringExtra("uri");
} else {
stopSelf();
success = false;
}
//Request audio focus
if (!requestAudioFocus()) {
//Could not gain focus
Log.d(TAG, "error requesting audio focus");
stopSelf();
success = false;
}
if (mediaFile != null && !mediaFile.equals("") && success) {
Log.d(TAG, "Media File:" + mediaFile);
success = initMediaPlayer();
}
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy() {
//we cant destroy the player here because the back button fires this
//maybe i can not fire super?
super.onDestroy();
/*if (mediaPlayer != null) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.release();
}
removeAudioFocus();*/
}
private boolean initMediaPlayer() {
boolean error = false;
//one time setup
if(mediaPlayer == null) {
mediaPlayer = new MediaPlayer();
//setup listeners
mediaPlayer.setOnCompletionListener(this);
mediaPlayer.setOnErrorListener(this);
mediaPlayer.setOnPreparedListener(this);
mediaPlayer.setOnBufferingUpdateListener(this);
mediaPlayer.setOnSeekCompleteListener(this);
mediaPlayer.setOnInfoListener(this);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
}
//Reset so that the MediaPlayer is not pointing to another data source
mediaPlayer.reset();
try {
Log.d(TAG, "setDataSource");
mediaPlayer.setDataSource(mediaFile);
} catch (IOException e) {
Log.e(TAG,"setDataSource error:"+e);
error = true;
}
try {
Log.d(TAG, "prepare");
mediaPlayer.prepare();
} catch (IOException e) {
Log.d(TAG, "prepare error");
e.printStackTrace();
error = true;
}
return error;
}
#Override
public void onPrepared(MediaPlayer mp) {
//Invoked when the media source is ready for playback.
Log.d(TAG, "onPrepared");
mp.start();
duration = mp.getDuration();
}
#Override
public void onCompletion(MediaPlayer mp) {
//Invoked when playback of a media source has completed.
removeAudioFocus();
mp.stop();
mp.reset();
}
#Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
//Invoked to communicate some info.
return false;
}
#Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
//Invoked indicating buffering status of
//a media resource being streamed over the network.
if(percent%25==0)
Log.d(TAG, "buffering:"+percent);
}
#Override
public void onSeekComplete(MediaPlayer mp) {
//Invoked indicating the completion of a seek operation.
Log.d(TAG, "onSeekComplete() current pos : " + mp.getCurrentPosition());
SystemClock.sleep(200);
start();
}
//Handle errors
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
//Invoked when there has been an error during an asynchronous operation
switch (what) {
case MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK:
Log.e(TAG, "MEDIA ERROR NOT VALID FOR PROGRESSIVE PLAYBACK " + extra);
break;
case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
Log.e(TAG, "MEDIA ERROR SERVER DIED " + extra);
break;
case MediaPlayer.MEDIA_ERROR_UNKNOWN:
Log.e(TAG, "MEDIA ERROR UNKNOWN " + extra);
//NowPlaying.error = true;
break;
default:
Log.e(TAG, what + "," + extra);
break;
}
PlayerActivity.error = true;
return false;
}
#Override
public void onAudioFocusChange(int focusState) {
//Invoked when the audio focus of the system is updated.
switch (focusState) {
case AudioManager.AUDIOFOCUS_GAIN:
// resume playback
mediaPlayer.setVolume(1.0f, 1.0f);
if(!mediaPlayer.isPlaying()
&& !userPause) {
pause(false);
}
break;
case AudioManager.AUDIOFOCUS_LOSS:
// Lost focus for an unbounded amount of time: stop playback and release media player
if (mediaPlayer.isPlaying()) mediaPlayer.pause();
removeAudioFocus();
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 (mediaPlayer.isPlaying()) mediaPlayer.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 (mediaPlayer.isPlaying()) mediaPlayer.setVolume(0.1f, 0.1f);
break;
}
}
private boolean requestAudioFocus() {
int result = 0;
if(audioManager == null) audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
if (audioManager != null) {
result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
}
Log.d(TAG, "requestAudioFocus:"+result);
return result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
//Could not gain focus
}
private void removeAudioFocus() {
audioManager.abandonAudioFocus(this);
}
boolean isPlaying() {
if(mediaPlayer != null)
return mediaPlayer.isPlaying();
return false;
}
//pause(true) == pause
//pause(false) == play
//this is used by the system
void pause(Boolean state){
//pause
if (state) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
} else {
if (!mediaPlayer.isPlaying()) {
start();
}
}
}
//this is a pause toggle that is only triggered by the pause/play button
boolean pause() {
if (mediaPlayer.isPlaying()){
userPause = true;
mediaPlayer.pause();
} else {
userPause = false;
start();
}
return !mediaPlayer.isPlaying();
}
void start(){
mediaPlayer.start();
}
int getCurrentPosition(){
if(mediaPlayer != null)
return mediaPlayer.getCurrentPosition();
return 0;
}
int getDuration(){
return duration;
}
}
I feel like someone else is going to have this problem so I'm going to post my solution.
So I noticed a mime type error popped up for every track. The error still shows up now that I've fixed this problem but the loud static has stopped.
Here is the error that started the wheels turning:
E/MediaHTTPConnectionEx: getMIMEType
[seekToEx] offset:0/mCurrentOffset:-1
I noticed some of the URLs youtube-dl was giving me for the webm didn't have a mime type specified in the URL.
Here is an example:
...O8c2&mime=&pl=...
But all of the m4a streams had a mime type in the URL
...70F61&mime=audio%2Fmp4&itag=140&key...
So I think that while my solution isn't the best solution, it's the easiest. Since ALL the m4a streams had a mime specified I just limited myself to those streams.
The rub is this:
I'm pretty sure that if I just checked the URL for a specified mime field I could still play most webm files. The only ones that were failing (staticy) were URLs that did not have that field.
My solution:
Python only pulls m4a files:
...
'format':'bestaudio[ext=m4a]',
...
Android now passes hard coded headers:
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "audio/mp4"); // change content type if necessary
Uri uri = Uri.parse(mediaFile);
Log.d(TAG, "getMimeType="+getMimeType(uri));//this is ALWAYS null
mediaPlayer.setDataSource(getApplicationContext(), uri, headers);

Unable to stop mediaplayer

I've two radio buttons in a radiogroup and on selection of one radio button it will start music and stop the other sound and on selection of other it will start the next song and stop the previous song. The problem is I'm unable to stop the music. The song keeps on playing in the background. I'm using dialog box to show radio buttons and getting the input from user on button'c click.
The length of each song is greater than 3 minutes.
I've searched the internet and tried multiples solution but no solution is working. Below is the code I've used:
btnDone.setOnClickListener(view.onClickListener)
{
#Override
public void onClick(View view)
{
boolean checked = radioButton1.isChecked();
boolean checked1 = radioButton2.isChecked();
MediaPlayer mediaPlayer = MediaPlayer.create(this,R.raw.song1);
MediaPlayer mediaPlayer2 = MediaPlayer.create(this,R.raw.song2);
if(checked && !checked1)
{
mediaPlayer.start();
}else if(checked1 && !checked)
{
try{
if(mediaPlayer !=null)
{
if(mediaPlayer.isPlaying())
{mediaPlayer.stop;
mediaPlayer.release;
mediaPlayer = null;
}
}
}
catch(Exception e)
{e.printStackTrace(); }
}
}
}
IMO your else if(checked1 && !checked1) condition not working properly so try else if(checked1 && !checked) try below code
btnDone.setOnClickListener(view.onClickListener)
{
#Override
public void onClick(View view)
{
boolean checked = radioButton1.isChecked();
boolean checked1 = radioButton2.isChecked();
MediaPlayer mediaPlayer = MediaPlayer.create(this,R.raw.song1);
MediaPlayer mediaPlayer2 = MediaPlayer.create(this,R.raw.song2);
if(checked && !checked1)
{
mediaPlayer.start();
}else if(checked1 && !checked) //change here
{
try{
if(mediaPlayer !=null)
{
if(mediaPlayer.isPlaying())
{mediaPlayer.stop(); // also change here
mediaPlayer.release(); //change here
mediaPlayer = null;
}
}
}
catch(Exception e)
{e.printStackTrace(); }
}
}
}

how to listen to the radio stream instantly without waiting in Android?

I always use this method to read the flow of streaming radio stations.
play.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(play.getTag().equals("Start")){
notificationBar("Click To Stop Radio",nom);
play.setEnabled(false);
startPlaying(image, nom, urlradio);
}else{
play.setTag("Start");
stopPlaying(urlradio);
play.setImageResource(R.drawable.play);
}
}
});
OnAudioFocusChangeListener focusChangeListener =
new OnAudioFocusChangeListener() {
public void onAudioFocusChange(int focusChange) {
switch (focusChange) {
case (AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) :
// Lower the volume while ducking.
player.setVolume(0.2f, 0.2f);
break;
case (AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) :
player.pause();
break;
case (AudioManager.AUDIOFOCUS_LOSS) :
// player.stop();
break;
case (AudioManager.AUDIOFOCUS_GAIN) :
// Return the volume to normal and resume if paused.
player.setVolume(1f, 1f);
player.start();
break;
default: break;
}
}
};
// Request audio focus for playback
int result = audioManager.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 void startPlaying(String image,String nom,String urlradio) {
initializeMediaPlayer(urlradio);
playSeekBar.setVisibility(View.VISIBLE);
player.prepareAsync();
player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
public void onPrepared(MediaPlayer mp) {
player.start();
playSeekBar.setVisibility(View.INVISIBLE);
play.setEnabled(true);
play.setImageResource(R.drawable.stop);
play.setTag("Stop");
}
});
}
private void stopPlaying(String urlradio) {
if (player != null) {
player.stop();
player.release();
player = null;
}
notificationClose(1);
playSeekBar.setVisibility(View.INVISIBLE);
}
private void initializeMediaPlayer(String radio) {
player = new MediaPlayer();
player.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
try {
player.setDataSource(radio);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
player.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
public void onBufferingUpdate(MediaPlayer mp, int percent) {
playSeekBar.setSecondaryProgress(percent);
Log.i("Buffering", "" + percent);
}
});
}
But in some radio the stream I expected 20 to 30 seconds to be listen and I saw in some application that the flow passes instantaneous .
how to listen to the radio stream instantly without waiting?

Recognize Stop AudioTrack

How to detect if an AudioTrack has finished playing? it's not simple!!!
I need to touch immediately after the other (enqueue) This code is not working ...
When press 2 times, the 1st not end, and two sound plays same time...
private void getNextAudio() {
try{
byte[] buffer = playlist.poll();
if (buffer != null) {
AudioTrack myatrack = getAudioTrack(buffer);
myatrack.setPlaybackPositionUpdateListener( new OnPlaybackPositionUpdateListener() {
public void onPeriodicNotification(AudioTrack track) {
}
public void onMarkerReached(AudioTrack track) {
Log.d(TAG, "onMarker - estado: " + track.getPlayState());
if(track.getPlayState() == AudioTrack.PLAYSTATE_STOPPED){
track.flush();
track.stop();
track.release();
getNextAudio();
}
}
});
if (myatrack != null) {
// toco o audio.
myatrack.play();
}
}else{
Log.d(TAG,"Finish");
}
}catch(NoSuchElementException ex){
Log.d(TAG,"No such element");
}
}
Thanks again!
Mateus

Categories

Resources