Ebad Ali
Ebad Ali

Reputation: 600

Record video in background and also when screen is turned off

I'm trying to create a Background Video Recording android application where a video is recorded in background (When app is not in foreground) and also when the screen is turned off. I've found some applications on the PlayStore that can carry out this function, so I believe this is doable.

PlayStore App

I have tried to implement this using a Service and an Activity. The activity has two buttons and a SurfaceView. When I click Start Recording button the service starts recording the video using the MediaRecorder and application gets in background. When I open the application again from background to stop the video recording and click on Stop Recording button then the app crashes with following logs. I have searched on here and I have found different solutions related to this but I couldn't find any solution that helped me with this.

08-13 22:04:50.085 24729-24729/com.meowme.camerarecorder E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.meowme.camerarecorder, PID: 24729
    java.lang.RuntimeException: Unable to stop service com.meowme.camerarecorder.RecorderService@38a64c2: java.lang.IllegalStateException
        at android.app.ActivityThread.handleStopService(ActivityThread.java:3727)
        at android.app.ActivityThread.-wrap27(Unknown Source:0)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1806)
        at android.os.Handler.dispatchMessage(Handler.java:105)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6940)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
     Caused by: java.lang.IllegalStateException
        at android.media.MediaRecorder._stop(Native Method)
        at android.media.MediaRecorder.stop(MediaRecorder.java:1306)
        at com.meowme.camerarecorder.RecorderService.stopRecording(RecorderService.java:164)
        at com.meowme.camerarecorder.RecorderService.onDestroy(RecorderService.java:92)
        at android.app.ActivityThread.handleStopService(ActivityThread.java:3709)
        at android.app.ActivityThread.-wrap27(Unknown Source:0) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1806) 
        at android.os.Handler.dispatchMessage(Handler.java:105) 
        at android.os.Looper.loop(Looper.java:164) 
        at android.app.ActivityThread.main(ActivityThread.java:6940) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

 

CameraRecorder.java

public class CameraRecorder extends Activity implements SurfaceHolder.Callback {

    private static final String TAG = CameraRecorder.class.getSimpleName();

    public static final int RequestPermissionCode = 7;


    public static SurfaceView mSurfaceView;
    public static SurfaceHolder mSurfaceHolder;
    public static Camera mCamera;
    public static boolean mPreviewRunning;

    /**
     * Called when the activity is first created.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (CheckingPermissionIsEnabledOrNot()) {
            initializeMainActivity();
        } else {
            RequestMultiplePermission();
        }


    }

    private void initializeMainActivity() {
        setContentView(R.layout.main);

        mSurfaceView = findViewById(R.id.surfaceView1);
        mSurfaceHolder = mSurfaceView.getHolder();
        mSurfaceHolder.addCallback(this);
        mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        Button btnStart = findViewById(R.id.StartService);
        btnStart.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                Intent intent = new Intent(CameraRecorder.this, RecorderService.class);
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                startService(intent);
                finish();
            }
        });

        Button btnStop = findViewById(R.id.StopService);
        btnStop.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                stopService(new Intent(CameraRecorder.this, RecorderService.class));
            }
        });

    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {

    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    }


    public boolean CheckingPermissionIsEnabledOrNot() {

        int FirstPermissionResult = ContextCompat.checkSelfPermission(getApplicationContext(), CAMERA);
        int SecondPermissionResult = ContextCompat.checkSelfPermission(getApplicationContext(), RECORD_AUDIO);
        int ThirdPermissionResult = ContextCompat.checkSelfPermission(getApplicationContext(), WRITE_EXTERNAL_STORAGE);


        return FirstPermissionResult == PackageManager.PERMISSION_GRANTED &&
                SecondPermissionResult == PackageManager.PERMISSION_GRANTED &&
                ThirdPermissionResult == PackageManager.PERMISSION_GRANTED;
    }


    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {

            case RequestPermissionCode:

                if (grantResults.length > 0) {

                    boolean CameraPermission = grantResults[0] == PackageManager.PERMISSION_GRANTED;
                    boolean RecordAudioPermission = grantResults[1] == PackageManager.PERMISSION_GRANTED;
                    boolean ExternalStoragePermission = grantResults[2] == PackageManager.PERMISSION_GRANTED;

                    if (CameraPermission && RecordAudioPermission && ExternalStoragePermission) {

                        Toast.makeText(CameraRecorder.this, "Permission Granted", Toast.LENGTH_LONG).show();
                        // TODO show activity here..
                        initializeMainActivity();
                    }
                     else {
                        Toast.makeText(CameraRecorder.this, "Permission Denied", Toast.LENGTH_LONG).show();
                        finish();
                    }
                }

                break;
        }
    }

    private void RequestMultiplePermission() {

        // Creating String Array with Permissions.
        ActivityCompat.requestPermissions(CameraRecorder.this, new String[]
                {
                        CAMERA,
                        RECORD_AUDIO,
                        WRITE_EXTERNAL_STORAGE,
                }, RequestPermissionCode);

    }

}

RecorderService.java

public class RecorderService extends Service {

    private static final String TAG = "RecorderService";
    private SurfaceView mSurfaceView;
    private SurfaceHolder mSurfaceHolder;
    private static Camera mServiceCamera;
    private boolean mRecordingStatus;
    private MediaRecorder mMediaRecorder;

    @Override
    public void onCreate() {
        mRecordingStatus = false;
        mServiceCamera = CameraRecorder.mCamera;
        mSurfaceView = CameraRecorder.mSurfaceView;
        mSurfaceHolder = CameraRecorder.mSurfaceHolder;

        super.onCreate();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent, flags, startId);

        if (mRecordingStatus == false)
            startRecording();

        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        stopRecording();
        mRecordingStatus = false;

        super.onDestroy();
    }

    public boolean startRecording() {
        try {
            Toast.makeText(getBaseContext(), "Recording Started", Toast.LENGTH_SHORT).show();

            mServiceCamera = Camera.open();
            Camera.Parameters params = mServiceCamera.getParameters();
            mServiceCamera.setParameters(params);
            Camera.Parameters p = mServiceCamera.getParameters();

            final List<Size> listPreviewSize = p.getSupportedPreviewSizes();
            for (Size size : listPreviewSize) {
                Log.i(TAG, String.format("Supported Preview Size (%d, %d)", size.width, size.height));
            }

            Size previewSize = listPreviewSize.get(0);
            p.setPreviewSize(previewSize.width, previewSize.height);
            mServiceCamera.setParameters(p);

            try {
                mServiceCamera.setPreviewDisplay(mSurfaceHolder);
                mServiceCamera.startPreview();
            } catch (IOException e) {
                Log.e(TAG, e.getMessage());
                e.printStackTrace();
            }

            mServiceCamera.unlock();

            mMediaRecorder = new MediaRecorder();
            mMediaRecorder.setCamera(mServiceCamera);
            mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
            mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
            mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
            mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
            mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
            mMediaRecorder.setOutputFile(Environment.getExternalStorageDirectory().getPath() + "video" + System.currentTimeMillis() + ".mp4");
            mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());

            mMediaRecorder.prepare();
            mMediaRecorder.start();

            mRecordingStatus = true;

            return true;

        } catch (IllegalStateException e) {
            Log.d(TAG, e.getMessage());
            e.printStackTrace();
            return false;

        } catch (IOException e) {
            Log.d(TAG, e.getMessage());
            e.printStackTrace();
            return false;
        }
    }

    public void stopRecording() {
        Toast.makeText(getBaseContext(), "Recording Stopped", Toast.LENGTH_SHORT).show();
        try {
            mServiceCamera.reconnect();

        } catch (IOException e) {
            e.printStackTrace();
        }

        mMediaRecorder.stop();
        mMediaRecorder.reset();

        mServiceCamera.stopPreview();
        mMediaRecorder.release();

        mServiceCamera.release();
        mServiceCamera = null;
    }
}

main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/StartService"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="5dp"
        android:background="#5699e6"
        android:padding="16dp"
        android:text="Start Recording"
        android:textColor="#fff"
        android:textSize="15sp">

    </Button>

    <Button
        android:id="@+id/StopService"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="5dp"
        android:background="#5699e6"
        android:layout_marginBottom="16dp"
        android:padding="16dp"
        android:text="Stop Recording"
        android:textColor="#fff"
        android:textSize="15sp"></Button>

    <SurfaceView
        android:id="@+id/surfaceView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">

    </SurfaceView>

</LinearLayout>

It would be really helpful if anyone can just guide me on how I can solve this issue.

Upvotes: 7

Views: 5837

Answers (2)

Merab
Merab

Reputation: 1

please use this code its work for me

        mMediaRecorder.setOutputFile(
                Environment.getExternalStorageDirectory()+"/"+
                        DateFormat.format("yyyy-MM-dd_kk-mm-ss", new Date().getTime())+
                        ".mp4"
        );

Upvotes: 0

The Science Boy
The Science Boy

Reputation: 359

A quick look at your crash log tells me that most likely, this happens when you close down the service. In "stopRecording()" you call mMediaRecorder.stop() and it looks like it is already stopped, since it throws an IllegalStateException.

Check if the media recorder is running before stopping it.

Upvotes: 0

Related Questions