blob: 291627f25af993edc56d291f5d79cb91b786405a [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;
Artem Titarenko69540f42018-12-10 12:30:46 +010014import android.support.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 */
Magnus Jedvert5ebb82b2018-04-12 16:23:34 +020070 @Deprecated
glaznev37adc5e2017-04-27 13:38:29 -070071 public interface MediaRecorderHandler {
72 // Invoked on success.
73 void onMediaRecorderSuccess();
74
75 // Invoked on failure, e.g. camera is stopped or any exception happens.
76 void onMediaRecorderError(String errorDescription);
77 }
78
79 /**
80 * Add MediaRecorder to camera pipeline. This can only be called while the camera is running.
81 * Once MediaRecorder is added to camera pipeline camera switch is not allowed.
82 * This function can be called from any thread.
83 */
Magnus Jedvert5ebb82b2018-04-12 16:23:34 +020084 @Deprecated
85 default void addMediaRecorderToCamera(
86 MediaRecorder mediaRecorder, MediaRecorderHandler resultHandler) {
87 throw new UnsupportedOperationException("Deprecated and not implemented.");
88 }
glaznev37adc5e2017-04-27 13:38:29 -070089
90 /**
91 * Remove MediaRecorder from camera pipeline. This can only be called while the camera is running.
92 * This function can be called from any thread.
93 */
Magnus Jedvert5ebb82b2018-04-12 16:23:34 +020094 @Deprecated
95 default void removeMediaRecorderFromCamera(MediaRecorderHandler resultHandler) {
96 throw new UnsupportedOperationException("Deprecated and not implemented.");
97 }
glaznev37adc5e2017-04-27 13:38:29 -070098
99 /**
magjedd5c77ab2017-04-19 08:45:45 -0700100 * Helper class to log framerate and detect if the camera freezes. It will run periodic callbacks
101 * on the SurfaceTextureHelper thread passed in the ctor, and should only be operated from that
102 * thread.
103 */
104 public static class CameraStatistics {
105 private final static String TAG = "CameraStatistics";
106 private final static int CAMERA_OBSERVER_PERIOD_MS = 2000;
107 private final static int CAMERA_FREEZE_REPORT_TIMOUT_MS = 4000;
108
109 private final SurfaceTextureHelper surfaceTextureHelper;
110 private final CameraEventsHandler eventsHandler;
111 private int frameCount;
112 private int freezePeriodCount;
113 // Camera observer - monitors camera framerate. Observer is executed on camera thread.
114 private final Runnable cameraObserver = new Runnable() {
115 @Override
116 public void run() {
117 final int cameraFps = Math.round(frameCount * 1000.0f / CAMERA_OBSERVER_PERIOD_MS);
118 Logging.d(TAG, "Camera fps: " + cameraFps + ".");
119 if (frameCount == 0) {
120 ++freezePeriodCount;
121 if (CAMERA_OBSERVER_PERIOD_MS * freezePeriodCount >= CAMERA_FREEZE_REPORT_TIMOUT_MS
122 && eventsHandler != null) {
123 Logging.e(TAG, "Camera freezed.");
124 if (surfaceTextureHelper.isTextureInUse()) {
125 // This can only happen if we are capturing to textures.
126 eventsHandler.onCameraFreezed("Camera failure. Client must return video buffers.");
127 } else {
128 eventsHandler.onCameraFreezed("Camera failure.");
129 }
130 return;
131 }
132 } else {
133 freezePeriodCount = 0;
134 }
135 frameCount = 0;
136 surfaceTextureHelper.getHandler().postDelayed(this, CAMERA_OBSERVER_PERIOD_MS);
137 }
138 };
139
140 public CameraStatistics(
141 SurfaceTextureHelper surfaceTextureHelper, CameraEventsHandler eventsHandler) {
142 if (surfaceTextureHelper == null) {
143 throw new IllegalArgumentException("SurfaceTextureHelper is null");
144 }
145 this.surfaceTextureHelper = surfaceTextureHelper;
146 this.eventsHandler = eventsHandler;
147 this.frameCount = 0;
148 this.freezePeriodCount = 0;
149 surfaceTextureHelper.getHandler().postDelayed(cameraObserver, CAMERA_OBSERVER_PERIOD_MS);
150 }
151
152 private void checkThread() {
153 if (Thread.currentThread() != surfaceTextureHelper.getHandler().getLooper().getThread()) {
154 throw new IllegalStateException("Wrong thread");
155 }
156 }
157
158 public void addFrame() {
159 checkThread();
160 ++frameCount;
161 }
162
163 public void release() {
164 surfaceTextureHelper.getHandler().removeCallbacks(cameraObserver);
165 }
166 }
Magnus Jedverta8eab862016-05-20 17:22:12 +0200167}