IllegalStateException occurs in mediaPlayer when start online streaming second time - android

I am creating a simple online audio streaming app.It has 4 buttons Play,Stop,Resume,Pause.When i press stop button,it works fine after that when i start again,application crashes.It gives the following exception
java.lang.IllegalStateException
at android.media.MediaPlayer._setAudioStreamType(Native Method)
at android.media.MediaPlayer.setAudioStreamType(MediaPlayer.java:1723)
at com.onlinestreaming.MediaPlayerActivity.onClick(MediaPlayerActivity.java:48)
at android.view.View.performClick(View.java:5204)
at android.view.View$PerformClick.run(View.java:21153)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
this is what i have done
#Override
public void onClick(View v) {
int id = v.getId();
switch (id) {
case R.id.play:
pd = new ProgressDialog(this);
pd.setMessage("Buffering");
pd.show();
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
mp.setOnPreparedListener(this);
mp.setOnErrorListener(this);
try {
// mp.setDataSource("http://www.robtowns.com/music/blind_willie.mp3");
//mp.setDataSource("http://picosong.com/zkWc");
mp.setDataSource("http://songs1.djmazadownload.com/music/indian_movies/Banjo%20%282016%29/01%20-%20Bappa%20-%20Banjo%20%5BDJMaza.Cool%5D.mp3");
} catch (IOException e) {
Toast.makeText(this, "" + e.getMessage(), Toast.LENGTH_SHORT).show();
}
mp.prepareAsync();
mp.setOnCompletionListener(this);
break;
case R.id.Stop:
mp.stop();
mp.reset();
mp.release();
break;
case R.id.Resume:
mp.start();
break;
case R.id.Pause:
Toast.makeText(this, "Hit", Toast.LENGTH_SHORT).show();
if (mp.isPlaying()) {
mp.pause();
} else {
mp.start();
}
// mp.pause();
break;
}
}
#Override
public void onCompletion(MediaPlayer mp) {
pd.dismiss();
}
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
pd.dismiss();
return false;
}
#Override
public void onPrepared(MediaPlayer mp) {
Toast.makeText(this, "Prepared Finished", Toast.LENGTH_SHORT).show();
pd.setMessage("Playing.......");
mp.start();
}

On stop button press, you are releasing the resource of the MediaPlayer object.
release():
Releases resources associated with this MediaPlayer object. It is
considered good practice to call this method when you're done using
the MediaPlayer. In particular, whenever an Activity of an application
is paused (its onPause() method is called), or stopped (its onStop()
method is called), this method should be invoked to release the
MediaPlayer object, unless the application has a special need to keep
the object around. In addition to unnecessary resources (such as
memory and instances of codecs) being held, failure to call this
method immediately if a MediaPlayer object is no longer needed may
also lead to continuous battery consumption for mobile devices, and
playback failure for other applications if no multiple instances of
the same codec are supported on a device. Even if multiple instances
of the same codec are supported, some performance degradation may be
expected when unnecessary multiple instances are used at the same
time.
So remove mp.release() from stop button clicklistener.
case R.id.Stop:
mp.stop();
mp.reset();
break;

You call mp.release() if the user clicks STOP. This will put the MediaPlayer in the 'End' state (see this state diagram).
So if the user clicks START the next time, you have to use a new MediaPlayer instance because setAudioStreamType() may only be used in the following states (see the MediaPlayer documentation):
Idle, Initialized, Stopped, Prepared, Started, Paused, PlaybackCompleted

Related

Overlapping two sounds in spinner

I'm having trouble with the following:
I have a spinner with different songs in it. In the spinner, users can preview the selected sound. I already developed that part. But my problem is: when I select one song from the list it will play. Then when we select another song from the list, Mediaplayer doesn't stop and plays the previous song also. But what I need is to stop the previous song when a user selects another song.
Here is my code...
//set onClickListner to the onItem SelectedListner
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
choose_ringtone = (int) id;
// Toast.makeText(setAlarm.this,"The selected choice is "+ id,Toast.LENGTH_SHORT).show();
String ringtSound = String.valueOf(parent.getItemAtPosition(position));
//set ringtone options
switch (ringtSound) {
case "alarm Sound 1":
mp = MediaPlayer.create(setAlarm.this, R.raw.wake_up);
break;
case "alarm Sound 2":
mp = MediaPlayer.create(setAlarm.this, R.raw.alarm);
break;
case "alarm Sound 3":
mp = MediaPlayer.create(setAlarm.this, R.raw.wake_up_tone);
break;
case "alarm Sound 4":
mp = MediaPlayer.create(setAlarm.this, R.raw.sweet_alarm);
break;
case "alarm Sound 5":
mp = MediaPlayer.create(setAlarm.this, R.raw.morning_alarm);
break;
default:
break;
}
if(mp!=null) {
mp.start();
}
Before the switch statement, you could do something like
if (mp != null && mp.isPlaying()) {
mp.stop();
}
I am not sure what the rest of your code looks like, but please make sure that it also follows the tips from Android Developers, specifically:
It is also recommended that once a MediaPlayer object is no longer being used, call release() immediately so that resources used by the internal player engine associated with the MediaPlayer object can be released immediately. Resource may include singleton resources such as hardware acceleration components and failure to call release() may cause subsequent instances of MediaPlayer objects to fallback to software implementations or fail altogether. Once the MediaPlayer object is in the End state, it can no longer be used and there is no way to bring it back to any other state.
Try this,,Before start Play call below function.
switch (ringtSound) {
case "alarm Sound 1":
stopPlaying()
mp = MediaPlayer.create(setAlarm.this, R.raw.wake_up);
mp.start();
break;
}
Call the function to stop sound.
private void stopPlaying() {
if (mp != null) {
mp.stop();
mp.release();
mp = null;
}
}
Try mp.stop(); before start any sound...

Android MediaPlayer : IllegalStateException when app closes/press back button

Im streaming an mp3 audio from a url by using mediaplayer, Now im able to play music , But when i press back button or close the app, it crashes.
can anyone pls help me to find my mistake.
thank you.
My code is :
private ImageView play, forward, backward;
private MediaPlayer mediaPlayer;
private boolean playing = false;
private ProgressDialog dialog;
private String mp3link;
private SeekBar seekbar;
private Handler handler = new Handler();
private int mediaPos;
private int mediaMax;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final String url ="";
initWidgets();
}
private void initWidgets() {
mp3link = "http://loc8app.com/church/uploads/audio/749928ad6fcb7b1aceefdf03bd7a9465.mp3";
play = (ImageView) findViewById(R.id.control);
seekbar = (SeekBar) findViewById(R.id.seekBar);
// forward = (ImageView) findViewById(R.id.playeer_forward);
// backward = (ImageView) findViewById(R.id.playeer_back);
mediaPlayer = new MediaPlayer();
play.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
playFunction();
}
});
seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if(mediaPlayer != null && fromUser){
mediaPlayer.seekTo(progress);
}
}
});
}
private void playFunction() {
if (!playing) {
try {
dialog = ProgressDialog
.show(MainActivity.this,
"",
getString(com.root5solutions.music.R.string.buffering),
true);
dialog.setCancelable(true);
dialog.show();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(mp3link);
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
play.setBackgroundResource(R.drawable.pause);
playing = true;
//this is new
mediaPos = mp.getCurrentPosition();
mediaMax = mp.getDuration();
seekbar.setMax(mediaMax);
seekbar.setProgress(mediaPos);
//this line is the error
handler.removeCallbacks(moveSeekBarThread);
handler.postDelayed(moveSeekBarThread, 100);
mp.start();
dialog.dismiss();
}
});
mediaPlayer.prepareAsync();
} catch (Exception e) {
e.printStackTrace();
dialog.dismiss();
}
} else {
play.setBackgroundResource(R.drawable.play);
mediaPlayer.stop();
mediaPlayer.release();
playing = false;
}
}
#Override
public void onBackPressed() {
super.onBackPressed();
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
private Runnable moveSeekBarThread = new Runnable() {
public void run() {
if (mediaPlayer.isPlaying()) {
int mediaPos_new = mediaPlayer.getCurrentPosition();
int mediaMax_new = mediaPlayer.getDuration();
seekbar.setMax(mediaMax_new);
seekbar.setProgress(mediaPos_new);
handler.postDelayed(this, 1000); // Looping the thread after 1 second
}
}
};
}
Logcat shows :
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.root.music, PID: 26981
java.lang.IllegalStateException
at android.media.MediaPlayer.isPlaying(Native Method)
at com.root.music.MainActivity$4.run(MainActivity.java:132)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5351)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:947)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:742)
The issue appears to be being caused by the moveSeekBarThread Runnable, from which the exception is being raised, continuing to execute after mediaPlayer is released in onBackPressed(). This results in the the isPlaying() method being executed, which as per the documentation will result in an IllegalStateException:
if the internal player engine has not been initialized or has been released.
Looking at moveSeekBarThread, it seems to be configured to reschedule itself endlessly by posting itself back into the handler Handler instance with a delay. This process is not being stopped when the user leaves the activity, which explains why moveSeekBarThread keeps running. So, based on the above, one solution could be to make sure that any instances of moveSeekBarThread in handler's queue are removed before calling mediaPlayer.release() when the user leaves the activity.
You should be able to do that by calling handler.removeCallbacks(moveSeekBarThread); before you call mediaPlayer.release(). For example, as follows:
#Override
public void onBackPressed() {
super.onBackPressed();
handler.removeCallbacks(moveSeekBarThread);
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
It should be okay to call it right before mediaPlayer.release(), but I think it's safer to call it regardless of whether mediaPlayer is playing. This way, if the Runnable does get or remain started somehow despite the media player not having being started or having been stopped, the Runnable will still be cleared.
As an aside, while I don't have any experience with MediaPlayer, I happened to notice that the documentation of the release method has the following to say:
It is considered good practice to call this method when you're done using the MediaPlayer. In particular, whenever an Activity of an application is paused (its onPause() method is called), or stopped (its onStop() method is called), this method should be invoked to release the MediaPlayer object, unless the application has a special need to keep the object around. In addition to unnecessary resources (such as memory and instances of codecs) being held, failure to call this method immediately if a MediaPlayer object is no longer needed may also lead to continuous battery consumption for mobile devices, and playback failure for other applications if no multiple instances of the same codec are supported on a device.
So unless there is that special need to keep the media player around in the activity in your case, it might be better to handle the release process (including clearing moveSeekBarThread from handler) in onPause or onStop instead.
Hope that helps!
you are getting IllegalStateException .
Signals that a method has been invoked at an illegal or inappropriate
time .
Call super.onBackPressed(); after if condition
#Override
public void onBackPressed()
{
if (mediaPlayer!= null)
{
if(mediaPlayer.isPlaying())
mediaPlayer.stop();
mediaPlayer.release();
}
super.onBackPressed(); // Call here
}
First you need to understand what illegalStateException means:
According to Android docs:
It Signals that a method has been invoked at an illegal or inappropriate time. In other words, the Java environment or Java application is not in an appropriate state for the requested operation.
have a look at the state diagram of a media player:
https://developer.android.com/images/mediaplayer_state_diagram.gif
Calling setDataSource(FileDescriptor), or setDataSource(String), or setDataSource(Context, Uri), or setDataSource(FileDescriptor, long, long), or setDataSource(MediaDataSource) transfers a MediaPlayer object in the Idle state to the Initialized state.
An IllegalStateException is thrown if setDataSource() is called in any other state.
It is good programming practice to always look out for IllegalArgumentException and IOException that may be thrown from the overloaded setDataSource methods.

How to play/stop/play again using MediaPlayer [duplicate]

This question already has answers here:
Media Player start stop start
(8 answers)
Closed 6 years ago.
I have a button when clicked it plays an audio, and while it is playing I can pause it and replay it again and so forth. I have a shake event, where I want to play the audio on shake and replay it when device is shaken again (by first stopping the audio, calling stopAudio?)
I have the following code:
llBtn = (LinearLayout) findViewById(R.id.button);
llBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Toast.makeText(MainActivity.this, "LL WAS CLICKED", Toast.LENGTH_SHORT).show();
//IF AUDIO IS NOT PLAYING... PLAY AUDIO
if (tvPS.getText() == "Stop Phrase!") {
StopAudio();
}
else {
PlayAudio();
}
}
});
//the same button is clicked to stop, it is currently setting to Pause.
public void StopAudio() {
mediaPlayer.pause();
Toast.makeText(MainActivity.this, "STOPPED", Toast.LENGTH_SHORT).show();
tvPS.setText("Play Phrase!");
}
public void PlayAudio() {
//stopPlaying(mediaPlayer);
tvPS.setText("Stop Phrase!");
inResId = getResources().getIdentifier("play" , "raw", getPackageName());
mediaPlayer = MediaPlayer.create(getBaseContext(), inResId);
mediaPlayer.seekTo(0);
mediaPlayer.start();
mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
//Toast.makeText(MainActivity.this, "Done", Toast.LENGTH_SHORT).show();
tvPS.setText("Play Phrase!");
mediaPlayer.pause();
}
});
}
...
public void onShake() {
// Do stuff!
Toast.makeText(getBaseContext(), "Motion detected",
Toast.LENGTH_SHORT).show();
if (mediaPlayer == null) {
PlayAudio();
}
}
How can I modify the code above to handle Play, and then stop if stopped in the middle and then able to replay it again.
The button click works but I am creating a new instance each time and not recycling. When the device is shaken, it plays the audio twice instead of just once.
First of all create the MediaPlayer in onCreate of the context and not in some listener, and don't forget to release it when done, since it consumes a lot of resources,
mediaPlayer.release();
mediaPlayer = null;
Next thing, stop the audio using the stop() function instead of the pause() on completion of the song.
Steps
If you are using a service/activity to play a video create a MediaPlayer instance before it's usage begins, likely in onCreate.
Later use that instance to play/pause/stop the media.
In the onStop of the Service/Activity release the MediaPlayer instance.
Update your playMusic() function to use the MediaPlayer instance you just created, also in the listener use stop() instead of pause()
To change track of an existing MediaPlayer instance
You can use this:
String path = getExternalFilesDir(null).toString()+"/";
mMediaPlayer.setDataSource(path + mediafile);
Link: Changing data source for audio playback using existing MediaPlayer?

MediaPlayer throwing IllegalStateException when calling onStop()

I have an AlertDialog, which stops playing a sound when I have clicked, but on some devices it appears that calling onStop() throws an IllegalStateException, but why?
If the dialog is up, that means the sound is playing, so it should be a case where the audio is not playing.
I surrounded it with a try catch for now, but what would cause this?
alert.setPositiveButton("YES", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
try{
mp.stop(); //error
mp.reset();
mp.release();
}catch(Exception e){
Log.d("Nitif Activity", e.toString());
}
v.cancel();
popupMessage();
finish();
}
});
Checking mp != null prevents a NullPointerException but the IllegalStateException can't be caused by that.
The reason you get that error is that the player is in a state where it can't stop(). If you have a look at the state-diagram at the top of the MediaPlayer documentation you can see that stop can only be called after the player is in the Prepared state. The next possibility is that you have already called release() or reset() which will also result in that error.
You can call stop() only in Prepared, Started, Paused, PlaybackComplete or Stopped state. All other states produce that error.
So you either do prepareAsync() and the user hits the button before your player is prepared or you have code that releases or resets the player before you hit the button.
I guess you might be nulling your instance before executing these lines.
When I got this error I check for null first.
if (mp != null) {
try {
mp.stop(); //error
mp.reset();
mp.release();
} catch(Exception e){
Log.d("Nitif Activity", e.toString());
}
}
Apparently mp isn't initialized, Dev Resource;
Try adding:
if(mp != null)
Checking mp!=null prevents when it is null, but your mediaplayer never goes null.
just add mp=null; where you are doing mp.stop();

How to turn off my media service for an incoming call? My AudioManager is not working

I'm trying to setup my audio playing app to stop playback if there is an interruption. I followed directions in Android SDK Developer notes about setting up an AudioFocusHelper like so:
public class AudioFocusHelper implements AudioManager.OnAudioFocusChangeListener {
AudioManager mAudioManager;
Media_Service mService;
Context mContext;
public AudioFocusHelper(Context ctx, Media_Service svc) {
mAudioManager = (AudioManager) ctx.getSystemService(Context.AUDIO_SERVICE);
mService = svc;
}
public boolean requestFocus() {
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED ==
mAudioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN);
}
public boolean abandonFocus() {
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED ==
mAudioManager.abandonAudioFocus(this);
}
#Override
public void onAudioFocusChange(int focusChange) {
// let your service know about the focus change
mService.AudioFocus(focusChange);
}
}
and I have my audio player running in a service as they suggest. I have this method in my audio service to respond to Audio Focus changes to pause the playback but its not working -- I don't know how to test this in the vm debugger so I can't really see what is happening on an incoming call. It doesn't appear to get called since I told it to popup toasts:
public void AudioFocus(int focusChange) {
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN: // resume playback
if (mMediaPlayer == null)
initMediaPlayer();
else if (!mMediaPlayer.isPlaying())
mMediaPlayer.start();
//mMediaPlayer.setVolume(1.0f, 1.0f);
break;
case AudioManager.AUDIOFOCUS_LOSS: // Lost focus for an unbounded amount of time: stop playback and release media player
if (mMediaPlayer.isPlaying()) {
Toast.makeText(this,
"Playback interrupted by focus loss", Toast.LENGTH_SHORT).show();
mMediaPlayer.stop();
}
mMediaPlayer.release();
mMediaPlayer = null;
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: // Lost focus for a short time, but we have to stop
// playback. We don't release the media player because playback
// is likely to resume
if (mMediaPlayer.isPlaying()) {
Toast.makeText(this,
"Playback paused by focus loss (transient)", Toast.LENGTH_SHORT).show();
mMediaPlayer.pause();
}
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: // Lost focus for a short time, but it's ok to keep playing
// at an attenuated level
if (mMediaPlayer.isPlaying()) {
Toast.makeText(this,
"Playback paused by focus loss (duck)", Toast.LENGTH_SHORT).show();
mMediaPlayer.pause();
//mMediaPlayer.setVolume(0.1f, 0.1f);
}
break;
}
}
I can post more of the code if necessary, it seems like I'm posting a lot of code already and I don't want to post an excessive amount. It looks to me like my onAudioFocusChange just isn't getting called. I am running this on Android 2.2 (minSDK 8) since these feature is not supported before 2.2. Searched hi and low for tips and I find very little about this topic at all so I'm hoping somebody out there can give me some clues.
I had this same issue, remember you need to call the requestFocus() method when you start playback and abandonFocus() when you are done.
I think this may help with generating incoming calls through DDMS: Fake Incoming Call Android
Hopefully, you can debug your application with this.

Categories

Resources