This only happens when a user presses the back button and re-enters the intent. I think the issue is I have a file that starts a MediaRecorder to grab sound, but when the user backs out the MediaRecorder isn't closing or I have a runOnUiThread that might not be closing either when the back button is pressed?
I have the following code which I thought would work:
#Override
public void onBackPressed() {
try {
stop();
} catch (IOException e) {
e.printStackTrace();
}
}
public void stop() throws IOException {
if (mRecorder != null) {
mRecorder.stop();
mRecorder.release();
mRecorder = null;
}
}
The whole class this is in I have in a runOnUiThread block, in
private class CustomSense extends TimerTask {
private String amps;
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
amps = String.valueOf(sounder.getAmplitude());
soundDisplay.setText(amps);
}
});
}
public String getAmps() {
return amps;
}
}
But maybe I don't quite understand how onBack works or runOnUiThread? I've been going over the documentation for both of those and MediaRecorder so I could easily be missing something in there (note this does not occur when going into another intent and back through, only when pressing the back button and re-starting the intent)
I feel like the issue is I'm not closing either when the back button is pressed and it's trying to run two instances of them causing the IllegalStateException, but I can't figure out how to actually close them when a user presses their phone's back button.
The StackTrace is as follows:
FATAL EXCEPTION: main
Process: PID: 28671
java.lang.RuntimeException: Unable to start activity ComponentInfo{SensorDisplayActivity}: java.lang.IllegalStateException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2671)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2736)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1478)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6154)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)
Caused by: java.lang.IllegalStateException
at android.media.MediaRecorder.start(Native Method)
at SoundDetect.start(SoundDetect.java:62)
at SoundDetect.<init>(SoundDetect.java:82)
at SensorDisplayActivity.onCreate(SensorDisplayActivity.java:89)
at android.app.Activity.performCreate(Activity.java:6683)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1140)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2624)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2736)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1478)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6154)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)
SoundDetect: 62 is mRecorder.start() in
public void start() throws IOException {
mFileName = Environment.getExternalStorageDirectory().getAbsolutePath();
mFileName += "/null.3gp";
if (mRecorder == null) {
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mRecorder.setOutputFile(mFileName);
mRecorder.prepare();
mRecorder.start();
}
}
SoundDetect 82 is just a .start() call
Related
if minimize app while recording video - everything all right, but once I deploy the application, ерут getting this error:
E/AndroidRuntime: FATAL EXCEPTION: CameraX-video encoding thread
Process: <pkgname>, PID: 12340
java.lang.IllegalStateException
at android.media.MediaCodec.native_dequeueOutputBuffer(Native Method)
at android.media.MediaCodec.dequeueOutputBuffer(MediaCodec.java:2698)
at androidx.camera.core.VideoCapture.videoEncode(VideoCapture.java:604)
at androidx.camera.core.VideoCapture$2.run(VideoCapture.java:348)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:214)
at android.os.HandlerThread.run(HandlerThread.java:65)
Or
if I stopped recording on onPause videoCapture?.stopRecording(), then getting this error:
E/AndroidRuntime: FATAL EXCEPTION: CameraX-
Process: <pkgname>, PID: 9489
java.lang.IllegalStateException
at androidx.core.util.Preconditions.checkState(Preconditions.java:96)
at androidx.core.util.Preconditions.checkState(Preconditions.java:108)
at androidx.camera.camera2.impl.Camera.openCaptureSession(Camera.java:874)
at androidx.camera.camera2.impl.Camera.onUseCaseReset(Camera.java:625)
at androidx.camera.camera2.impl.Camera$11.run(Camera.java:611)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:214)
at android.os.HandlerThread.run(HandlerThread.java:65)
How right stop record video while minimize app???
here's my code:
I collect configurations:
CameraX.unbindAll()
getDisplayMetrics()
setPreviewConfig()
when (typeCapture) {
TYPE_IMAGE -> {
setImageCapture()
CameraX.bindToLifecycle(this, preview, imageCapture)
}
TYPE_VIDEO -> {
setVideoCapture()
CameraX.bindToLifecycle(this, preview, videoCapture)
}
}
set videoConfig and videoCapture:
val videoCaptureConfig = VideoCaptureConfig.Builder().apply {
setLensFacing(lensFacing)
setTargetAspectRatioCustom(screenAspectRatio)
setTargetRotation(rotation)
}.build()
videoCapture = VideoCapture(videoCaptureConfig)
then I start recording video:
videoCapture?.startRecording(videoFile,
CameraXExecutors.mainThreadExecutor(), recordListener)
on onPause() the errors I get are described above
Thanks
I had the same error when stoping the video on onPause. To solve it I added a delay before to call super.onPause() ( see : android: camera onPause/onResume issue).
Declare videoSavedListener
private VideoCapture.OnVideoSavedListener videoSavedListener= new VideoCapture.OnVideoSavedListener() {
#Override
public void onVideoSaved(#NonNull File file) {
if(isRecording) {
isRecording = false;
// Do whatever you want
}
}
#Override
public void onError(#NonNull VideoCapture.VideoCaptureError videoCaptureError, #NonNull String message, #Nullable Throwable cause) {
}
};
Add onClickListener
button.setOnClickListener(v -> {
if(!isRecording){
videoCapture.startRecording(videoFile, CameraXExecutors.mainThreadExecutor(), videoSavedListener);
isRecording = true;
}else{
videoCapture.stopRecording();
}
});
Override onPause()
#SuppressLint("RestrictedApi")
#Override
public void onPause() {
if(isRecording){
isRecording = false;
videoCapture.stopRecording();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
super.onPause();
}else
super.onPause();
}
Please note that video recording use case is currently marked as
hidden in the API and is in a very preliminary state and subject to
change.
EDIT: With some devices the app still crash when calling onPause() with the videoCapture use case set. I added CameraX.unbindAll() to remove all the use cases before calling super.onPause(). Then, in the onResume() method I bind them again.
Declare a boolean variable
public class MyClass{
private boolean isSafe;
private boolean isPending
onPause{
isSafe=false;
}
onPostResume{
isSafe=true;
if(isPending)
methodForDoingUrAction();
}
methodForDoingUrAction(){
if(isSAfe){
//do your process
isPending=false;
}
else
isPending=true;
}
}
I'm trying to pause and resume VideoView with MediaPlayer in activity onPause() and onResume() methods, but in onResume() method MediaPlayer throws java.lang.IllegalStateException. I didn't release MediaPlayer but I think MediaPlayer automatically released after activity paused.
How should I handle it?
private MediaPlayer mediaPlayer;
void prepareVideo() {
videoView = new VideoView(context.getApplicationContext());
String path = "android.resource://" + getPackageName() + "/" +
R.raw.my_video;
videoView.setVideoPath(path);
}
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mediaPlayer = mp;
mediaPlayer.start();
}
});
#Override
protected void onResume() {
super.onResume();
if (mediaPlayer != null) {
mediaPlayer.start();
}
}
#Override
protected void onPause() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
super.onPause();
}
The exception:
Caused by: java.lang.IllegalStateException
at android.media.MediaPlayer._start(Native Method)
at android.media.MediaPlayer.start(MediaPlayer.java:1194)
at co.myapp.app.reborn.myappTestActivity.onResume(myappTestActivity.java:370)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1259)
at android.app.Activity.performResume(Activity.java:6347)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3110)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3152)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1400)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5530)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:734)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:624)
Take a look at the mediaplayer state diagram on android documentation
MediaPlayer state diagram
According to the diagram you have to call setDataSource() and prepare() before calling start().
Probably something wrong happened before. Your logcat should point you in the right direction.
My guess is that your mediaplayer is not in paused state but in stopped state. So you have to call prepare and then start, not just start.
Unfortunately in this way your playback will restart from scratch.
You can use seek command for resuming a position saved during the activity pausing.
We just need to implement MediaPlayer.OnSeekCompleteListener interface and set MediaPlayer in onSeekComplete method.
private MediaPlayer mediaPlayer;
#Override
public void onSeekComplete(final MediaPlayer mp) {
mediaPlayer = mp;
}
I was facing this issue yesterday and I'd like to share my experience facing this issue, the root cause and the fix in my particular issue; this might be helpful for someone else.
This is what I found in my particular issue.
I´m running MediaPlayer in Fragment
When the phone goes to sleep (black screen), in the fragment-life-cycle the stop() function is call.
MediaPlayer recommends to release() MediaPlayer resources on STOP state.
When the phone resumes, it complains with illegal-state-exception because there are no MediaPlayer resource available, remember it was released in the STOPE state.
So, to fix it. I overrided start() state and I got another instance of MediaPlayer if it was null at that specific point in time. START state is called at resume time.
sample code
public class xMediaPlayer extends MediaPlayer
{
private static xMediaPlayer instance = null;
public static xMediaPlayer getInstance( )
{
if( instance == null )
instance = new xMediaPlayer( );
return instance;
}
}
Override start() on fragment
#Override
public void onStart() {
super.onStart();
mMediaPlayer = xMediaPlayer.getInstance( );
}
I am developing a game on Android, I have a background music that I would like to stop using a switch that is in an activity other than the one where I launch the music, that of the parameters. The music is in the main menu.
Here is my class for the music:
public class BackgroundMusic {
private MediaPlayer player;
public Menu context;
public BackgroundMusic(Menu pContext) {
context = pContext;
player = MediaPlayer.create(context.getApplicationContext(), R.raw.opening);
player.setLooping(true);
player.setVolume(1.0f, 1.0f);
}
public void start() {
player.start();
}
public void stop(){
player.pause();
}
}
And here is the code I use for the switch:
buttonmusique = (Switch) findViewById(R.id.switch3);
buttonmusique.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Log.e("bouton",String.valueOf(buttonmusique.isChecked()));
// If the music is playing
if (isChecked) {
media.start();
buttonmusique.setText("Musique On"); //To change the text near to switch
Log.d("You are :", "Checked");
} else {
media.stop();
// Resume the music player
buttonmusique.setText("Musique OFF"); //To change the text near to switch
Log.d("You are :", " Not Checked");
}
}
});
The problem is that, if I press the switch, it sends me back to the main menu (on some phones the application crashed).
This is the logcat :
E/bouton: false
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
Process: pts3.botanicagofinal, PID: 14271
java.lang.NullPointerException: Attempt to invoke virtual method 'void pts3.botanicagofinal.BackgroundMusic.stop()' on a null object reference
at pts3.botanicagofinal.Parametres$3.onCheckedChanged(Parametres.java:61)
at android.widget.CompoundButton.setChecked(CompoundButton.java:156)
at android.widget.Switch.setChecked(Switch.java:1071)
at android.widget.Switch.toggle(Switch.java:1066)
at android.widget.CompoundButton.performClick(CompoundButton.java:120)
at android.view.View$PerformClick.run(View.java:22314)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:241)
at android.app.ActivityThread.main(ActivityThread.java:6223)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
Application terminated.
I want to know if it is possible to do otherwise for it to work or if I have an error in my code?
Thank you in advance for your feedback.
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.
I have been trying camera2 API. I have downloaded code from
https://developer.android.com/samples/Camera2Video/index.html to learn about how it works. It works fine till I stop recording. When I stop recording it runs following code.
private void stopRecordingVideo() {
// UI
mIsRecordingVideo = false;
mBtn_Video.setText(R.string.record);
// Stop recording
try {
mMediaRecorder.stop();
mMediaRecorder.reset();
}
catch (Exception e) {
e.printStackTrace();
}
Activity activity = getActivity();
if (null != activity) {
System.out.println("file " + getVideoFile(activity));
Toast.makeText(activity, "Video saved: " + getVideoFile(activity),
Toast.LENGTH_SHORT).show();
}
startPreview();
at mMediaRecorder.stop(); it throw following error
01-12 16:24:23.115 2161-2200/com.cameratwoapi E/Surface﹕ queueBuffer: error queuing buffer to SurfaceTexture, -19
01-12 16:24:23.135 2161-2200/com.cameratwoapi E/EGL_emulation﹕ tid 2200: swapBuffers(285): error 0x3003 (EGL_BAD_ALLOC)
01-12 16:24:23.197 2161-2200/com.cameratwoapi E/CameraDeviceGLThread-0﹕ Received exception on GL render thread:
java.lang.IllegalStateException: swapBuffers: EGL error: 0x3003
at android.hardware.camera2.legacy.SurfaceTextureRenderer.checkEglError(SurfaceTextureRenderer.java:487)
at android.hardware.camera2.legacy.SurfaceTextureRenderer.swapBuffers(SurfaceTextureRenderer.java:480)
at android.hardware.camera2.legacy.SurfaceTextureRenderer.drawIntoSurfaces(SurfaceTextureRenderer.java:681)
at android.hardware.camera2.legacy.GLThreadManager$1.handleMessage(GLThreadManager.java:103)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:135)
at android.os.HandlerThread.run(HandlerThread.java:61)
Any Idea what I am doing wrong. I spent few hours but couldn't find any solution.
Edit - I am using geneymotion emulator. The path I am using
file /storage/emulated/0/Android/data/com.gold.cameratwoapi/files/video.mp4
Thanks
My solution is to change void stopRecordingVideo() as following:
private void stopRecordingVideo() {
// UI
mIsRecordingVideo = false;
mButtonVideo.setText(R.string.record);
// Added by Ben Ning, to resolve exception issue when stop recording.
try {
mPreviewSession.stopRepeating();
mPreviewSession.abortCaptures();
} catch (CameraAccessException e) {
e.printStackTrace();
}
// Stop recording
mMediaRecorder.stop();
mMediaRecorder.reset();
}
Key is:
try {
mPreviewSession.stopRepeating();
mPreviewSession.abortCaptures();
} catch (CameraAccessException e) {
e.printStackTrace();
}
private void stopRecordingVideo() {
// UI
mIsRecordingVideo = false;
mButtonVideo.setText(R.string.record);
// Added by Ben Ning, to resolve exception issue when stop recording.
try {
mPreviewSession.stopRepeating();
mPreviewSession.abortCaptures();
} catch (CameraAccessException e) {
e.printStackTrace();
}
// Stop recording
mMediaRecorder.stop();
mMediaRecorder.reset();
Activity activity = getActivity();
if (null != activity) {
Toast.makeText(activity, "Video saved: " + getVideoFile(activity),
Toast.LENGTH_SHORT).show();
}
startPreview();
}
this is working for me.
After calling mMediaRecorder.stop() an IllegalStateException is always thrown. I've noticed that on devices with INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY the CameraDevice changes status to error, immediately calling onError() in the CameraDevice.StateCallback.
In the sample you referenced, onError() closes the camera and finishes the activity, so just change onError() to re-open the camera, like this:
#Override
public void onError(CameraDevice cameraDevice, int error) {
// mCameraOpenCloseLock.release();
// cameraDevice.close();
// mCameraDevice = null;
// Activity activity = getActivity();
// if (null != activity) {
// activity.finish();
// }
closeCamera();
openCamera(mTextureView.getWidth(), mTextureView.getHeight());
}
It'd also be a good idea to put some check in there to make sure that if an error really did happen, that the commented out code gets called instead of entering a loop of trying to open the camera over and over.
Tested on a Moto G 2nd gen, with Android 5.0.2
It depends on what you are doing with the CameraCaptureSession and the MediaRecorder but when you call mMediaRecorder.stop() I think it is destroying the surface used for the camera preview session which causes this error because the documentation says
Once recording is stopped, you will have to configure it again as if it has just been constructed
Therefore if you call PreviewSession.abortCaptures() (mPreviewSession.stopRepeating(); isn't necessary from what I gather) it stops the camera sending output to the recorder surface which will allow you to stop the MediaRecorder without issue.
PreviewSession.abortCaptures(); doesn't instantly stop the camera preview output so you might find you need to call MediaRecorder.stop() in the onClosed() or onReady() method of the CameraCaptureSession.StateCallback
In my case, I use TimerTask and a Handler. There is error direct to the mMediaRecorder.stop(). So I use this method
final Handler mTimerHandler = new Handler(Looper.getMainLooper());
mIsRecordingVideo = false;
// Stop recording
try {
mPreviewSession.stopRepeating();
mPreviewSession.abortCaptures();
} catch (CameraAccessException e) {
e.printStackTrace();
}
try{
Timer timer = new Timer();
TimerTask timerTask = new TimerTask() {
#Override
public void run() {
mTimerHandler.post(new Runnable() {
#Override
public void run() {
mMediaRecorder.stop();
mMediaRecorder.reset();
}
});
}
};
timer.schedule(timerTask,30);
}catch(RuntimeException e){
Log.e("----------------","---->>>>>>>>>"+e);
e.printStackTrace();
}