@Override
        public void run() {
          int cameraFramesCount = cameraStatistics.getAndResetFrameCount();
          int cameraFps =
              (cameraFramesCount * 1000 + CAMERA_OBSERVER_PERIOD_MS / 2)
                  / CAMERA_OBSERVER_PERIOD_MS;

          Logging.d(
              TAG,
              "Camera fps: "
                  + cameraFps
                  + ". Pending buffers: "
                  + cameraStatistics.pendingFramesTimeStamps());
          if (cameraFramesCount == 0) {
            ++freezePeriodCount;
            if (CAMERA_OBSERVER_PERIOD_MS * freezePeriodCount > CAMERA_FREEZE_REPORT_TIMOUT_MS
                && eventsHandler != null) {
              Logging.e(TAG, "Camera freezed.");
              if (cameraStatistics.pendingFramesCount() == cameraStatistics.maxPendingFrames) {
                eventsHandler.onCameraError("Camera failure. Client must return video buffers.");
              } else {
                eventsHandler.onCameraError("Camera failure.");
              }
              return;
            }
          } else {
            freezePeriodCount = 0;
          }
          cameraThreadHandler.postDelayed(this, CAMERA_OBSERVER_PERIOD_MS);
        }
 @Override
 public void onError(int error, Camera camera) {
   String errorMessage;
   if (error == android.hardware.Camera.CAMERA_ERROR_SERVER_DIED) {
     errorMessage = "Camera server died!";
   } else {
     errorMessage = "Camera error: " + error;
   }
   Logging.e(TAG, errorMessage);
   if (eventsHandler != null) {
     eventsHandler.onCameraError(errorMessage);
   }
 }
  private void startCaptureOnCameraThread(
      final int width,
      final int height,
      final int framerate,
      final CapturerObserver frameObserver,
      final Context applicationContext) {
    Throwable error = null;
    checkIsOnCameraThread();
    if (camera != null) {
      throw new RuntimeException("Camera has already been started.");
    }
    this.applicationContext = applicationContext;
    this.frameObserver = frameObserver;
    this.firstFrameReported = false;

    try {
      try {
        synchronized (cameraIdLock) {
          Logging.d(TAG, "Opening camera " + id);
          if (eventsHandler != null) {
            eventsHandler.onCameraOpening(id);
          }
          camera = Camera.open(id);
          info = new Camera.CameraInfo();
          Camera.getCameraInfo(id, info);
        }
      } catch (RuntimeException e) {
        openCameraAttempts++;
        if (openCameraAttempts < MAX_OPEN_CAMERA_ATTEMPTS) {
          Logging.e(TAG, "Camera.open failed, retrying", e);
          openCameraOnCodecThreadRunner =
              new Runnable() {
                @Override
                public void run() {
                  startCaptureOnCameraThread(
                      width, height, framerate, frameObserver, applicationContext);
                }
              };
          cameraThreadHandler.postDelayed(openCameraOnCodecThreadRunner, OPEN_CAMERA_DELAY_MS);
          return;
        }
        openCameraAttempts = 0;
        throw e;
      }

      try {
        camera.setPreviewTexture(surfaceHelper.getSurfaceTexture());
      } catch (IOException e) {
        Logging.e(TAG, "setPreviewTexture failed", error);
        throw new RuntimeException(e);
      }

      Logging.d(
          TAG,
          "Camera orientation: "
              + info.orientation
              + " .Device orientation: "
              + getDeviceOrientation());
      camera.setErrorCallback(cameraErrorCallback);
      startPreviewOnCameraThread(width, height, framerate);
      frameObserver.onCapturerStarted(true);

      // Start camera observer.
      cameraThreadHandler.postDelayed(cameraObserver, CAMERA_OBSERVER_PERIOD_MS);
      return;
    } catch (RuntimeException e) {
      error = e;
    }
    Logging.e(TAG, "startCapture failed", error);
    stopCaptureOnCameraThread();
    frameObserver.onCapturerStarted(false);
    if (eventsHandler != null) {
      eventsHandler.onCameraError("Camera can not be started.");
    }
    return;
  }