Handling MediaPlayer error when SDCard removed - android

I want to handle use case when user remove SD Card while Android MediaPlayer is playing song.
I was trying to do it in BroadcastReciever and listen to ACTION_MEDIA_REMOVED or other actions related with SD.
I always get errors.
In receiver I was calling player.reset(); to get to idle status. After calling that method my media player stuck in infinite loop with errors printing in logcat.
How can I manage that UC? Can I use OnErrorListener?
I'm using Thread to publish progress of song playback on UI, I'm killing it before resetting player.

Check out this description of how to handle errors when using MediaPlayer. You should use OnErrorListener. It will put MediaPlayer into error state (see this state diagram). To exit from this state you need to reset() the player.

Related

Stopping media players in android

I have an application in android which uses many mediaplayers from a service.
Seeking a way that pressing a button, stop the audio.
The problem is that I can not know the name of the media player is playing when I press the button.
Is there any way to stop all mediaplayers? or to detect the name of the mediaplayer is playing and stop it?
I appreciate any help
Thanks and regards
At most, you need two MediaPlayer objects. While one is playing, call prepare or prepareAsync on the other. After the 2nd finishes preparation (in OnPreparedListener if using async), call setNextMediaPlayer on the MediaPlayer object that is currently playing. If the current one has finished before preparation completed just go ahead and call start instead.
Be sure to call release in the OnCompletionListener for each player, and if there are more files to play simply call setDataSource and prepare (or prepareAsync) for the next media. You can continue this pattern indefinitely without using extraneous resources, and the playback should switch as seamlessly as Android is able to make it.

Why do we use prepare() in a media player?

I am unable to clear myself that why do we need to use prepare() method in Mediaplayer. Why start() independently doesn't work in music players...
The prepare method collects metadata about the file or stream to be played, which may be necessary for proper function of the player itself and related components (like UI). The fact that you can call prepare and prepareAsync separately from calling setDataSource or start is simply a means of allowing the developer control over when and how things happen to suit his/her particular circumstance. Particularly for streaming media, preparation may take a significant amount of time, and so doing things the same way all the time will not be ideal in every situation.
suppose if you want doing some work that can be possible when media player is collecting infoemation then what you do. if start() work for both what happened if media player is collecting information about media. this will be treated as playing and it crashes completely. these are the states and has there works.

Gapless Playback with android MediaPlayer

I'm trying to repeatedly play a audio continuously, without any gap. I've tried,
mediaplayer.setLooping(true);
But it gives a gap between repeat time. And tried this,
mediaplayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp)
{
mediaplayer.start();
}
});
It gives a gap also. I've tried with different audio format. But neither way worked for me. Is there any other way in android?
When a playback finishes, the player engine would check if all tracks are completed and once done, it will check for the looping flag. Based on the looping flag, a seek to 0 seconds. As part of the seek, the player engine will read the data from the specific position and start the playback.
The delay may be due to the seek implementation along with the delay introduced by the storage medium like sdcard apart from re-initializing all tracks and restarting them. Hence, there is definite delay by the time the player reverts back to the starting position.
The underlying looping implementation can be found in this function AwesomePlayer::onStreamDone as shown here: http://androidxref.com/4.2.2_r1/xref/frameworks/av/media/libstagefright/AwesomePlayer.cpp#834
EDIT 1:
To implement a true gapless playback, you could also consider the setNextMediaPlayer() feature.
Probably MediaPlayer is re-prefetching the data from server (or even from the device itself), this may take some seconds. Only if the buffering is done, it starts playing again.
If you want to bypass this, you can AFAIK only use a second MediaPlayer which starts buffering the media file shortly before the first one stops playing. Then you can start the second one on OnCompletionListener.

AsyncTasks and Audio

I am trying to play multiple audio files, one after the other and am currently using AsyncTasks to prepare and start the mediaPlayer but have failed to find a good way to move on the to next track at the end of the current one. Not every audio file will be played every time, and it's playing is decided by a boolean value.
Any help is much apprecieated.
I guess you have read android-sdk/docs/reference/android/media/MediaPlayer.html , it says:
When the playback reaches the end of stream, the playback completes.
If the looping mode was being set to truewith setLooping(boolean), the
MediaPlayer object shall remain in the Started state. If the looping
mode was set to false , the player engine calls a user supplied
callback method, OnCompletion.onCompletion(), if a
OnCompletionListener is registered beforehand via
setOnCompletionListener(OnCompletionListener). The invoke of the
callback signals that the object is now in the PlaybackCompleted
state. While in the PlaybackCompleted state, calling start() can
restart the playback from the beginning of the audio/video source.
So you may set a new source, prepareAsync then start in completion callback. In this way , you get continuous playback, but it is not seamless.
Doubtful using MediaPlayer for this will work like you want it to. Try this tutorial:
http://www.droidnova.com/creating-sound-effects-in-android-part-1,570.html
If that doesn't work you'll probably have to mix the sounds together yourself them stream that result directly to the hardware using AudioTrack. That's more low level, but it will give you the most control. It just depends on what you are doing if the AudioManager solution will work for you or not. It's definitely the simpler route. But, if you're trying to line up two samples so that when one finishes the next begins, like in a music app, you probably will have to mix and stream that audio yourself.
http://developer.android.com/reference/android/media/AudioTrack.html
Algorithm to mix sound

Safe to reset a MediaPlayer in preparing state?

I'm writing an audio player using MediaPlayer that allows the user to skip the actual tune. A skip request might occur at any time, including between a call to MediaPlayer.prepareAsync and the upcoming onPrepared callback. The doc says:
It is important to note that the Preparing state is a transient state, and the behavior of calling any method with side effect while a MediaPlayer object is in the Preparing state is undefined.
Does that include calls to reset, or even to release? Because if it so, then I would either have to wait for the onPrepared callback to reuse the MediaPlayer or allocate a brand new MediaPlayer if I don't want to wait and release the obsolete one on the onPrepared callback, right?
I also built a stream music player and struggled with the preparing state. The worse part of it was that there were some streams where prepare() hung forever downloading (buffering) data without ever calling onBufferUpdate. Calling release did nothing. So, the way I did it was calling reset() on the stuck MediaPlayer from anotherthread after 15 seconds despite the recommendations in the docs. This caused it to throw an exception and brought it to error state. After catching the exception I called release(). This seems to have solved the problem. I hope this will be useful to someone.
In my opinion i will follow the advice in the docs, i found several issues with player in different devices (in some devices is not stable at all reusing the same player).
I think a good option is to have to players allocated, and switch between them when user skips a tune, then you wait for the original player to arrive to prepared state and then you reset it safely.
I'm facing an issue when MP "hangs" at preparing state too long (stream) and i'm trying to stop it using reset(). This causes MP to hang and thus my whole app freezes. Seems like there is no way to stop MP at preparing state. Im thinking on use prepare() wrapped in thread instead of prepareAsync(). Then i'll be able to kill that thread. As for now i did it in following way:
try {
mp.setDataSource(new String());
} catch (Exception e) {
e.printStackTrace();
android.util.Log.d(TAG,"actionCancel(): mp.setDataSource() exception");
mp.reset();
}
and it works 4me.

Categories

Resources