I'm working on writing a small app that will stream mp3 files. I'm using the NPR code, but having a strange problem with mediaPlayer.prepareAsync().
I'm using a trimmed down version of the PlaybackService from the NPR app, which is getting started correctly. I am getting a reference to the service inside an OnClick handler inside an Activity, and calling listen() with the URL to the MP3 stream. The following (simplified) code is from my PlaybackService:
public void listen(String url) throws IllegalArgumentException, IllegalStateException, IOException {
if (mediaPlayer == null) {
mediaPlayer = new MediaPlayer();
}
mediaPlayer.setOnBufferingUpdateListener(this);
mediaPlayer.setOnCompletionListener(this);
mediaPlayer.setOnErrorListener(this);
mediaPlayer.setOnInfoListener(this);
mediaPlayer.setOnPreparedListener(this);
synchronized (this) {
mediaPlayer.setDataSource(url);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.prepareAsync();
}
}
// ... lots of other code
#Override
public void onPrepared(MediaPlayer mp) {
Log.d(LOG_TAG, "Prepared");
play();
}
I have the other callbacks defined as well. I can see from LogCat that the MediaPlayer is loading the stream and buffering, as I see the following messages:
AwesomePlayer I calling prefetcher->prepare()
AwesomePlayer I prefetcher is done preparing
But my onPrepared method never gets called. If I add a timer and try to call play() on the MediaPlayer at some point after I see the above log messages, the media players plays, so it is indeed entering into the Prepared state.
If I replace the call to prepareAsync() with prepare(), the player just works. This is all on 2.2, which I have been reading seems to have some issues, but the problem I'm having doesn't seem related, as the stream works fine when prepare() is used.
I did notice that the Content-Length on the the stream is quite large (450MB), but since I can call play on the Media Player without getting an exception, it appears to be handling this OK.
The only other change is that in the NPR app, the service is being bound to and the playback started from inside a View object (while in my app, this happens inside an Activity).
Any thoughts on what I could be doing wrong?
Make sure you have created the mediaplayer in a thread that has a looper, which is required for the callbacks to work properly.
Related
I've seen other posts on this but I cant figure out problem.
So I'm designing a calculator and all the numbers have one onclick method and all the operators have different . I have a method playSound() where the code is:
public void playSound(){
MediaPlayer mp= MediaPlayer.create(this, R.raw.btn);
setVolumeControlStream(AudioManager.STREAM_MUSIC);
if(mp.isPlaying())
{
mp.stop();
mp.reset();
}
mp.start();
}
I've tried release to. Can anyone let me know the efficient way to write this.
I call this method inside the onclick methods. But after around 30 clicks it stops. I've also tried to create MediaPlayer global but it still stops. I've read mediaplayer is actually costly so we can use soundpool. But even soundpool is deprecated. Any help?
Implement onComplition() Listener , and in that listener you can call release method
You created multiple instances of mediaplayer and not release mediaplayer instanace thats why issue is came
After you release called your issue will be resolved
Initialize the MediaPlayer as a class attribute:
MediaPlayer media = MediaPlayer.create(this,R.raw. btn);
In the playSound() method:
public void playSound(){
setVolumeControlStream(AudioManager.STREAM_MUSIC);
mp.reset();
mp.start();
}
I'm trying to get a simple sound to play. The sound plays on the emulator but not on the phone. It says
start called in state 0
and
Error (-38,0)
Here's what I've tried so far:
MediaPlayer secondSound;
MediaPlayer minuteSound;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
secondSound = new MediaPlayer();
secondSound = MediaPlayer.create(this, R.raw.everysecondsound);
minuteSound = MediaPlayer.create(this, R.raw.everyminutesound);
secondSound.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
public void onPrepared(MediaPlayer player) {
player.start();
}
});
minuteSound.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
public void onPrepared(MediaPlayer player) {
player.start();
}
});
}
Later in the program, the following methods are called:
minuteSound.start();
secondSound.start();
On the emulator, this works fine even without the .setOnPreparedListener part. The emulator is running API 22, the phone is running API 19. Is there a different way to use the media player in the older APIs?
When you call MediaPlayer.create(), that automatically calls prepare() for you, as seen in the source code. As per the state diagram in the MediaPlayer documentation:
This puts you into the Prepared state. At that point, when you call start(), you move into the Started state. After playback completes, you'll be in the Playback Completed state. If you'd like to play your sound again, you have to call create() again, or call stop() and prepare() again.
You'll find SoundPool more appropriate for short tracks you want to play repeatedly.
First of all, I think you have to declare the minute MediaPayer (as you did with the second), this way: minuteSound = new MediaPlayer();
Try this and return. If it doesn't work, maybe you will have to release the MediaPlayer before calling it again.
The problem was the file format for my sound files. They were originally 96000Hz wave files, I changed them to 44100Hz MP3 files and then everything worked. I removed the .setOnPrepareListener part since it worked without it.
I work with a MediaPlayer and set the state of the player often programmatically like for example:
if(mp.isPlaying()) {
mp.pause();
animationPausedMusic();
}
private void animationPausedMusic() {
// Changing button image to play button
btn_play.setBackgroundResource(R.drawable.play);
... // more code
}
But sometimes the logcat gives me the message:
"internal/external state mismatch corrected"
And then the play and pause function is not working anymore.
What does this message mean? And how can I solve it?
After going through the android's native framework for media player I found that in source file mediaplayer.cpp inside function bool MediaPlayer::isPlaying() The developer is checking if the currentState of media player is in STARTED state and yet the media player is not playing any media, so it tries to change the state to PAUSED state so that the state consistency should be maintained for API users.(and here is where he is printing the message "ALOGE("internal/external state mismatch corrected");")
Now If you go through the media player state diagram below:
You would notice that this may happen when the MediaPlayer moved to 'STARTED' state after a call to start() and at this time for some obscure reason has not yet started the playback and you fire a MediaPlayer.isPlaying() method call , The Framework treat this as state inconsistency and moves to 'PAUSED' state and that's why you cannot see anything playing further.
However, if someone has some better understanding please share your thoughts!
I ran into this recently, and like some other questions say, it's this bug (marked obsolete alas)
https://code.google.com/p/android/issues/detail?id=9732
I found this error occurs when playing a MIDI file, but only sometimes. It happens when mp.isPlaying() is called quickly after mp.start()
If you can manage to not call mp.isPlaying() for a little bit, the error doesn't occur. In my case, a 10th of a second or so made the difference between getting the error or not. It's awkward, but it works.
e.g.
//setting a new track
mp.setDataSource(path);
mp.prepare();
mp.start();
//calling mp.isPlaying() here or shortly after starts the problem
//since we know it's playing, we can store that state, or call
updateUiPlaying(); //eg instead of updateUi();
//or just call some code here that takes more time first
updateScaledImages(); //something that might take time
Log.v(TAG, "mp.isPlaying = " + mp.isPlaying()); //now isPlaying() shouldn't cause that error
Also, I put a check in when I pause later.
mp.pause()
if(mp.isPlaying()){
//shouldn't be playing, must be in error
mp.stop();
mp.release();
mp = new MediaPlayer();
//any other initialization here
}
Though the problem doesn't occur if there is a wait before calling isPlaying()
Apparently there is more than one cause of this message. The following solution worked for me. It may or may not work for you. I called the method MediaPlayer.reset() immediately after instantiating the MediaPlayer object:
MediaPlayer mp = new MediaPlayer();
mp.reset();
I have this piece of code:
try
{
mMusicPlayer.reset();
FileInputStream fis = new FileInputStream(pathToTitleFile);
mMusicPlayer.setDataSource(fis.getFD());
mMusicPlayer.prepareAsync();
}
catch (Exception e){}
When I skip a song, sometimes I get two Error/error(-38,0).
I've debugged it and the errors were thrown at the following code-section:
The error(-38,0) after the reset()-call. The Error(-38,0) after the prepareAsync()-call.
After this the player calls the onPrepare()-callback and jumps back and performs the try-block again. This repeats a few times before the song is played.
Strange thing is, that I don't get any other information about the error and error (-38,0) seems to be a "generic-error".
Based here MediaPlayer reset
Resets the MediaPlayer to its uninitialized state. After calling this method, you will have to initialize it again by setting the data source and calling prepare().
You need to initialize MediaPlayer again.
I have an application with a VideoView that will keep looping the same video over and over until a user does something to the device(touch screen, etc) Currently I am using the OnCompletionListener() to restart the video once it ends. This works properly on every device I have tested, except for the Samsung Replenish.
Here is my code:
mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mVideoView.setVideoPath(file.getAbsolutePath());
mVideoView.start();
}
});
What happens on the Replenish is the video plays all the way through once but then is never started again and the screen goes all black (But backlight still turned on). On every other device I've tested on with this exact same code it has worked to repeat the video. Does anyone know of anything specific about the Replenish that could cause this error? I thought maybe delaying the calls to setVideoPath(), and start() by 200-300ms might help it, but that had no affect. I am really at a loss here.
I am seeing these messages in my Log:
ERROR/QCvdec(87): Omx Flush issued when vdec is not initialized yet.
ERROR/QCvdec(87): OMXCORE-SM:Recieved command DISABLE (2)
ERROR/QCvdec(87): Omx Flush issued when vdec is not initialized yet.
ERROR/QCvdec(87): OMXCORE-SM:Recieved command ENABLE (3)
But these logs are happening both when the video starts (the first time it plays) and when it fails to start again. so I am not sure if they are related to my problem
Edit:
I just tried setting mVideoView to null, and then getting a new reference to it with findViewById() right before the setVideoPath(). I know this would complicate the way the OnCompletionListener is set up. But regardless of that it didn't work anyway, still the same dark screen.
Edit 2:
I've started to notice that sometimes the video doesn't even start the first time. I am using these same two lines to start it up the first time:
mVideoView.setVideoPath(file.getAbsolutePath());
mVideoView.start();
It seems to start more consistantly, but not quite 100% when its the first time it is being played.
Edit 3: This is how I have it set up now. I am manually setting the OnPreparedListener to start the video for me. So I added this to my onCreate()
mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer arg0) {
mVideoView.start();
}
});
Then when I am ready to restart the video I just call only the setVideoPath() method, Like this:
mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mVideoView.setVideoPath(file.getAbsolutePath());
}
});
This seems to be doing the trick. I am letting it run for a while to find out for sure though.
Edit 4:
#MByD In the code for VideoView setVideoPath() is a wrapper for setVideoUri(). setVideoURI() is setting mStartWhenPrepared = false; The default OnPreparedListener checks this switch to decide whether to start playback or not. That is why it doesn't start with the default listener. I haven't looked into it more than that, but there may be a setter method that lets me change the mStartWhenPrepared value to true, which would cause the video to be started from the default listener.
Have you tryed to prepare() your video before you call .start()?
from the docs: http://developer.android.com/reference/android/media/MediaPlayer.html#prepare%28%29
with a OnPreparedListener you can start your video when its ready.