blob: be9d669fc4dfcae3cfd83634a26358c9f746b143 [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;
14
Magnus Jedverta8eab862016-05-20 17:22:12 +020015/**
16 * Base interface for camera1 and camera2 implementations. Extends VideoCapturer with a
17 * switchCamera() function. Also provides subinterfaces for handling camera events, and a helper
18 * class for detecting camera freezes.
19 */
20public interface CameraVideoCapturer extends VideoCapturer {
21 /**
22 * Camera events handler - can be used to be notifed about camera events. The callbacks are
23 * executed from an arbitrary thread.
24 */
25 public interface CameraEventsHandler {
26 // Camera error handler - invoked when camera can not be opened
27 // or any camera exception happens on camera thread.
28 void onCameraError(String errorDescription);
29
sakalf156bdd2016-10-06 00:59:10 -070030 // Called when camera is disconnected.
31 void onCameraDisconnected();
32
Magnus Jedverta8eab862016-05-20 17:22:12 +020033 // Invoked when camera stops receiving frames.
34 void onCameraFreezed(String errorDescription);
35
36 // Callback invoked when camera is opening.
sakalbc18fc02016-09-14 05:36:20 -070037 void onCameraOpening(String cameraName);
Magnus Jedverta8eab862016-05-20 17:22:12 +020038
39 // Callback invoked when first camera frame is available after camera is started.
40 void onFirstFrameAvailable();
41
42 // Callback invoked when camera is closed.
43 void onCameraClosed();
44 }
45
46 /**
47 * Camera switch handler - one of these functions are invoked with the result of switchCamera().
48 * The callback may be called on an arbitrary thread.
49 */
50 public interface CameraSwitchHandler {
51 // Invoked on success. |isFrontCamera| is true if the new camera is front facing.
52 void onCameraSwitchDone(boolean isFrontCamera);
53
54 // Invoked on failure, e.g. camera is stopped or only one camera available.
55 void onCameraSwitchError(String errorDescription);
56 }
57
58 /**
59 * Switch camera to the next valid camera id. This can only be called while the camera is running.
60 * This function can be called from any thread.
61 */
62 void switchCamera(CameraSwitchHandler switchEventsHandler);
magjedd5c77ab2017-04-19 08:45:45 -070063
64 /**
glaznev37adc5e2017-04-27 13:38:29 -070065 * MediaRecorder add/remove handler - one of these functions are invoked with the result of
66 * addMediaRecorderToCamera() or removeMediaRecorderFromCamera calls.
67 * The callback may be called on an arbitrary thread.
68 */
69 public interface MediaRecorderHandler {
70 // Invoked on success.
71 void onMediaRecorderSuccess();
72
73 // Invoked on failure, e.g. camera is stopped or any exception happens.
74 void onMediaRecorderError(String errorDescription);
75 }
76
77 /**
78 * Add MediaRecorder to camera pipeline. This can only be called while the camera is running.
79 * Once MediaRecorder is added to camera pipeline camera switch is not allowed.
80 * This function can be called from any thread.
81 */
82 void addMediaRecorderToCamera(MediaRecorder mediaRecorder, MediaRecorderHandler resultHandler);
83
84 /**
85 * Remove MediaRecorder from camera pipeline. This can only be called while the camera is running.
86 * This function can be called from any thread.
87 */
88 void removeMediaRecorderFromCamera(MediaRecorderHandler resultHandler);
89
90 /**
magjedd5c77ab2017-04-19 08:45:45 -070091 * Helper class to log framerate and detect if the camera freezes. It will run periodic callbacks
92 * on the SurfaceTextureHelper thread passed in the ctor, and should only be operated from that
93 * thread.
94 */
95 public static class CameraStatistics {
96 private final static String TAG = "CameraStatistics";
97 private final static int CAMERA_OBSERVER_PERIOD_MS = 2000;
98 private final static int CAMERA_FREEZE_REPORT_TIMOUT_MS = 4000;
99
100 private final SurfaceTextureHelper surfaceTextureHelper;
101 private final CameraEventsHandler eventsHandler;
102 private int frameCount;
103 private int freezePeriodCount;
104 // Camera observer - monitors camera framerate. Observer is executed on camera thread.
105 private final Runnable cameraObserver = new Runnable() {
106 @Override
107 public void run() {
108 final int cameraFps = Math.round(frameCount * 1000.0f / CAMERA_OBSERVER_PERIOD_MS);
109 Logging.d(TAG, "Camera fps: " + cameraFps + ".");
110 if (frameCount == 0) {
111 ++freezePeriodCount;
112 if (CAMERA_OBSERVER_PERIOD_MS * freezePeriodCount >= CAMERA_FREEZE_REPORT_TIMOUT_MS
113 && eventsHandler != null) {
114 Logging.e(TAG, "Camera freezed.");
115 if (surfaceTextureHelper.isTextureInUse()) {
116 // This can only happen if we are capturing to textures.
117 eventsHandler.onCameraFreezed("Camera failure. Client must return video buffers.");
118 } else {
119 eventsHandler.onCameraFreezed("Camera failure.");
120 }
121 return;
122 }
123 } else {
124 freezePeriodCount = 0;
125 }
126 frameCount = 0;
127 surfaceTextureHelper.getHandler().postDelayed(this, CAMERA_OBSERVER_PERIOD_MS);
128 }
129 };
130
131 public CameraStatistics(
132 SurfaceTextureHelper surfaceTextureHelper, CameraEventsHandler eventsHandler) {
133 if (surfaceTextureHelper == null) {
134 throw new IllegalArgumentException("SurfaceTextureHelper is null");
135 }
136 this.surfaceTextureHelper = surfaceTextureHelper;
137 this.eventsHandler = eventsHandler;
138 this.frameCount = 0;
139 this.freezePeriodCount = 0;
140 surfaceTextureHelper.getHandler().postDelayed(cameraObserver, CAMERA_OBSERVER_PERIOD_MS);
141 }
142
143 private void checkThread() {
144 if (Thread.currentThread() != surfaceTextureHelper.getHandler().getLooper().getThread()) {
145 throw new IllegalStateException("Wrong thread");
146 }
147 }
148
149 public void addFrame() {
150 checkThread();
151 ++frameCount;
152 }
153
154 public void release() {
155 surfaceTextureHelper.getHandler().removeCallbacks(cameraObserver);
156 }
157 }
Magnus Jedverta8eab862016-05-20 17:22:12 +0200158}