I'm developing a simple music player, but an error appeared sometimes(just one line error):
Error: start called in state 0, mPlayer(0x0)
I have a MusicService for operating something about music. Part of it:
#Override
public void onCreate() {
super.onCreate();
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setOnBufferingUpdateListener(this);
mediaPlayer.setOnPreparedListener(this);
mediaPlayer.setOnCompletionListener(this);
}
...
public void play(String url) {
try {
mediaPlayer.reset();
mediaPlayer.setDataSource(url);
mediaPlayer.prepareAsync();
} catch (Exception e) {
e.printStackTrace();
}
}
...
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
addTimer();
status = MUSIC_STATUS_PLAYING;
}
When I open a Activity, and bind MusicService, execute play(), the error appeared sometimes.
Any idea?
I had the same issue in Kotlin, and I was able to tackle it.
In my case I added the MediaPlayer.create() inside a Boolean statement, so let's say in fragment 1 I use a Boolean called "globalAudio", I set this Boolean globally true from "MyModel" class, hence it will execute MediaPlayer.create as normal since it is true outside the conditional body. But, if I move to fragment 2 and set the Boolean "globalAudio" to false and when I go back to fragment 1, the Logcat will throw me error "pause called in state 64, mPlayer(0xca47c070)" and "error (-38, 0)", because I am attempting to start the audio without Media.create() being set up.
I attached the problem and the solution below to make the understanding easier for you
Problem
if (MyModel.StaticData.globalAudio) { // A
homeAudio = MediaPlayer.create(requireActivity(), R.raw.background1)
homeAudio.setVolume(MyModel.StaticData.backgroundVolume, MyModel.StaticData.backgroundVolume)
}
if (homeAudio.isPlaying) { // B
homeAudio.pause() // pause
homeAudio.seekTo(0) // set start from 00:00
}
if (!homeAudio.isPlaying) { // C
homeAudio.start() // throws error if A is not executed
}
Solution
//A
homeAudio = MediaPlayer.create(requireActivity(), R.raw.background1)
homeAudio.setVolume(MyModel.StaticData.backgroundVolume, MyModel.StaticData.backgroundVolume)
if (homeAudio.isPlaying) { // B
homeAudio.pause() // pause
homeAudio.seekTo(0) // set start from 00:00
}
if (!homeAudio.isPlaying) { // C
homeAudio.start() // won't throw error because A is always executed
}
Here I provide you a Kotlin code that it can be automatically converted to Java in Android Studio:
var myAudio = MediaPlayer.create(requireActivity(), R.raw.[yourAudio])
myAudio.setVolume([leftChannelInFLoat], [rightChannelInFLoat])
if (myAudio.isPlaying) {
myAudio.pause()
myAudio.seekTo(0)
}
if (!hmyAudio.isPlaying) {
myAudio.start()
}
Related
I found and use some method bellow but it is not work for me:
myThread.stop() //it is not safe but I am tried that
myThread.interupt
Here is my program: I wanna play video using Videoview when video finish. If user no choose the next video in 120s then my app will finish.
My video view code:
Uri uri = Uri.parse(filePath);
videoView = findViewById(R.id.videoView);
videoView.setVideoURI(uri);
waitingThread w8 = new waitingThread();
//set params video before play
videoView.setOnPreparedListener(mediaPlayer -> {
PlaybackParams playbackParams = new PlaybackParams();
playbackParams.setSpeed(DeviceConfig.getInstance().getVideoPeed());// 1.25 1.5 2 2.5
mediaPlayer.setPlaybackParams(playbackParams);
// I am tryied using stop thread here
// w8.stop()
// or w8.interrupt();
videoView.start();
});
videoView.setOnErrorListener((mediaPlayer, i, i1) -> {
Log.d(TAG,"Video Error");
//send error message to server
return false;
});
//I call thread when video complete
videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
**waiting();** -> w8.start //edited i start thread here
}
});
My thread waiting
private class waitingThread extends Thread{
public void run() {
try {
while (!isInterrupted()) {
timeCount ++;
Thread.sleep(1000);
Log.d(TAG, "Time count : " + timeCount);
if(timeCount == 120){
finish();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//i am try to using this funtion but still not work too.
public void stopping(){
Thread.currentThread().interrupt();
// timeCount = 0;
// Log.d(TAG, "Stopping, reset time :" + timeCount);
}
}
Brief my idea: When video start play, thread waiting will be stopped. When video finish program will waiting a time if no video chose in time to wait program will finish, if any video chose then thread w8 stop.
My problem: when I choose the next video, my thread "w8" still keep running. That is make my app finished while video playing
Plz help me how to fix that problem or any same idea to work are appreciated
You don't want to call interrupt on Thread.currentThread. Thread.currentThread is the thread currently running- it's the thread you're calling the function on. It's not the thread object you just created. Instead it would be this.interrupt(). Or just get rid of the function entirely and call interrupt directly.
Introducing your own boolean variable might help
class waitingThread extends Thread{
boolean stop;
public void run(){
while(!stop){
//your task
}
stop = false; //
}
public void stopping(){
stop= true;
}
}
what I'm trying to do is add 1 button that will play and stop the music. is it possible to loop them like 1st click play then 2nd click stop 3rd click will start from beginning and 4th stops again and so on?
based on my search on google it's something like this? sorry if noob question
public void playtd(View view) {
if(!td.isPlaying()) {
td.start();
}
else if(td.isPlaying()) {
td.pause();
}
}
Try This:
MediaPlayer td;
boolean isPrepared;
public void prepareMediaPlayer(Uri yourTrackUri){
// call this on initialization of your mediaplayer
sMRMediaPlayer = MediaPlayer.create(mContext, uri);
sPrepared = true;
}
public void playtd(View view) {
if (!isPrepared) {
prepareMediaPlayer(Uri yourTrackUri)
}
if(!td.isPlaying()) {
td.start();
else {
// reprepare mediaplayer
td = MediaPlayer.create(Context, uriToUrFile);
isPrepared = true;
}
} else { // stop playing instead of pause, stop will start playing next time u play from beginning
td.stop();
}
void releaseMediaPlayer() {
if (td!= null) {
Log.d(TAG, "MediaPlayer is released.");
td.reset();
td.release();
td= null;
isPrepared = false;
}
}
call releaseMediaPlayer once done with all play and stop stuff (may be on destroy etc.)
initialize mediaplayer by passing track uri to prepareMediaPlayer
add try catch, wherever needed
for last three weeks I have worked on a Media Player in Android.I am trying to find a solution of how can I make my Media Player to change the song when it's already playing one.
Here is my Listener on the RecyclerView
musicList.addOnItemTouchListener(
new RecyclerItemClickListener(getApplicationContext(), new RecyclerItemClickListener.OnItemClickListener() {
#Override
public void onItemClick(View view, final int position) {
currentPosition = position;
if(!mediaPlayer.isPlaying()){
musicThread.start();
} else {
mediaPlayer.reset();
}
}
})
);
}
and my Thread is this:
final Thread musicThread = new Thread(new Runnable(){
#Override
public void run() {
try {
URL = getMusicURL(myDataset[currentPosition]);
try {
mediaPlayer.setDataSource(URL);
//mediaPlayer.prepare(); // might take long! (for buffering, etc)
mediaPlayer.prepareAsync(); // prepare async to not block main thread
} catch (IOException e) {
e.printStackTrace();
Log.i("TEST","Eroare: "+e.getMessage());
}
} catch (StorageApiException e) {
e.printStackTrace();
Log.i("TEST","Eroare: "+e.getMessage());
}
}
});
I think you have a mess. First of all, you dont need a thread to play music, the own mediaplayer API does it for you when you call mediaPlayer.start(). However, you have to care about the time it takes to prepare the data source if you are for example streaming online music. For this, just use mediaPlayer.prepareAsync() and register a callback. When it has finished preparing, you can automatically start playing or do whatever you want.
If you want to change the data source, just follow the automaton map that you can find in MediaPlayer docs. Essentially, when the user selects another track, you register the call in your button listener, then reset the mediaPlayer, and recall all prepare, start... cycle again. By the way, it is advised to deploy all your mediaplayer code into a service so that it can keep playing even though the user has closed your activity.
I have problems with my app because multimedia sound is heard when the app is in background
I have defined my Media player like this;
private void playLocalAudio(int R1)throws Exception
{
MediaPlayer mediaPlayer = MediaPlayer.create(this,R1);
mediaPlayer.start();
}
For calling PlayLocalAudio I do:
try{
playLocalAudio(R.raw.fartw1);
}
catch (Exception e) {
e.printStackTrace();
}
}});
But I am not able to call correctly MediaPlayer.Stop()
I am trying:
public void onPause()
{
super.onPause();
mediaplayer.stop();
}
But it doesn't work. Could you help me?
I'm guessing that your code has a class variable mediaPlayer that's not visible in your example. In that case you have variable shadowing, because you're instantiating a new mediaPlayer in playLocalAudio and that instance is not visible inside the pause method. So stop is never called. Remove the MediaPlayer class name from the declaration in playLocalAudio.
I am making a music player with a service but when i click a song in the music list, the music starts with no errors, but if i go back to the list and click another i get Attempt to call getDuration without a valid mediaplayer error (-38, 0)
My onStart method in the service:
#Override
public void onStart(final Intent i, int startid) {
Log.d(TAG, "Start music");
re = 0;
songUrl = i.getData().toString();
streamMusic = new Thread() {
public void run() {
Looper.prepare();
try {
re = 1;
music.reset();
music.setDataSource(songUrl);
music.prepare();
this.interrupt();
} catch (Exception e) {
e.printStackTrace();
}
}
};
streamMusic.start();
}
I start the service with startService(i); and I have set a music.setOnPreparedListener so nothing is runned to early.
How do I make it work?
Try calling reset() method before calling prepare again.
Also, if you are calling prepare() and not prepareAsync() I don't see why you need to use the prepared listener.