0

The following code throws a runtime exception when trying to start a camera with deprecated Camera API for android:

E/MediaRecorder: start failed: -19
E/AndroidRuntime: FATAL EXCEPTION: IntentService[RecordIntentService]
    Process: com.example.songtry2, PID: 15956
    java.lang.RuntimeException: start failed.
        at android.media.MediaRecorder._start(Native Method)
        at android.media.MediaRecorder.start(MediaRecorder.java:1348)
        at com.example.songtry2.RecordIntentService.prepareVideoRecorder(RecordIntentService.java:259)
        at com.example.songtry2.RecordIntentService.handleActionRecord(RecordIntentService.java:149)
        at com.example.songtry2.RecordIntentService.onHandleIntent(RecordIntentService.java:119)
        at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:76)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:214)
        at android.os.HandlerThread.run(HandlerThread.java:65)
D/ViewRootImpl@1099d2e[MainActivity]: dispatchDetachedFromWindow
I/Process: Sending signal. PID: 15956 SIG: 9
Disconnected from the target VM, address: 'localhost:8603', transport: 'socket'

I really tried using the new camera2 API, but had no luck with it... The service I am trying to create should open the camera in a service and record video in the background until the camera should be closed.

Manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.songtry2">
    <uses-permission android:name="android.permission.RECORD_AUDIO"></uses-permission>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-feature android:name="android.hardware.camera.front" android:required="false" />
    <uses-feature android:name="android.hardware.camera" android:required="false" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <service
            android:name=".RecordIntentService"
            android:exported="false">
        </service>

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

The code which the MainActivity uses in order to open the camera:

package com.example.songtry2;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import android.Manifest;
import android.app.IntentService;
import android.app.Service;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {

            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                    0);
        } else {
            Toast.makeText(this, "wow storage", Toast.LENGTH_SHORT).show();
            Log.d("camera","camera");
        }
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {

            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO},
                    0);
        } else {
            Toast.makeText(this, "Camera on! Cool!!!", Toast.LENGTH_SHORT).show();
            Log.d("camera","camera");
        }
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {

            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA},
                    0);
        }
        RecordIntentService.startActionRecord(this);

    }
}

'getCameraInstance' function used in order to search for a front-facing camera and open it for use:

    public static Camera getCameraInstance(){
        int cameraCount = 0;
        Camera cam = null;
        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
        cameraCount = Camera.getNumberOfCameras();
        for (int camIdx = 0; camIdx < cameraCount; camIdx++) {
            Camera.getCameraInfo(camIdx, cameraInfo);
            if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                try {
                    cam = Camera.open(camIdx);
                } catch (RuntimeException e) {
                    Log.e(TAG, "Camera failed to open: " + e.getLocalizedMessage());
                }
            }
        }

        return cam;
    }

The function which uses the camera in the Recording Service code:

    private boolean prepareVideoRecorder(){
        mCamera = getCameraInstance();
        recorder = new MediaRecorder();
        recorder.reset();
        //recorder.setCamera(Camera.Face);

        // Step 1: Unlock and set camera to MediaRecorder
        mCamera.unlock();
        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));
        CamcorderProfile profile = CamcorderProfile.get(Camera.CameraInfo.CAMERA_FACING_FRONT,CamcorderProfile.QUALITY_LOW);
        recorder.setProfile(profile);
        // Step 4: Set output file
        recorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString());

        // Step 6: Prepare configured MediaRecorder
        try {
            recorder.prepare();
            recorder.start();
        } catch (IllegalStateException e) {
            Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage());
            System.out.println("ERROR" + e.getMessage());
            releaseMediaRecorder();
            return false;
        } catch (IOException e) {
            Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage());
            releaseMediaRecorder();
            return false;
        }
        return true;
    }
    private void releaseCamera(){
        if (mCamera != null){
            mCamera.release();        // release the camera for other applications
            mCamera = null;
        }
    }
Roy Levy
  • 640
  • 1
  • 11
  • 24
  • "The following code throws a runtime exception" -- I recommend that you edit your question and provide the complete stack trace. Otherwise, we have to guess. One guess is that your runtime permission logic is incorrect, as you call `requestPermissions()` but proceed to try to use the camera before you get permission. – CommonsWare Jan 26 '20 at 18:06
  • I also recommend that you use `Log.e()` instead of `System.out.println()`, and include the exception in the `e()` call (e.g., `Log.e("MyApp", "Exception preparing MediaRecorder", e);`). As it stands, you do not have the complete stack trace, which will hamper your debugging efforts. – CommonsWare Jan 26 '20 at 18:08
  • Thanks, added the error message that i'm receiving, and switched to using logger. – Roy Levy Jan 26 '20 at 21:42
  • OK, that didn't help much :-( Some additional notes from a quick scan of your code: 1. You cannot use cameras from the background on modern versions of Android, and your use of a service suggest that is what you are aiming to do. 2. An `IntentService` is designed to run for a few seconds and is not suitable for something long-running like recording a video. 3. As I noted in my earlier comment, you need to wait on recording until you have permission from the user. – CommonsWare Jan 26 '20 at 21:47
  • Please add your `getCameraInstance()` implementation. Also, see [here](https://stackoverflow.com/questions/10496969/android-mediarecorder-start-failed-19). – greeble31 Jan 27 '20 at 00:11
  • @CommonsWare 1. This is exactly what i'm trying to achieve. I need the user to be able to play a game as Activity and capture a video the whole time in the background. Is there any other way to do it? 2. So you suggest Service instead of IntentService, but this also could not run as a background service, right? – Roy Levy Jan 28 '20 at 13:32
  • 1
    @RoyLevy: "Is there any other way to do it?" -- foreground service, perhaps. "So you suggest Service instead of IntentService" -- yes, as then you control the lifetime. "but this also could not run as a background service, right? " -- correct. You can see if running it as a foreground service helps. – CommonsWare Jan 28 '20 at 13:41
  • We have an issue of confusing terminology -- the two meanings of "foreground/background". On Oreo+, you can't access the camera if your app is off-screen _unless_ you have a foreground service. If you have an `Activity` (your game) in the foreground, then you don't have to worry about that. – greeble31 Jan 28 '20 at 14:30
  • @greeble31 Yes, so what i need is the MainActivity to run games/videos and the service to (without showing!) record the player from the front camera. So from what i understood i need a foreground service for camera recording in the MainActivity. – Roy Levy Jan 28 '20 at 17:38
  • No -- that's the opposite of what I'm saying. You only need the foreground service if the app's gonna be offscreen during recording. I cannot see any problems with your code, by the way. If you'd care to mention what device/API level this is happening on, I may be able to try it for myself, later. – greeble31 Jan 28 '20 at 17:54

0 Answers0