I'm currently trying to write a simple audio player that streams a URL until the user quits. Nothing fancy really, but I'm trying to use the onInfo method of MediaPlayer to wait for the metadata update flag. I have the following code for creating the media player object.
/**
* Creates a new media player and attempts to prepare it.
*/
private void createPlayer(){
Log.v(TAG, "Now in createPlayer()");
if(mPlayer==null){
Log.i(TAG, "No existing media player found, creating.");
mPlayer=new MediaPlayer();
mPlayer.setOnErrorListener(this);
mPlayer.setOnInfoListener(new OnInfoListener() {
public boolean onInfo(MediaPlayer mp, int what, int extra) {
Log.w(TAG,"---Got some info!---");
return false;
}
});
mPlayer.setOnPreparedListener(this);
mPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
} else {
Log.i(TAG, "Found an existing media player. Doing nothing.");
}
try{
mPlayer.setDataSource(mStreamUri);
mPlayer.prepareAsync();
Log.i(TAG, "Just sent the media player a prepareAsync()");
}catch(Exception e){
Log.e(TAG,"Caught exception while trying to set up media player.");
}
}
I have yet to see onError fire, but I also have yet to actually get any errors because of the simplicity of my app, but of course onPrepare works fine. I've tried implementing it with the class, as well as an inline method like the above code but nothing happens.
Change your code with this and try again -
mPlayer.prepare();
You cannot return false in onInfoListener. The android developer says if it returns false, the infoListener seems as if it was not set.
Related
I am trying to implement an online devotional psalm streaming Android app. I am trying to stream these audio files from my website server directly using the MediaPlayer class provided by Android SDK framework.
Here is the code for my MediaPlaybackUtility.java
public class MediaPlaybackUtility {
static boolean isMediaPlaying = false;
static MediaPlayer mMediaPlayer = new MediaPlayer();
static void playPauseBhajan(String fileURL) {
if(!mMediaPlayer.isPlaying()) {
try {
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setDataSource(ONLINE_AUDIO_URL);
mMediaPlayer.prepareAsync();
mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mMediaPlayer.start();
isMediaPlaying = true;
}
});
} catch (IOException e) {
// TODO: handle exception
}
} else {
mMediaPlayer.pause();
isMediaPlaying = false;
}
}
static void stopBhajan() {
mMediaPlayer.stop();
isMediaPlaying = false;
}
}
I entered the URL of the audio file saved on my server in the place of ONLINE_AUDIO_URL but there are some bizarre experiences I had while I was working with MediaPlayer class. The MediaPlayer class is playing some files while it is not playing others and I am not able to understand where the problem is.
Here are the links to the audio files that the above code is playing without any errors:
1. testsong_20sec.mp3
2. TheRadiance.m4a
3. WaitingfortheEnd.m4a
And here are the links that the MediaPlayer is not able to play:
1. ShapeofYou.mp3
2. AreyDwalPalon.mp3
3. KrishnaTheme.mp3
4. BataoKahaMilegaShyam.mp3
I then tried to set a OnErrorListener to the MediaPlayer so that if there is some error streaming these files I could log these errors out and therefore I added these lines just after the mMediaPlayer.prepareAsync(); but then again when I changed the URL to one of those that the MediaPlayer was not able to play no errors were logged in the Logcat.
mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
Log.e("MEDIAPLAYER", "Can't play media.");
return false;
}
});
Then I converted these MP3 files into M4A format just like this one
AreyDwarPalonm4a.m4a but again no luck and still this file was not played by MediaPlayer from the server.
I have also searched the web and everywhere but couldn't find anything related to my specific problem. Maybe I am ignoring some fundamental concept here as I am working first time with MediaPlayer and audio files but again the main confusing part is, it is playing some of those files saved on the server but not the others.
I think you should have to add this listener before mMediaPlayer.prepareAsync() like
mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
Log.e("MEDIAPLAYER", "Can't play media.");
return false;
}
});
mMediaPlayer.prepareAsync();
It shows error while playing large audio file (>1mb).
Find some workaround for playing large file.
Thanks!
I'm trying to implement the restart of MediaPlayer in Android, when errors happen (connection with server lost, network is unreachable and other).
I've seen many code examples, but all are somewhat non-standard. I think there must be the standard way to restart corresponding to the developer.android.com, but it's not clear from here, how to set the listener which would restart player on such errors.
Here are the parts of my code:
public class PlayerService extends Service implements OnErrorListener {
....
////////////////////
this.mplayer = MediaPlayer.create(c, Uri.parse(url));
mplayer.setOnErrorListener(onErrorListener);
////////////////////
MediaPlayer.OnErrorListener onErrorListener = new MediaPlayer.OnErrorListener()
{
#Override
public boolean onError(MediaPlayer mp, int what, int extra)
{
Log.e(getPackageName(), String.format("Error(%s%s)", what, extra));
playlist="ERROR";
restart();
return true;
}
};
#Override
public boolean onError(MediaPlayer player, int what, int extra) {
restart();
return true;
};
public void restart()
{
try
{
playlist="RELOADING";
for (int u=1; u<=5; u++)
{
Thread.sleep(5000);
mplayer.stop();
mplayer.release();
mplayer=null;
playSong(getApplicationContext(),currenturl);
};
}
catch (Exception e)
{
playlist="RELOADING ERROR";
}
}
//////////////
....
}
Am I setting the listener right? I'm not sure where to put onError function so I have 2 of them. When I emulate the error by setting the phone to the flight mode, the listener fires "RELOADING" and "RELOADING ERROR" title. But after the network is on, no restart of the player happens. There is no sound.
What's wrong here? The player cannot restart.
Please help to make the code workable. Also can be connection skips and IO Exception.
Overview
I ran into a similar issue and based on the documentation it indicates that all you need to do is reset your media player:
In order to reuse a MediaPlayer object that is in the Error state and recover from the error, reset() can be called to restore the object to its Idle state.
What you are currently doing is stopping and releasing (mplayer.stop() and mplayer.release()) a media player that is in the Error state. This should be causing something like an IllegalStateException to be raised. If it's not throwing an error you would still be trying to start a song in a null object. Instead of calling stop and release then setting the variable to null you should be using the mplayer.reset() function.
Another option would be to initiate a new media player but the documentation details the subtle difference between a newly instantiated MediaPlayer object and one that has had reset() called on it.
Reset after Error
Based on this information something like the following should fix your issue:
public boolean onError(MediaPlayer mp, int what, int extra)
{
Log.e(getPackageName(), String.format("Error(%s%s)", what, extra));
playlist="ERROR";
if(what == MediaPlayer.MEDIA_ERROR_SERVER_DIED)
mp.reset();
else if(what == MediaPlayer.MEDIA_ERROR_UNKNOWN)
mp.reset();
// Deal with any other errors you need to.
// I'm under the assumption you set the path to the song
// and handle onPrepare, start(), etc with this function
playSong(getApplicationContext(),currenturl);
mplayer.setOnErrorListener(this);
mplayer.setOnCompletionListener(this);
mplayer.setOnPreparedListener(this);
return true;
}
See media player constant documentation for a list of potential errors.
Setting Error Listener
As for setting the error listener, here is how I've implemented it in the past:
public class MediaPlayerActivity extends Activity implements OnCompletionListener,
OnPreparedListener, AnimationListener, OnErrorListener{
private MediaPlayer mediaPlayer;
#Override
public boolean onError(final MediaPlayer arg0, final int arg1, final int arg2) {
// Error handling logic here
return true;
}
protected void onResume(){
super.onResume();
// do some onResume logic
mediaPlayer.setOnErrorListener(this);
mediaPlayer.setOnCompletionListener(this);
mediaPlayer.setOnPreparedListener(this);
// finish on resume and start up media player
}
}
I then handle loading up the media player in another function initiated by onResume().
I am having some trouble using the android MediaPlayer in a non activity class, always a context error. Here is the bugged line:
MediaPlayer Shoot = MediaPlayer.create(this, R.raw.shot);
Now I know I cant use "this" in a service, but all the other stuff I tried kept giving bugs.
any suggestions?
You are too luck because in the last two days I have develop an app that uses MediaPlayer inside a background Service ;)
You can simply retrieve an instance of your MediaPlayer using the next line:
MediaPlayer mediaPlayer = new MediaPlayer();
Then you can set all listener and play song that you want.
Edit 22th april 2012
To set listeners (an example):
mediaPlayer.setOnErrorListener(new OnErrorListener() {
public boolean onError(MediaPlayer mp, int what, int extra) {
// TODO notify error to user or play next song
return true;
}
});
mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
// TODO Notify to user the completion of song or play next song
}
});
To start and play song you have to do something like this:
try{
mediaPlayer.setDataSource(mSongUrl);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.prepare();
} catch (Exception e) {
e.printStackTrace();
}
// Starting media player
mediaPlayer.start();
Why don't you just pass the context reference to the constructor of your non activity class.
and then from there save it and pass it to where it is needed.
Make sure your context reference no longer remain live after its use. Else it will gonna cause memory issue.
I have created a list of songs on click on the song i am able to play the song using MedaiPlayer. While one song is playing if the user clicks another song then i am stopping the media player and starting the player again. But I am getting illegalstateexception in reset(). Here is the code where I am getting the exception. How to stop a player properly? also why am i getting this exception. How to avoid it?
public void stopPlayer() {
try {
if (player != null) {
// Log.e("Trying to Stop "," Player ");
player.stop();
player.release();
player.reset();// causes IllegalstateException
player = null;
}
} catch (Exception e) {
player = null;
playerStatus = false;
e.printStackTrace();
}
}
try this :
player.reset();
player.release();
and also have a look at media player state diagram.
If you want to play again ,then use player.reset(),
player.release() means that it releases the player object so you have to re-intialise the player. So first you use reset() and then release(). release() is used when your player object no longer working. When your activity destroys release() method to be used for good practice.
Whenever you want to stop it:
if(player!=null)
{
if(player.isPlaying())
player.stop();
player.reset();//It requires again setDataSource for player object.
}
Whenever your player no longer to be needed:
if(player!=null)
{
if(player.isPlaying())
player.stop();
player.reset();//It requires again setDataSource for player object.
player.release();
player=null; // fixed typo.
}
Though the accepted answer works, This is a better way to achieve the task
private void stopSong() {
if(mediaPlayer!=null) {
if(mediaPlayer.isPlaying()) {
mediaPlayer.reset();// It requires again setDataSource for player object.
mediaPlayer.stop();// Stop it
mediaPlayer.release();// Release it
mediaPlayer = null; // Initialize it to null so it can be used later
}
}
}
Are you planning on reusing the player again, or are you done with the player? If you're done with the player, call release() and not reset(). If you plan on reusing the player, call reset() and not release().
reset() resets the player to its uninitialized state.
release() frees all resources associated with the player.
The Media Player State Diagram shows, and also states:
Calling stop() stops playback and causes a MediaPlayer in the Started, Paused, Prepared or PlaybackCompleted state to enter the Stopped state.
Once in the Stopped state, playback cannot be started until prepare() or prepareAsync() are called to set the MediaPlayer object to the Prepared state again.
That means, that after calling stop(), we should call prepare() on the same audio file if we wish to play it again. Otherwise calling start() again won't do anything.
As prepare() might throw exception, we should wrap it in a try-catch block, like this:
public void stopAudio(View view) {
mplayer.stop();
try {
mplayer.prepare();
} catch (IOException e) {
Log.e("stopAudio", "Unable to prepare() mplayer after stop()", e);
}
}
I have a list of songs that I'm streaming using the MediaPlayer. Some of the songs consistently work and others consistently do not work. I can't see a difference between these files, and they seem to play fine in itunes and such.
When the songs fail it is throwing an IllegalStateException on the mediaPlayer.prepare() line. The IllegalStateException that is thrown has no useful info in it, (detailMessage is null, stackState is null)
Here is my code
try {
mediaPlayer.setDataSource(media.url);
setPlayerState(PlayerState.PREPARING);
mediaPlayer.prepare();
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, "bad stream");
}
Here is a url to the file that does NOT work:
skdy.bryceb.dev.mediarain.com/song.m4a
Here is one that DOES work:
skdy.bryceb.dev.mediarain.com/song2.m4a
Any ideas why this works on some songs and fails on others?
Thanks MisterSquonk I'm sure that way would work.
In my particular case after beating my head against the wall for a while I realized that on some songs, I was getting to the buffered amount before the player state was getting set to prepared. So I added a check to make sure that the MediaPlayer was in the "PREPARED" state and then it worked great:
// Media prepared listener
mediaPlayer.setOnPreparedListener(
new MediaPlayer.OnPreparedListener() {
public void onPrepared(MediaPlayer mp) {
setPlayerState(PlayerState.PREPARED);
}
});
// Media buffer listener
mediaPlayer.setOnBufferingUpdateListener(
new MediaPlayer.OnBufferingUpdateListener() {
public void onBufferingUpdate(MediaPlayer mp, int percent) {
// Sometimes the song will finish playing before the 100% loaded in has been
// dispatched, which result in the song playing again, so check to see if the
// song has completed first
if(getPlayerState() == PlayerState.COMPLETED)
return;
if(getPlayerState() == PlayerState.PAUSED)
return;
// If the music isn't already playing, and the buffer has been reached
if(!mediaPlayer.isPlaying() && percent > PERCENT_BUFFER) {
if(getPlayerState() == PlayerState.PREPARED)
{
mediaPlayer.start();
setPlayerState(PlayerState.PLAYING);
}
//if it isn't prepared, then we'll wait till the next buffering
//update
return;
}
}
});
OK, I hacked together a minimal Mediaplayer implementation in a 'sandbox' app/activity I always keep spare for testing.
I might be wrong but if you're streaming these songs over the net, you'll need to prefix the url with http://.
I tried the urls with Winamp and Chrome verbatim (no protocol prefix string) and they worked fine although it's likely both of those applications will use some form of intelligence to work out how to connect/stream.
If I tried that in my mediaPlayer code, I get the same exception as you but if I prefix the urls with http:// the songs play fine.
Example...
// Activity scope
Button button;
CheckBox checkBox;
String url = "";
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//button declared in my activity
button = (Button)findViewById(R.id.button);
button.setOnClickListener(this);
if (!checkBox.isChecked())
url = getString(R.string.url_song1);
else
url = getString(R.string.url_song2);
mediaPlayer = new MediaPlayer();
}
#Override
public void onClick(View arg0) {
try {
Log.i(TAG, "onClick() entered...");
mediaPlayer.setDataSource(url);
Log.i(TAG, "Preparing mediaplayer...");
mediaPlayer.prepare();
Log.i(TAG, "Starting mediaplayer...");
mediaPlayer.start();
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, "bad stream");
}
}
If I copy the songs to my SD card both play fine and as long as the internet url strings have an 'http://' prefix then they also work.