blob: 3d9516d5a11f14df5fa3d7fa81e0452ac23fe8a6 [file] [log] [blame]
Magnus Jedverta8eab862016-05-20 17:22:12 +02001/*
2 * Copyright 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11package org.webrtc;
12
glaznev37adc5e2017-04-27 13:38:29 -070013import android.media.MediaRecorder;
Sami Kalliomäkie7592d82018-03-22 13:32:44 +010014import javax.annotation.Nullable;
glaznev37adc5e2017-04-27 13:38:29 -070015
Magnus Jedverta8eab862016-05-20 17:22:12 +020016/**
17 * Base interface for camera1 and camera2 implementations. Extends VideoCapturer with a
18 * switchCamera() function. Also provides subinterfaces for handling camera events, and a helper
19 * class for detecting camera freezes.
20 */
21public interface CameraVideoCapturer extends VideoCapturer {
22 /**
23 * Camera events handler - can be used to be notifed about camera events. The callbacks are
24 * executed from an arbitrary thread.
25 */
26 public interface CameraEventsHandler {
27 // Camera error handler - invoked when camera can not be opened
28 // or any camera exception happens on camera thread.
29 void onCameraError(String errorDescription);
30
sakalf156bdd2016-10-06 00:59:10 -070031 // Called when camera is disconnected.
32 void onCameraDisconnected();
33
Magnus Jedverta8eab862016-05-20 17:22:12 +020034 // Invoked when camera stops receiving frames.
35 void onCameraFreezed(String errorDescription);
36
37 // Callback invoked when camera is opening.
sakalbc18fc02016-09-14 05:36:20 -070038 void onCameraOpening(String cameraName);
Magnus Jedverta8eab862016-05-20 17:22:12 +020039
40 // Callback invoked when first camera frame is available after camera is started.
41 void onFirstFrameAvailable();
42
43 // Callback invoked when camera is closed.
44 void onCameraClosed();
45 }
46
47 /**
48 * Camera switch handler - one of these functions are invoked with the result of switchCamera().
49 * The callback may be called on an arbitrary thread.
50 */
51 public interface CameraSwitchHandler {
52 // Invoked on success. |isFrontCamera| is true if the new camera is front facing.
53 void onCameraSwitchDone(boolean isFrontCamera);
54
55 // Invoked on failure, e.g. camera is stopped or only one camera available.
56 void onCameraSwitchError(String errorDescription);
57 }
58
59 /**
60 * Switch camera to the next valid camera id. This can only be called while the camera is running.
61 * This function can be called from any thread.
62 */
63 void switchCamera(CameraSwitchHandler switchEventsHandler);
magjedd5c77ab2017-04-19 08:45:45 -070064
65 /**
glaznev37adc5e2017-04-27 13:38:29 -070066 * MediaRecorder add/remove handler - one of these functions are invoked with the result of
67 * addMediaRecorderToCamera() or removeMediaRecorderFromCamera calls.
68 * The callback may be called on an arbitrary thread.
69 */
70 public interface MediaRecorderHandler {
71 // Invoked on success.
72 void onMediaRecorderSuccess();
73
74 // Invoked on failure, e.g. camera is stopped or any exception happens.
75 void onMediaRecorderError(String errorDescription);
76 }
77
78 /**
79 * Add MediaRecorder to camera pipeline. This can only be called while the camera is running.
80 * Once MediaRecorder is added to camera pipeline camera switch is not allowed.
81 * This function can be called from any thread.
82 */
83 void addMediaRecorderToCamera(MediaRecorder mediaRecorder, MediaRecorderHandler resultHandler);
84
85 /**
86 * Remove MediaRecorder from camera pipeline. This can only be called while the camera is running.
87 * This function can be called from any thread.
88 */
89 void removeMediaRecorderFromCamera(MediaRecorderHandler resultHandler);
90
91 /**
magjedd5c77ab2017-04-19 08:45:45 -070092 * Helper class to log framerate and detect if the camera freezes. It will run periodic callbacks
93 * on the SurfaceTextureHelper thread passed in the ctor, and should only be operated from that
94 * thread.
95 */
96 public static class CameraStatistics {
97 private final static String TAG = "CameraStatistics";
98 private final static int CAMERA_OBSERVER_PERIOD_MS = 2000;
99 private final static int CAMERA_FREEZE_REPORT_TIMOUT_MS = 4000;
100
101 private final SurfaceTextureHelper surfaceTextureHelper;
102 private final CameraEventsHandler eventsHandler;
103 private int frameCount;
104 private int freezePeriodCount;
105 // Camera observer - monitors camera framerate. Observer is executed on camera thread.
106 private final Runnable cameraObserver = new Runnable() {
107 @Override
108 public void run() {
109 final int cameraFps = Math.round(frameCount * 1000.0f / CAMERA_OBSERVER_PERIOD_MS);
110 Logging.d(TAG, "Camera fps: " + cameraFps + ".");
111 if (frameCount == 0) {
112 ++freezePeriodCount;
113 if (CAMERA_OBSERVER_PERIOD_MS * freezePeriodCount >= CAMERA_FREEZE_REPORT_TIMOUT_MS
114 && eventsHandler != null) {
115 Logging.e(TAG, "Camera freezed.");
116 if (surfaceTextureHelper.isTextureInUse()) {
117 // This can only happen if we are capturing to textures.
118 eventsHandler.onCameraFreezed("Camera failure. Client must return video buffers.");
119 } else {
120 eventsHandler.onCameraFreezed("Camera failure.");
121 }
122 return;
123 }
124 } else {
125 freezePeriodCount = 0;
126 }
127 frameCount = 0;
128 surfaceTextureHelper.getHandler().postDelayed(this, CAMERA_OBSERVER_PERIOD_MS);
129 }
130 };
131
132 public CameraStatistics(
133 SurfaceTextureHelper surfaceTextureHelper, CameraEventsHandler eventsHandler) {
134 if (surfaceTextureHelper == null) {
135 throw new IllegalArgumentException("SurfaceTextureHelper is null");
136 }
137 this.surfaceTextureHelper = surfaceTextureHelper;
138 this.eventsHandler = eventsHandler;
139 this.frameCount = 0;
140 this.freezePeriodCount = 0;
141 surfaceTextureHelper.getHandler().postDelayed(cameraObserver, CAMERA_OBSERVER_PERIOD_MS);
142 }
143
144 private void checkThread() {
145 if (Thread.currentThread() != surfaceTextureHelper.getHandler().getLooper().getThread()) {
146 throw new IllegalStateException("Wrong thread");
147 }
148 }
149
150 public void addFrame() {
151 checkThread();
152 ++frameCount;
153 }
154
155 public void release() {
156 surfaceTextureHelper.getHandler().removeCallbacks(cameraObserver);
157 }
158 }
Magnus Jedverta8eab862016-05-20 17:22:12 +0200159}