Android MediaPlayer setsurface illegalstateexception - android

I have a ListView with videos as items. In some occasions I get an IllegalStateException while I try to set the surface.
Source code:
if(surfaceTexture != null){
mSurface = new Surface(surfaceTexture);
mMediaPlayer.setSurface(mSurface);
}
Exception:
Fatal Exception: java.lang.IllegalStateException
android.media.MediaPlayer._setVideoSurface (MediaPlayer.java)
android.media.MediaPlayer.setSurface (MediaPlayer.java:829)
However, the Android MediaPlayer docs state that setSurface can be called in any state.
setSurface
any
{}
This method can be called in any state and calling it does not change the object state.
(http://developer.android.com/reference/android/media/MediaPlayer.html)
I cannot reproduce this exception and I don't know in which state the MediaPlayer is during the exception.
Any Ideas?

This would occur if the player was not yet initialized or already released without your realizing it. The documentation for MediaPlayer doesn't seem to reflect the behavior I've experienced. I've encountered it throwing IllegalStateException on very early calls to setSurface where the mediaPlayer object is not null but likely not initialized and separately after release is called. To handle this I simply catch the exception:
try {
mediaPlayer.setSurface(surface);
} catch (Exception e) {
Log.i("TAG", "MediaPlayer setSurface failed.");
}
Since our callback that calls setSurface gets hit multiple times throughout the setup of playback, by the time start is called, the surface has been set again without throwing the exception.

Related

How can I ask Android MediaPlayer not to play after onPrepared?

I am working on an Android application which does lots of concurrencies and RxJava treading in the background and it is possible to not want to play a music which is in the async preparation phase for some reason:
player.prepareAsync()
and
override fun onPrepared(mp: MediaPlayer?) {
isPreparing = false
if (playAfterPreparing) {
//start playback
mp?.start()
} else {
// don't play and keep it prepare for later!!!
}
updateNotification()
}
but the problem is after preparation you should play(!) because:
Media Player called in state 0, error (-38,0)
I even tried to start and pause one after another in preparation:
override fun onPrepared(mp: MediaPlayer?) {
Timber.i("onPrepared")
Timber.i("playAfterPreparing: $playAfterPreparing")
isPreparing = false
//start playback
mp?.start()
if (!playAfterPreparing) {
mp?.pause()
}
updateNotification()
}
but it didn't work cause it rendered to the same issue.
I also know how MediaPlayer state machine is working, but don't see anything in this situation in documents:
https://developer.android.com/reference/android/media/MediaPlayer.html
any solution for such a situation?
Thanks to #VladyslavMatviienko comments, I suspected that I am doing something wrong somewhere else and he was correct. According to Android MediaPlayer document:
It is possible to stay in Prepared state, but it is not possible to call any method namely pause() and that was my fault. In Prepared state You can only call start(), seekTo() or stop().
Hope this answer comes handy for those who might face this issue later.

A public method in Crashlytics to log uncaught exceptions

We usually initialize Crashlytics in the very early stage in our Application.onCreate() method in main thread. The initialization process of Crashlytics is usually very fast, but it could still take more than 2 frames and as long as 32ms on some devices. Since we are constantly improving our cold start time, we thought about putting the Crashlytics initialization into a background thread and the concern is whether we can still capture a crash before the Crashlytics is initialized.
Our approach here is to set up a CustomDefaultUncaughtExceptionHandler as the first thing and initialize Crashlyatics really early as well but in a background thread. If we got a crash before the Crashlytics is initialized or to be initialized, we will reinitialize Crashlytics in the CustomDefaultUncaughtExceptionHandler and use reflection to get CrashlyticsCore's CrashlyticsUncaughtExceptionHandler and then log this uncaught exception.
Our ask is whether it's possible to make a public method for us to log a uncaught exception so that we don't have to use reflection. Or if there are some other suggestions for us to offload the Crashlytics initialization to a background thread but also be able to catch early exceptions.
The pseudo code looks like the following:
public void uncaughtException(Thread thread, Throwable ex) {
try {
if (_crashlyticsEnabled) {
if (!_crashlyticsInitialized) {
// IMPORTANT: in case we encounter a crash before the crashlytics is
// initialized, we can initialize crashlytics here and send this crash
// to the server right away.
initCrashlytics(_context);
Crashlytics.logUncaughtException(thread, ex); // API we are asking
}
}
} catch (Exception e) {
PLog.error(e, "Exception occurred during ...");
} finally {
_defaultExceptionHandler.uncaughtException(thread, ex);
}
}

What means the message "internal/external state mismatch corrected" at the MediaPlayer?

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();

Mediaplayer throws Error(-38,0) on reset()- and prepareAsync()-call

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.

MediaPlayer callbacks not firing after calling prepareAsync() from a Service

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.

Categories

Resources