title: Camera2 API running in background service
body: <p>I have used the <code>Camera2</code> API to implement a background video recorder running as a service and recording from the front cam. For this I have created a new <code>SurfaceView</code>, set its size to 1x1 and moved it to the top left corner. My code is shown below. I'm using Android 5.1.</p>
  
  <p>With the Camera API it worked very well but unfortunately the frame rate is only at 20 fps (and when I increase the exposure compensation it drops even more), although with the <code>Open Camera</code> app I have 30 fps also with increased exposure compensation. That is why I want to try <code>Camera2</code> API (hoping to get higher fps). Unfortunately, I'm getting the following error:</p>
  
  <pre><code>MediaRecoder: setOutputFile called in an invalid state(2)
  MediaRecorder: start called in an invalid state: 2
  </code></pre>
  
  <p>Here is my code:</p>
  
  <pre><code>public class RecorderServiceCamera2 extends Service implements SurfaceHolder.Callback {
      private WindowManager windowManager;
      private SurfaceView surfaceView;
      private CameraDevice mCamera;
      private MediaRecorder mediaRecorder = null;
      private CaptureRequest mCaptureRequest;
      private CameraCaptureSession mSession;
  
      @Override
      public void onCreate() {
          // Create new SurfaceView, set its size to 1x1, move it to the top left corner and set this service as a callback
          windowManager = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
  
          surfaceView = new SurfaceView(this);
          WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
                  1, 1,
                  WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
                  WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
                  PixelFormat.TRANSLUCENT
          );
          layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
          windowManager.addView(surfaceView, layoutParams);
          surfaceView.getHolder().addCallback(this);
      }
  
      @Override
      public int onStartCommand(Intent intent, int flags, int startId) {
          Intent notificationIntent = new Intent(this, MainActivity.class);
  
          PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
                  notificationIntent, 0);
  
          Notification notification = new NotificationCompat.Builder(this)
                  //.setSmallIcon(R.mipmap.app_icon)
                  .setContentTitle("Background Video Recorder")
                  .setContentText("")
                  .setContentIntent(pendingIntent).build();
  
          startForeground(MainActivity.NOTIFICATION_ID_RECORDER_SERVICE, notification);
  
          return Service.START_NOT_STICKY;
      }
  
      @Override
      public void surfaceCreated(final SurfaceHolder surfaceHolder) {
          mediaRecorder = new MediaRecorder();
  
          try {
              CameraManager manager = (CameraManager) getSystemService(CAMERA_SERVICE);
              String[] cameras = manager.getCameraIdList();
              CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameras[1]);
              StreamConfigurationMap configs = characteristics.get(
                      CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
              Size[] sizes = configs.getOutputSizes(MediaCodec.class);
  
              final Size sizeHigh = sizes[0];
  
              manager.openCamera(cameras[1], new CameraDevice.StateCallback() {
                  @Override
                  public void onOpened(@NonNull CameraDevice camera) {
                      mCamera = camera;
                      mediaRecorder.setPreviewDisplay(surfaceHolder.getSurface());
                      mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
                      mediaRecorder.setMaxFileSize(0);
                      mediaRecorder.setOrientationHint(0);
  
                      mediaRecorder.setOutputFile("test.mp4");
                      try { mediaRecorder.prepare(); } catch (Exception ignored) {}
                      List&lt;Surface&gt; list = new ArrayList&lt;&gt;();
                      list.add(surfaceHolder.getSurface());
  
                      try {
                          CaptureRequest.Builder captureRequest = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
                          captureRequest.addTarget(surfaceHolder.getSurface());
                          mCaptureRequest = captureRequest.build();
                      } catch (CameraAccessException e) {
                          e.printStackTrace();
                      }
  
                      try {
                          mCamera.createCaptureSession(list, new CameraCaptureSession.StateCallback() {
                              @Override
                              public void onConfigured(@NonNull CameraCaptureSession session) {
                                  mSession = session;
                              }
  
                              @Override
                              public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                                  mSession = session;
                              }
                          }, null);
                      } catch (CameraAccessException e) {
                          e.printStackTrace();
                      }
  
                      mediaRecorder.start();
  
                      try {
                          mSession.setRepeatingRequest(mCaptureRequest,
                                  new CameraCaptureSession.CaptureCallback() {
                                      @Override
                                      public void onCaptureStarted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, long timestamp, long frameNumber) {
                                          super.onCaptureStarted(session, request, timestamp, frameNumber);
                                      }
  
                                      @Override
                                      public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
                                          super.onCaptureCompleted(session, request, result);
                                      }
  
                                      @Override
                                      public void onCaptureFailed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureFailure failure) {
                                      }
                                  }, null);
                      } catch (CameraAccessException e) {
                          e.printStackTrace();
                      }
                  }
  
                  @Override
                  public void onDisconnected(@NonNull CameraDevice camera) {
                  }
  
                  @Override
                  public void onError(@NonNull CameraDevice camera, int error) {
                  }
              }, null);
          } catch (CameraAccessException e) {
              e.printStackTrace();
          }
      }
  
      // Stop recording and remove SurfaceView
      @Override
      public void onDestroy() {
          mediaRecorder.stop();
          mediaRecorder.reset();
          mediaRecorder.release();
          mCamera.close();
          mediaRecorder= null;
  
          windowManager.removeView(surfaceView);
      }
  
      @Override
      public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {}
  
      @Override
      public void surfaceDestroyed(SurfaceHolder surfaceHolder) {}
  
      @Override
      public IBinder onBind(Intent intent) { return null; }
  }
  </code></pre>