IllegalStateException when reusing MediaRecorder instance - android

Hey I'm trying to make MediaRecorder record the contents of my screen. It works when I'm making a recording for a first time but when I try to record the screen for a second time it fails. Here is relevant code:
void startRecording(String directory,String filename,MediaProjection mediaProjection) {
this.mediaProjection=mediaProjection;
this.directory=directory;
this.filename=filename;
initRecorder();
prepareRecorder();
virtualDisplay = createVirtualDisplay();
mediaRecorder.start();
}
void stopRecording() {
mediaRecorder.stop();
mediaRecorder.reset();
if (virtualDisplay != null) {
virtualDisplay.release();
}
if (mediaProjection != null) {
mediaProjection.stop();
mediaProjection = null;
}
initRecorder();
prepareRecorder();
}
void setScreen(int screenWidth, int screenHeight, int screenDensity) {
this.screenWidth = screenWidth;
this.screenHeight = screenHeight;
this.screenDensity = screenDensity;
}
void prepareRecorder() {
try {
mediaRecorder.prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
void initRecorder() {
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mediaRecorder.setVideoEncodingBitRate(512 * 1000);
mediaRecorder.setVideoFrameRate(30);
mediaRecorder.setVideoSize(screenWidth, screenHeight);
mediaRecorder.setOutputFile(directory + "/" + filename + ".mp4");
//mediaRecorder.setOutputFile(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES).getAbsolutePath()+"/vitalij.mp4");
}
So in my activity I create a new instance of this class once then after pressing the button the startRecording method get's invoked. Then user can press stop recording which calls stopRecording method. When app is destroyed i release the mediaRecorder object.
This is the error I get:
Caused by: java.lang.IllegalStateException
at android.media.MediaRecorder.setAudioSource(Native Method)
at com.example.xxx.myapplication.VideoRecorder.initRecorder(VideoRecorder.java:77)
at com.example.xxx.myapplication.VideoRecorder.startRecording(VideoRecorder.java:30)
at com.example.xxx.myapplication.MainActivity.onActivityResult(MainActivity.java:134)
I'm sure that I have the correct permissions set and the first video gets created fine. The problem only occurs when making the recording for a second time.

The issue is that you're executing these two lines of code:
initRecorder();
prepareRecorder();
at the end of your stopRecording() function and again in your startRecording() function.
When you try to call mediaRecorder.setAudioSource in initRecorder() after the audio source has already been set, you get an IllegalStateException because it's in the incorrect state.
If you look at the state diagram on the Android MediaRecorder reference page, you'll see that a MediaRecorder must be in the Initial state to call setAudioSource(), but yours is in the Prepared state after stopRecording() has been called and you try to call setAudioSource() again.

Related

Unable to start mediarecorder for front camera, it throws illegalStateException start failed: -38

What is the meaning of start failed: -38?
I created two CameraView(Preview) Objects and one Camera Object.
Using Handlers I am able to switch the camera for some times, say, 10 secs open back camera and 10 secs open front camera.
Now I am facing some issue in recording front camera.
When I click the record button, first it will record back camera for 10 secs, and save it into sd card. and after 10 secs automatically it switches to front camera to record.
Back camera recording is working fine. But front camera preview is showing correctly, but it is not recording video, it says IllegalStateException start failed: -38 when I call mediarecorder.start();
here is the code
Prepare Media
mediaRecorder = new MediaRecorder();
mCamera.unlock(); // lock camera for later use
mediaRecorder.setCamera(mCamera); // lock camera for later use
//mediaRecorder.setCamera(mCamera); // lock camera for later use
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
//mediaRecorder.setOrientationHint(90);
mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_720P));
//mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_LOW));
//mediaRecorder.setVideoSize(320, 240);
//mediaRecorder.setVideoFrameRate(15);
//mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
//mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
long l = System.currentTimeMillis();
mediaRecorder.setOutputFile("/sdcard/" + l + ".mp4");
mediaRecorder.setMaxDuration(600000); // Set max duration 60 sec.
mediaRecorder.setMaxFileSize(50000000); // Set max file size 50M
try {
mediaRecorder.prepare();
Log.e(TAG, "prepareMediaRecorder: ");
} catch (IllegalStateException e) {
releaseMediaRecorder();
return false;
} catch (IOException e) {
releaseMediaRecorder();
return false;
}
Log.e(TAG, "prepareMediaRecorder: RETURN TRUE");
Start Record
if (!prepareMediaRecorder()) {
Toast.makeText(getContext(), "Fail in prepareMediaRecorder()!\n - Ended -", Toast.LENGTH_LONG).show();
//finish();
return;
}
try {
Log.e(TAG, "recordBackCameraVideo: START START ");
mediaRecorder.start();
Log.e(TAG, "recordBackCameraVideo: START END ");
} catch (final Exception ex) {
Log.i("---", "Exception in thread");
}
recording = true;
Stop Recording
try {
Log.e(TAG, "stopRecording: STOP START");
mediaRecorder.stop(); // stop the recording
Log.e(TAG, "stopRecording: STOP END");
} catch (RuntimeException stopException) {
Log.e(TAG, "stopRecording: " + stopException.getMessage());
}
releaseMediaRecorder(); // release the MediaRecorder object
Toast.makeText(getContext(), "Video captured!", Toast.LENGTH_LONG).show();
recording = false;
Try this one. First you need to check CamcorderProfile.hasProfile("CameraID", "Pass your desired quality") If it is true then you can use that quality for video recording otherwise you need to use some other CamcorderProfile quality.
Below code is just for the reference which I used in my project you can change the code according to your need.
private boolean prepareMediaRecorder() {
mediaRecorder = new MediaRecorder();
CamcorderProfile profile = null;
if (!cameraFront) {
profile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
} else {
if (CamcorderProfile.hasProfile(0, CamcorderProfile.QUALITY_HIGH)) {
profile = CamcorderProfile.get(0, CamcorderProfile.QUALITY_HIGH);
} else {
profile = CamcorderProfile.get(0, CamcorderProfile.QUALITY_LOW);
}
}
mCamera.unlock();
if (!cameraFront) {
// Back
mediaRecorder.setOrientationHint(90);
} else {
// Front
mediaRecorder.setOrientationHint(270);
}
mediaRecorder.setCamera(mCamera);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mediaRecorder.setOutputFormat(profile.fileFormat);
mediaRecorder.setVideoEncoder(profile.videoCodec);
mediaRecorder.setVideoEncodingBitRate(profile.videoBitRate);
mediaRecorder.setVideoFrameRate(profile.videoFrameRate);
mediaRecorder.setOutputFile(Utils.getOriginalFileName());
mediaRecorder.setVideoSize(640, 480);
mediaRecorder.setMaxDuration(50000); // Set max duration 5 sec.
mediaRecorder.setMaxFileSize(50000000); // Set max file size 50M
try {
mediaRecorder.prepare();
} catch (IllegalStateException e) {
releaseMediaRecorder();
return false;
} catch (IOException e) {
releaseMediaRecorder();
return false;
}
return true;
}

Is it necessary to call Camera.stopPreview() before MediaRecorder.start()?

I am having a basic Camera application using MediaRecorder. Application previews the video on TextureView and when button is clicked it starts recording. I works on most mobile phones, but on some specific device, underlying OMX fails:
(40b1df38) hardware/ti/omap4xxx/camera/OMXCameraAdapter/OMXCameraAdapter.cpp:2176 UseBuffersPreview - Exiting function UseBuffersPreview because of ret 0 eError=80001018
and in consequence, preview freezes and recording fails.
I found that this is most likely caused when Camera object is still previewing, while MediaRecorder object start recording. When I call mCamera.stopPreview() before starting recording, it works. Therefore, I have following questions:
1. Why is call to mCamera.stopPreview() necessary on some devices, and not on others?
2. How can the recorded video be still previewed, if stopPreview() on Camera object is called, but MediaRecorder.setPreviewDisplay() was not?
Below I present some code:
public boolean startRecording() throws IllegalStateException, IOException {
if (!mRecordingStarted) {
mMediaRecorder = new MediaRecorder();
try {
mCamera.stopPreview(); // !!! without this recording fails on some devices!
mCamera.unlock();
mMediaRecorder.setCamera(mCamera);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT); mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mMediaRecorder.setProfile(mCamProfile);
//mMediaRecorder.setPreviewDisplay(mSurfaceView.getHolder().getSurface());
mMediaRecorder.setOutputFile(mCaptureFile);
mMediaRecorder.prepare();
mMediaRecorder.start();
mRecordingStarted = true;
} catch (Exception e) {
mMediaRecorder.release();
mCamera.lock();
Log.e("ERROR", e.toString());
}
}
return mRecordingStarted;
}
private void startPreview() throws IllegalStateException, IOException {
if (mCamera == null) {
return;
}
try {
mCamera.stopPreview();
} catch (Exception e) {
}
Camera.Parameters parameters = mCamera.getParameters();
mCamera.setDisplayOrientation(0);
mCamProfile = getConfiguredProfile();
mVideoSize = getBestPreviewSize(mCamProfile, parameters);
parameters.setPreviewSize(mVideoSize.width, mVideoSize.height);
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY);
mCamera.setParameters(parameters);
mCamera.setPreviewTexture(mPreview.getSurfaceTexture());
mCamera.startPreview();
}

IllegalStateException when MediaRecorder is recording: how to fix

I got this issue and cant get my head around it, im recording calls directly from the speaker, so when i get TelephonyManager.CALL_STATE_OFFHOOK I instantly start recording audio from VOICE_CALL. thats part its ok, start recording but if the call is ended and start a new one, I get a java.lang.IllegalStateException
I think this is because the first call it's still being recorded... I've tried to do:
mRecorder.stop();
mRecorder.release();
mRecorder.reset();
but no luck, they all gave me a illegalStateException, I just want to know how to stop first call recording and record a new one without errors.
Here's my code for recording and call handling,
//At least one call exists that is dialing, active, or on hold, and no calls are ringing or waiting.
if (state == TelephonyManager.CALL_STATE_OFFHOOK){
if (record_calls == 1){
record_enviroment();
}
}
//when Idle = No activity.
if (state == TelephonyManager.CALL_STATE_IDLE){
//Check for audio recorded and if exists post audio to server
}
public void record_enviroment(){
path = context.getFilesDir().getAbsolutePath() + "/";
try {
//Random number for file name
Random r = new Random( System.currentTimeMillis() );
i = 10000 + r.nextInt(20000);
// Save file local to app
mFileName = path + i + "_call_" + id_asociado + ".3gp";
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.VOICE_CALL);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.setOutputFile(mFileName);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
try {
mRecorder.prepare();
} catch (IOException e) {
Log.e("AUDIO_RECORDER", "prepare() failed");
}
mRecorder.start();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

Media Recorder stop() is never called

I am recording an audio file on my broadcast but I am not getting any error but my recorder.stop() is never called heres my code:
String file_name= "recording";
audiofile = File.createTempFile(file_name, ".3gp", sampleDir);
String path=Environment.getExternalStorageDirectory().getAbsolutePath();
//recorder = null;
int audioSource = MediaRecorder.AudioSource.VOICE_CALL;
recorder.setAudioSource(audioSource);
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
recorder.setOutputFile(audiofile.getAbsolutePath());
recorder.prepare();
recorder.start();
and my stop function contains:
public void stopRecord()throws IOException{
if(recorder!=null)
{
recorder.stop();
recorder.release();
recorder.reset();
Log.d(TAG, "recording stopped");
}
else
{
Log.d(TAG, "recording stopped error");
}
i am calling start recorder at offhook stage and stop recorder at idle ,but it goes to idle state and stop is not called at all .
case TelephonyManager.CALL_STATE_IDLE:
prev_state=state;
Log.d(TAG, "CALL_STATE_IDLE==>"+incoming_nr);
Log.d(TAG, "recording stopped"); // Executes till here and skips the below part
try {
stopRecord();
Log.d(TAG, "recording stopped");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.d(TAG, "recording stopped");
I have give all the permission required pls help me on this
Thanks in Advance
TelephonyManager.EXTRA_STATE_IDLE is called when there is no activity and this is called before TelephonyManager.EXTRA_STATE_OFFHOOK.
Here you are calling stopRecord() function in the TelephonyManager.EXTRA_STATE_IDLE state and thus you are accessing mRecorder.stop();, but at that point Recorder object is null and not initialized. Checdk this post for more clarification Null Exception when recording using mediaRecorder. Also check out the comments.
As far as no error is concerned, you are calling it in try/catch block. So only stack trace will be generated.

Mediarecorder start failed -19

I am getting this error when running start() for mediarecorder.
06-28 18:46:22.570: E/MediaRecorder(9540): start failed: -19
06-28 18:46:22.570: W/System.err(9540): java.lang.RuntimeException: start failed.
I am extending mediarecorder class
My code:
camera = Camera.open(cameraId);
super.setCamera(camera);
super.setVideoSource(MediaRecorder.VideoSource.CAMERA);
super.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
if (mode==MODE_DEFAULT) {
super.setMaxDuration(1000);
super.setMaxFileSize(Integer.MAX_VALUE);
} else {
// On some phones a RuntimeException might be thrown :/
try {
super.setMaxDuration(0);
super.setMaxFileSize(Integer.MAX_VALUE);
} catch (RuntimeException e) {
Log.e(TAG,"setMaxDuration or setMaxFileSize failed !");
}
}
super.setVideoEncoder(videoEncoder);
if(surfaceHolder!=null)
super.setPreviewDisplay(surfaceHolder.getSurface());
//super.setVideoSize(quality.resX,quality.resY);
super.setVideoFrameRate(quality.frameRate);
super.setVideoEncodingBitRate(quality.bitRate);
I saw these pages
Error opening android camera for streaming video
Android MediaRecorder - "start failed: -19"
But non of them worked for me...
Running on archos 80 g9, android 3.2
Any one got any ideas?
Fixed by removing
super.setVideoFrameRate(quality.frameRate);
I was facing the same proble during video recording and i solved it by adding this for video recording
/**
* Start video recording by cleaning the old camera preview
*/
private void startVideoRecorder() {
// THIS IS NEEDED BECAUSE THE GLASS CURRENTLY THROWS AN ERROR OF
// "MediaRecorder start failed: -19"
// THIS WONT BE NEEDED INCASE OF PHONE AND TABLET
// This causes crash in glass kitkat version so remove it
// try {
// mCamera.setPreviewDisplay(null);
// } catch (java.io.IOException ioe) {
// Log.d(TAG,
// "IOException nullifying preview display: "
// + ioe.getMessage());
// }
// mCamera.stopPreview();
// mCamera.unlock();
recorder = new MediaRecorder();
// Let's initRecorder so we can record again
initRecorder();
}
/**
* Initialize video recorder to record video
*/
private void initRecorder() {
try {
File dir = new File(folderPath);
if (!dir.exists()) {
dir.mkdirs();
}
mCamera.stopPreview();
mCamera.unlock();
videofile = new File(dir, fileName + ".mp4");
recorder.setCamera(mCamera);
// Step 2: Set sources
recorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
// Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
recorder.setProfile(CamcorderProfile
.get(CamcorderProfile.QUALITY_HIGH));
// Step 4: Set output file
recorder.setOutputFile(videofile.getAbsolutePath());
// Step 5: Set the preview output
recorder.setPreviewDisplay(mPreview.getHolder().getSurface());
// Step 6: Prepare configured MediaRecorder
recorder.setMaxDuration(video_duration * 1000);
recorder.setOnInfoListener(new OnInfoListener() {
#Override
public void onInfo(MediaRecorder mr, int what, int extra) {
if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
mCamera.stopPreview();
releaseMediaRecorder();
/*
* initiate media scan and put the new things into the
* path array to make the scanner aware of the location
* and the files you want to see
*/MediaScannerConnection.scanFile(
CuxtomCamActivity.this,
new String[] { videofile.getPath() }, null,
null);
Intent intent = new Intent();
intent.putExtra(CuxtomIntent.FILE_PATH,
videofile.getPath());
intent.putExtra(CuxtomIntent.FILE_TYPE, FILE_TYPE.VIDEO);
setResult(RESULT_OK, intent);
finish();
}
}
});
recorder.prepare();
recorder.start();
} catch (Exception e) {
Log.e("Error Stating CuXtom Camera", e.getMessage());
}
}
private void releaseMediaRecorder() {
if (recorder != null) {
recorder.reset(); // clear recorder configuration
recorder.release(); // release the recorder object
recorder = null;
}
}
To see detail of how a camera is actually implemented refer to Open Source Cuxtom Cam
I found a subtle hint in documentation for the MediaRecorder.start() method that suggest if it fails to lock() the Camera before attempting to re-record. This worked for me. Implies a Camera state bug was fixed post API level 13 - calling Camera.lock() is the known workaround.
This code worked for me (found here)
mCamera.unlock(); // maybe not for your activity flow
//1st. Initial state
mProfile = CamcorderProfile.get( CamcorderProfile.QUALITY_HIGH );
mMediaRecorder = new MediaRecorder();
mMediaRecorder.setCamera( mCamera );
//2nd. Initialized state
mMediaRecorder.setAudioSource( MediaRecorder.AudioSource.CAMCORDER );
mMediaRecorder.setVideoSource( MediaRecorder.VideoSource.CAMERA );
//3rd. config
mMediaRecorder.setOutputFormat( mProfile.fileFormat );
mMediaRecorder.setAudioEncoder( mProfile.audioCodec );
mMediaRecorder.setVideoEncoder( mProfile.videoCodec );
mMediaRecorder.setOutputFile( "/sdcard/FBVideo.3gp" );
mMediaRecorder.setVideoSize( mProfile.videoFrameWidth, mProfile.videoFrameHeight );
mMediaRecorder.setVideoFrameRate( mProfile.videoFrameRate );
mMediaRecorder.setVideoEncodingBitRate( mProfile.videoBitRate );
mMediaRecorder.setAudioEncodingBitRate( mProfile.audioBitRate );
mMediaRecorder.setAudioChannels( mProfile.audioChannels );
mMediaRecorder.setAudioSamplingRate( mProfile.audioSampleRate );
mMediaRecorder.setPreviewDisplay( mHolder.getSurface() );
try {
mMediaRecorder.prepare();
mMediaRecorder.start();
} catch ( IllegalStateException e ) {
e.printStackTrace();
} catch ( IOException e ) {
e.printStackTrace();
}
The problem here is about the camera. Just use camera.unlock() to allow the media process to access the camera.
This must be done before calling MediaRecorder.setCamera(Camera). This cannot be called after recording starts.
Read more here.

Categories

Resources