Open anonym24 opened 7 years ago
And when I run mMediaPlayer.prepareAsync();
in new Thread, then everything is ok, but I don't think this is a normal solution, this should work without creating any new threads (like with default android mediaplayer)
mMediaPlayer.reset();
try {
mMediaPlayer.setDataSource(source);
new Thread(new Runnable() {
@Override
public void run() {
mMediaPlayer.prepareAsync();
}
}).start();
} catch (IOException e) {
Log.i(TAG, "mMediaPlayer setDataSource e: " + e);
}
I also confirm that prepareAsync() not load OnPreparedListener(). It dose only the first time, cold be the .resete()?
@anonym24 @SluggedGerm2 Hi. Sorry for the late response 😞 I tried to reproduce it today, but it cannot be done yet. Could you provide a sample project which can reproduce the issue?
04-29 20:13:56.809 26389-26389/com.android.testpalyer E/OpenSLMediaPlayer: An error occurred in getCurrentPosition() 04-29 20:13:56.815 26389-26389/com.android.testpalyer I/LOGGG: MediaPlayer: onError -38 0
This seems that you are calling getCurrentPosition()
method in wrong state. Please refer to the "Valid and invalid states" table on the official MediaPlayer document.
public OpenSLMediaPlayer player;
private OpenSLMediaPlayerContext openSLMediaPlayerContext;
public Song nextSong;
private Song actual_playing;
public customPlayer(Context context){
OpenSLMediaPlayerContext.Parameters parameters = new OpenSLMediaPlayerContext.Parameters();
parameters.streamType = AudioManager.STREAM_MUSIC;
openSLMediaPlayerContext = new OpenSLMediaPlayerContext(context,parameters);
player = new OpenSLMediaPlayer(openSLMediaPlayerContext,Settings.OPTION_USE_FADE);
player.setOnPreparedListener(new OnPreparedListener()); //I add one single time the prepared listener
nextSong = null;
actual_listSong = new ArrayList<>();
}
class OnPreparedListener implements IBasicMediaPlayer.OnPreparedListener{
@Override
public void onPrepared(IBasicMediaPlayer mp) {
mp.start();
}
}
private void playSong(final Context context, final Song song){
if (player == null) { //create the player if it is null
new customPlayer(context);
} else {
player.reset(); //reset the player anyway. If it is playing, or has finished to play, setdatasource wan't crash without the reset of mediaplayer
//player.setOnPreparedListener(new OnPreparedListener()); //I tried here to reset the player,but didn't work
}
Uri contentUri = ContentUris.withAppendedId(android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, song.getID());
if (contentUri == null) {
Log.i(LOG_TAG,"Error finding the media Id : " + song.getTitle() + " - " + song.getID());
return;
}
setNextSong(); //update the next song
try {
player.setDataSource(context,contentUri);
player.prepare();
player.start();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(context,e.getMessage() + " (" + actual_playing.getTitle() + ")",Toast.LENGTH_LONG).show();
}
}
Using prepareAsync() the OnPrepared is called the first time but not the following times. For this reason i'm using normal prepare() I also tried to create an asynctask and simulate the prepareAsync() but didn't work, some error occured
@SluggedGerm2 Thanks, but it cannot be reproduced yet on my setup. Could you try the following repository, it is a simple sample project based on your code.
https://github.com/h6ah4i/openslmediaplayer_issue_40
My setup:
Your sample works :/ what is the trick?
@h6ah4i for me my own project seems to be working ok now, not sure what happened I tried 0.7.3 & 0.7.5 and both worked ok. I'll let you know if issue happens again and upload example
also I'll check my old backuped projects, and compare with the latest one and mb find out something
@h6ah4i: I have updated my project from 0.7.3 to 0.7.5 and now the prepareAsync() is called some times, but still not always. I can't see anything common for songs that never arrived to OnPreparedListener. The same song sometimes works and other time not. I thought that cold be the thread that simultaneasly try to read the the song cover art, but also disabling this thread prepareAsync doesn't work. Disabling this thread there isn't anything more can interfare with song prepare, i think For example now I'm trying to play always same two songs. Sometimes both works, sometimes only one, and sometimes none works. But your sample works. I can't understand what's wrong.
I guess I quite understood the problem, so mb it really because of calling such methods like .getDuration
, .getCurrentPosition
in the wrong state (e.g. before source/song was prepared).
And it seems that OpenslMediaPlayer calls onCompletion
method when these errors happens - here I guess the difference between OpenslMediaPlayer
& Default Android MediaPlayer
.
So for Default Android MediaPlayer
these errors weren't critical, it didn't call onCompletion
and it still calls onPrepared
so there was no loop with fast switching to the next song (in onCompletion
method I call my nextSong
method)
yes, now I'm sure. If we for example call mMediaPlayer.getCurrentPosition()
while something is being prepared async (with prepareAsync
method), OpenslMediaPlayer
will call onError
and onCompletion
and will NOT call onPrepared
.
Default Android MediaPlayer
doesn't behave like this with prepareAsync
@anonym24 Thanks for this clarification! now I can try to avoid this problem :)
I solved with a simple boolean that is setted to false when setDataSource is setted (so before prepareAsync) and is setted to true when the Onprepared is called. So I ovveride dangerous methods like getCurrentPosition() to make it only working if the boolean is true
@SluggedGerm2 yeah I did exactly the same :)
@anonym24 @h6ah4i Thanks a lot for your kind help
@anonym24 @h6ah4i @SluggedGerm2 Is there anyone to guide me for the same.
Actually I'm also facing the same scenario even after performing the above suggestions
And my audio glitches if I perform prepare()
fun startSong() { mHandler?.removeCallbacks(sendUpdatesToUI)
mSong = mSongs[mSongPos]
mMediaPlayer1?.reset()
mMediaPlayerPrepared = false
try {
mSongDataHelper = SongDataHelper()
mSongDataHelper?.populateSongData(mContext!!, null, mSongPos)
mMediaPlayer1?.setDataSource(mContext!!, getUri(mSongs[mSongPos]._id!!))
mMediaPlayer1?.setOnPreparedListener(onPreparedListener)
mMediaPlayer1?.setOnErrorListener(onErrorListener)
mMediaPlayer1?.prepareAsync()
} catch (ex: Exception) {
ex.printStackTrace()
}
}
/ Prepared Listener /
private val onPreparedListener =
IBasicMediaPlayer.OnPreparedListener {
mMediaPlayerPrepared = true
mMediaPlayer1?.setOnCompletionListener(mOnCompletionListener)
if (mPlayingForFirstTime) {
mPlayingForFirstTime = false
}
startPlaying()
val intent = Intent(Constants.ACTION_UPDATE_NOW_PLAYING_UI)
intent.putExtra(Constants.UPDATE_UI, true)
sendBroadcast(intent)
}
@anonym24 @h6ah4i @SluggedGerm2 Is there anyone to guide me for the same. Actually I'm also facing the same scenario even after performing the above suggestions And my audio glitches if I perform
prepare()
fun startSong() { mHandler?.removeCallbacks(sendUpdatesToUI)
mSong = mSongs[mSongPos] mMediaPlayer1?.reset() mMediaPlayerPrepared = false try { mSongDataHelper = SongDataHelper() mSongDataHelper?.populateSongData(mContext!!, null, mSongPos) mMediaPlayer1?.setDataSource(mContext!!, getUri(mSongs[mSongPos]._id!!)) mMediaPlayer1?.setOnPreparedListener(onPreparedListener) mMediaPlayer1?.setOnErrorListener(onErrorListener) mMediaPlayer1?.prepareAsync() } catch (ex: Exception) { ex.printStackTrace() } }
/ Prepared Listener /
private val onPreparedListener = IBasicMediaPlayer.OnPreparedListener { mMediaPlayerPrepared = true mMediaPlayer1?.setOnCompletionListener(mOnCompletionListener) if (mPlayingForFirstTime) { mPlayingForFirstTime = false } startPlaying() val intent = Intent(Constants.ACTION_UPDATE_NOW_PLAYING_UI) intent.putExtra(Constants.UPDATE_UI, true) sendBroadcast(intent) }
Wonderfull. Thanks
I created a hybrid player in my service. When I do this:
It just instantly calls
onError
&onCompletion
and tries to play the next song, fails again with the same error and so on