Here is my code
if (player != null) {
if(player.isPlaying()){
player.pause();
player.stop();
}
player.release();
}
and here is error
FATAL EXCEPTION: main
java.lang.IllegalStateException
at android.media.MediaPlayer.isPlaying(Native Method)
at com.mindefy.sindhipathshala.RecViewAdapter.mediafileRelease(RecViewAdapter.java:234)
at com.mindefy.sindhipathshala.SectionFruits.onBackPressed(SectionFruits.java:252)
I am a beginner in Android and i am very confused with the lifecycle of a MediaPlayer.
This is a function in an adapter that is called from onBackPressed() function of another Activity. player is a class variable.
I am releasing this MediaPlayer in same file as
public void onClick(View v) {
try {
if (player != null) {
player.stop();
player.release();
}
} catch (Exception e) {
}
player = MediaPlayer.create(activityContext, soundId);
player.start();
}
The problem is you don't keep track of the state of your MediaPlayer instance.
Before calling isPlaying() you only perform a null value check, although player can still be released (but not null).
Calling isPlaying() on a released MediaPlayer instance will result in an IllegalStateException.
To avoid this, you could for example set player to null when you release it:
player.release();
player = null;
Or you could use a boolean flag to keep track of its state:
boolean isReleased;
// ...
player.release();
isReleased = true;
So you could check for this flag when necessary:
if (player != null && !isReleased) {
if(player.isPlaying()) {
// ...
}
}
(don't forget to set it to false when appropriate)
Adding to earthW0rmjim: I was facing the same issue (some audios didn't reproduce because of an ilegal state exception). What I found is that I was reseting my audio object on a callback. So, I was setting player.setDataSource(url) before I reset my object, because the callback was doing it after. My solution: player.reset() on the try / catch block of setDataSource and prepareAsync.
try {
player.reset(); //Important line
player.setDataSource(url);
player.prepareAsync();
} catch (Exception e) {
Log.e(Constants.AUDIO_LOG_TAG, "Error playing file " + url, e);
}
And look at the callback:
public void finishedPlayback(){
player.reset(); //Executing after the try / catch (sometimes)
}
Related
I am trying to create Mediaplayer session with given uri. but it causes NullpointerException.
Uri uri = Uri.parse(path);
// Creating MediaPlayer with given song's URI
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
}
mediaPlayer = MediaPlayer.create(this, uri);
try {
// Setting the MediaPlayer Listener
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
seekBar.setMax(mp.getDuration());
mediaPlayer.start();
changeSeekbar();
}
});
} catch (Exception e) {
Log.e("ERROR", e.toString());
}
Given Logcat:
2020-04-07 22:21:05.289 12237-12237/com.example.musicappresearch2 E/Path: /storage/emulated/0/Music/Alone - Viren.mp3
2020-04-07 22:21:05.289 12237-12237/com.example.musicappresearch2 E/ERROR: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.media.MediaPlayer.setOnPreparedListener(android.media.MediaPlayer$OnPreparedListener)' on a null object reference
Could you Tell me What i am doing wrong ? Thanks.
There are two ways to write this code, both tested on the device
First of all, make sure you handle android.permission.READ_EXTERNAL_STORAGE correctly and you really have correct Uri.
MediaPlayer.create(this, uri); will fail if either context or uri are invalid.
MediaPlayer.create(this, uri); which itself already prepares player so you don't need .prepareAsync() in this situation. and your code is good to go.
another way:
mediaPlayer = new MediaPlayer(); // hence, we don't use .create, manually instantiate
try {
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(this, uri);
mediaPlayer.setOnPreparedListener(mp -> {
mediaPlayer.start();
});
/* use async, if you don't want to block UI thread
keep in mind, this should be called after setting listener
because it might prepare even until the listener has been set */
mediaPlayer.prepareAsync();
} catch (Exception e) {
Log.e("ERROR", e.toString());
}
Try this :
Uri uri = Uri.parse(path);
mediaPlayer = new MediaPlayer();
try {
// mediaPlayer.setDataSource(String.valueOf(uri));
mediaPlayer.setDataSource(MainActivity.this,uri);
} catch (IOException e) {
e.printStackTrace();
}
try {
mediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
mediaPlayer.start();
My photo taking algorithm works perfectly the first time, but if I call the method the second time, I get java.lang.RuntimeException: Fail to connect to camera service on camera.open()
takePhoto(this, 0);//back camera.
takePhoto(this, 1);//selfie. No matter what, the second line crashes. Even if I switch the two lines.
Here is the method that only works the first time:
private void takePhoto(final Context context, final int frontorback) {
Log.v("myTag", "In takePhoto()");
final SurfaceView preview = new SurfaceView(context);
SurfaceHolder holder = preview.getHolder();
// deprecated setting, but required on Android versions prior to 3.0
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
holder.addCallback(new SurfaceHolder.Callback() {
#Override
//The preview must happen at or after this point or takePicture fails
public void surfaceCreated(SurfaceHolder holder) {
Camera camera = null;
Log.v("myTag", "Surface created ");
try {
camera = Camera.open(frontorback); //** THIS IS WHERE IT CRASHES THE SECOND TIME **
Log.v("myTag", "Opened camera");
try {
camera.setPreviewDisplay(holder);
} catch (IOException e) {
Log.v("myTag", "Can't assign preview to Surfaceview holder" + e.toString());
}
try {
camera.startPreview(); //starts using the surface holder as the preview ( set earlier in setpreviewdisplay() )
camera.autoFocus(new Camera.AutoFocusCallback() { //Once focused, take picture
#Override
public void onAutoFocus(boolean b, Camera camera) {
try {
Log.v("myTag", "Started focusing");
camera.takePicture(null, null, mPictureCallback);
Log.v("myTag", "Took picture!");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
} catch (Exception e) {
Log.v("myTag", "Can't start camera preview " + e.toString());
if (camera != null)
camera.release();
throw new RuntimeException(e);
}
}catch(Exception e){
Log.v("myTag", "can't open camera " +e.toString());
e.printStackTrace();
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
});
addPreviewToSurfaceView(); //Irrelavent here
}
//CALLBACK WHERE I RELEASE:
android.hardware.Camera.PictureCallback mPictureCallback = new android.hardware.Camera.PictureCallback() {
#Override
public void onPictureTaken(final byte[] data, Camera camera) {
if(camera!=null){
camera.stopPreview();
camera.setPreviewCallback(null);
camera.release();
camera = null;
}
downloadPicture(data);
sendPicture(data);
Log.v("myTag","Picture downloaded and sent");
}
};
It's odd, because takePhoto(context, int) only works the first time no matter what. Even if I switch the second parameter, only the first takePhoto() works.
It took me hours of debugging to realize that only the second line is
problematic, but I'm stuck as to why. Any feedback is much
appreciated!
EDIT:
Even after removing the code in my onPictureTaken callback, the problem continues to persist. I suspect the camera may need time to reopen immediately, but I can't sleep the thread since I'm performing UI interactions on it. This bug is like a puzzle right now!
You cannot call takePhoto() one after another, because this call takes long time (and two callbacks) to complete. You should start the second call after the first picture is finished. Here is an example, based on your code:
private void takePhoto(final Context context, final int frontorback) {
...
android.hardware.Camera.PictureCallback mPictureCallback = new android.hardware.Camera.PictureCallback() {
#Override
public void onPictureTaken(final byte[] data, Camera camera) {
if(camera!=null){
camera.stopPreview();
camera.setPreviewCallback(null);
camera.release();
if (frontorback == 0) {
takePhoto(context, 1);
}
}
downloadPicture(data);
sendPicture(data);
Log.v("myTag","Picture downloaded and sent");
}
};
This will start the first photo and start the second photo only when the first is complete.
Here might be problem.
After you take photo, the picture taken callback get called.
if(camera!=null){
camera.stopPreview();
camera.setPreviewCallback(null);
camera.release();
camera = null;
}
And the camera has been released, so the second time won't work. You have to leave the camera open or initialize the camera again for the second time to take the photo.
I am using the mediaplayer feature on Android. I basically have songs in the raw folder and I would just like to change to a new track but it fails. One music file plays and then I press a button after or during the music playing to skip to a random track but it fails.
Current code
mediaplayer.stop();
try {
mediaplayer.prepareAysn();
mediaPlayer.selectTrack(randomtrack_num - 1);
}
catch(Exception e){}
mediaplayer.start();
The error that I receive:
MediaPlayer: start called in state 64
MediaPlayer: error (-38, 0)
MediaPlayer: Error (-38,0)
I tried this without mediaplayer.stop() and still included mediaplayer.start() at the end and it would just replay the same track again.
Am I missing something?
Please let me know.
2nd Approach
After reading the document I realized this can only be done in the prepared state which I assume in my second approach it should work but it is not.
mediaPlayer.stop();
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener(){
#Override
public void onPrepared(MediaPlayer mp) {
try{
mp.selectTrack(randomtrack_num - 1);
}catch(Exception e){}
mp.start();
}
});
mediaPlayer.prepareAsync();
I get this error:/MediaPlayer: Should have subtitle controller already set
Basically the same track plays again and it does not go to the selected track.
You are calling mediaplayer.start() in wrong state. Firstly read this documentation:
https://developer.android.com/reference/android/media/MediaPlayer.html
You will have a better idea of correct implementation.
EDITED:
String[] url ; // initiliaze your URL array here
MediaPlayer myMediaPlayer = new MediaPlayer();
myMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
myMediaPlayer.setDataSource(url[0]);
myMediaPlayer.prepareAsync(); // might take long! (for buffering, etc)
} catch (IOException e) {
Toast.makeText(this, "mp3 not found", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
//mp3 will be started after completion of preparing...
myMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer player) {
player.start();
}
});
Playing different track after completions
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp)
{
myMediaPlayer.reset();
/* load the new source */
myMediaPlayer.setDataSource(url[position]);//select the path according to your need
/* Prepare the mediaplayer */
myMediaPlayer.prepareAsync();
}
I've looked around here but none of the solutions I've found work for me.
Basically, what I'm trying to do is start recording when the ImageButton is held down, stop recording when the ImageButton is released and be able to record again, this time, overwriting the old recording, without first closing the app. When I try to record more than once (hold down the ImageButton again), the app crashes and gives me a:
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.media.MediaRecorder.prepare()' on a null object reference
at com.myname.audiorecorder.MainActivity.startRecording(MainActivity.java:86)
at com.myname.audiorecorder.MainActivity$1.onTouch(MainActivity.java:61)
This is my code (Both errors have comments with **)
public class MainActivity extends Activity {
Button play;
private MediaRecorder myAudioRecorder;
private String outputFile;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
play = (Button)findViewById(R.id.button3);
play.setEnabled(false);
outputFile = Environment.getExternalStorageDirectory().getAbsolutePath() + "/recording.3gp";;
myAudioRecorder = new MediaRecorder();
myAudioRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
myAudioRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
myAudioRecorder.setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB);
myAudioRecorder.setOutputFile(outputFile);
// handles "record" and "stop"
ImageButton roundButton = (ImageButton) findViewById(R.id.fab_button);
roundButton.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event)
{
Vibrator vb = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
if (event.getAction() == MotionEvent.ACTION_DOWN)
{
vb.vibrate(50);
Log.i("Touched", "Recording");
startRecording(); // ** ERROR (MainActivity.java:86)
}
else if (event.getAction() == MotionEvent.ACTION_UP) {
stopRecording();
Log.i("Released", "Stopped");
vb.vibrate(50);
}
return false;
}
});
// play recording
play.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) throws IllegalArgumentException,SecurityException,IllegalStateException {
playRecording();
}
});
}
// start recording voice
public void startRecording()
{
try {
myAudioRecorder.prepare(); // ** ERROR (MainActivity.java:61)
myAudioRecorder.start();
}
catch (IllegalStateException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
Toast.makeText(getApplicationContext(), "Recording started", Toast.LENGTH_LONG).show();
}
// stop recording voice
public void stopRecording()
{
myAudioRecorder.stop();
myAudioRecorder.reset();
myAudioRecorder.release();
myAudioRecorder = null;
play.setEnabled(true);
Toast.makeText(getApplicationContext(), "Audio recorded successfully",Toast.LENGTH_LONG).show();
}
// play recorded voice
public void playRecording()
{
MediaPlayer m = new MediaPlayer();
try {
m.setDataSource(outputFile);
}
catch (IOException e) {
e.printStackTrace();
}
try {
m.prepare();
}
catch (IOException e) {
e.printStackTrace();
}
m.start();
Toast.makeText(getApplicationContext(), "Playing audio", Toast.LENGTH_LONG).show();
}
}
Any ideas as to what is going on? I've tried some solutions I saw here and a few I came up with on my own but nothing worked. Thank you very much.
EDIT
Here's the rest of the error in the logcat
at android.view.View.dispatchTouchEvent(View.java:8470)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2407)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2049)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2407)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2049)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2407)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2049)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2407)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2049)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2369)
at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1719)
at android.app.Activity.dispatchTouchEvent(Activity.java:2752)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2330)
at android.view.View.dispatchPointerEvent(View.java:8671)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4193)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4059)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3604)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3657)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3623)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3740)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3631)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3797)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3604)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3657)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3623)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3631)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3604)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:5912)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:5851)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:5822)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6002)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:192)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:143)
at android.os.Looper.loop(Looper.java:122)
at android.app.ActivityThread.main(ActivityThread.java:5343)
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:905)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:700)
You are initialising AudioRecorder in oncreate. This means Instance will be created when you open that activity. So better is Initialize AudioRecorder on ClickListener, so when you click on ImageView each and every time new Instance will be created.
You should initialize AudioRecorder before calling startRecording() inside onTouch(), otherwise the second time you call it it will be null because your setting it to null after releasing it inside stopRecording();
I use this code to prepare my MediaRecorder for recording video. After this I call the start() method, which doesn't crash, however when I call the stop() method a crash occurs and the RuntimeException stop failed is raised. I also notice that the video file which is saved in the device is broken and is only 32B. I'm assuming I have an error somewhere when setting up the device in the below method. Notice that I am trying to record from the surfaceView live preview which is displayed on screen ( like snapchat) not from the native camera app.
private void initRecorder(Surface surface) throws IOException {
// It is very important to unlock the camera before doing setCamera
// or it will results in a black preview
if(mCamera == null) {
mCamera = Camera.open();
mCamera.unlock();
}
if(mMediaRecorder == null) mMediaRecorder = new MediaRecorder();
mMediaRecorder.setPreviewDisplay(surface);
mMediaRecorder.setCamera(mCamera);
mMediaRecorder.setOnErrorListener(new MediaRecorder.OnErrorListener() {
#Override
public void onError(MediaRecorder mr, int what, int extra) {
Toast.makeText(getApplicationContext(),
Integer.toString(what) + "_____" + Integer.toString(extra), Toast.LENGTH_LONG)
.show(); }
});
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
// mMediaRecorder.setOutputFormat(8);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mMediaRecorder.setVideoEncodingBitRate(512 * 1000);
mMediaRecorder.setVideoFrameRate(30);
mMediaRecorder.setVideoSize(640, 480);
mMediaRecorder.setOutputFile(getVideoFile());
try {
mMediaRecorder.prepare();
} catch (IllegalStateException e) {
// This is thrown if the previous calls are not called with the
// proper order
e.printStackTrace();
}
mInitSuccesful = true;
}