blob: 8750194cc7d1d1dd655760dcb08a0f19639b863c [file] [log] [blame]
Igor Murashkin70725502013-06-25 20:27:06 +00001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Eino-Ville Talvala2f1a2e42013-07-25 17:12:05 -070017package android.hardware.camera2.impl;
Igor Murashkin70725502013-06-25 20:27:06 +000018
Igor Murashkin57ea59b2013-08-23 16:55:57 -070019import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE;
20
Eino-Ville Talvala2f1a2e42013-07-25 17:12:05 -070021import android.hardware.camera2.CameraAccessException;
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -070022import android.hardware.camera2.CameraCaptureSession;
Ruben Brunk57493682014-05-27 18:58:08 -070023import android.hardware.camera2.CameraCharacteristics;
Eino-Ville Talvala2f1a2e42013-07-25 17:12:05 -070024import android.hardware.camera2.CaptureRequest;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070025import android.hardware.camera2.CaptureResult;
26import android.hardware.camera2.ICameraDeviceCallbacks;
27import android.hardware.camera2.ICameraDeviceUser;
Igor Murashkindb075af2014-05-21 10:07:08 -070028import android.hardware.camera2.TotalCaptureResult;
Eino-Ville Talvala5afd3e92013-08-21 10:37:04 -070029import android.hardware.camera2.utils.CameraBinderDecorator;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070030import android.hardware.camera2.utils.CameraRuntimeException;
Igor Murashkin49b2b132014-06-18 19:03:00 -070031import android.hardware.camera2.utils.CloseableLock;
32import android.hardware.camera2.utils.CloseableLock.ScopedLock;
Igor Murashkin9c595172014-05-12 13:56:20 -070033import android.hardware.camera2.utils.LongParcelable;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070034import android.os.Handler;
Ruben Brunkdecfe952013-10-29 11:00:32 -070035import android.os.IBinder;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070036import android.os.Looper;
Ruben Brunkdecfe952013-10-29 11:00:32 -070037import android.os.RemoteException;
Igor Murashkin70725502013-06-25 20:27:06 +000038import android.util.Log;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070039import android.util.SparseArray;
Igor Murashkin70725502013-06-25 20:27:06 +000040import android.view.Surface;
41
Jianing Weid2c3a822014-03-27 18:27:43 -070042import java.util.AbstractMap.SimpleEntry;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070043import java.util.ArrayList;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070044import java.util.HashSet;
Ruben Brunkdecfe952013-10-29 11:00:32 -070045import java.util.Iterator;
Igor Murashkin70725502013-06-25 20:27:06 +000046import java.util.List;
Jianing Weid2c3a822014-03-27 18:27:43 -070047import java.util.TreeSet;
Igor Murashkin70725502013-06-25 20:27:06 +000048
49/**
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070050 * HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
Igor Murashkin70725502013-06-25 20:27:06 +000051 */
Igor Murashkin21547d62014-06-04 15:21:42 -070052public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
Igor Murashkin70725502013-06-25 20:27:06 +000053
54 private final String TAG;
Zhijun Heecb323e2013-07-31 09:40:27 -070055 private final boolean DEBUG;
Igor Murashkin70725502013-06-25 20:27:06 +000056
Ruben Brunkdecfe952013-10-29 11:00:32 -070057 private static final int REQUEST_ID_NONE = -1;
58
Igor Murashkin70725502013-06-25 20:27:06 +000059 // TODO: guard every function with if (!mRemoteDevice) check (if it was closed)
60 private ICameraDeviceUser mRemoteDevice;
61
Igor Murashkin49b2b132014-06-18 19:03:00 -070062 private final CloseableLock mCloseLock;
Igor Murashkin70725502013-06-25 20:27:06 +000063 private final CameraDeviceCallbacks mCallbacks = new CameraDeviceCallbacks();
64
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070065 private final StateListener mDeviceListener;
Igor Murashkin0b27d342014-05-30 09:45:05 -070066 private volatile StateListener mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070067 private final Handler mDeviceHandler;
68
Igor Murashkin49b2b132014-06-18 19:03:00 -070069 private volatile boolean mClosing = false;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -070070 private boolean mInError = false;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070071 private boolean mIdle = true;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070072
Igor Murashkin21547d62014-06-04 15:21:42 -070073 /** map request IDs to listener/request data */
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070074 private final SparseArray<CaptureListenerHolder> mCaptureListenerMap =
75 new SparseArray<CaptureListenerHolder>();
Igor Murashkin70725502013-06-25 20:27:06 +000076
Ruben Brunkdecfe952013-10-29 11:00:32 -070077 private int mRepeatingRequestId = REQUEST_ID_NONE;
78 private final ArrayList<Integer> mRepeatingRequestIdDeletedList = new ArrayList<Integer>();
Igor Murashkin57ea59b2013-08-23 16:55:57 -070079 // Map stream IDs to Surfaces
80 private final SparseArray<Surface> mConfiguredOutputs = new SparseArray<Surface>();
Igor Murashkin70725502013-06-25 20:27:06 +000081
82 private final String mCameraId;
Ruben Brunk57493682014-05-27 18:58:08 -070083 private final CameraCharacteristics mCharacteristics;
Zhijun He83159152014-07-16 11:32:59 -070084 private final int mTotalPartialCount;
Igor Murashkin70725502013-06-25 20:27:06 +000085
Jianing Weid2c3a822014-03-27 18:27:43 -070086 /**
87 * A list tracking request and its expected last frame.
88 * Updated when calling ICameraDeviceUser methods.
89 */
90 private final List<SimpleEntry</*frameNumber*/Long, /*requestId*/Integer>>
91 mFrameNumberRequestPairs = new ArrayList<SimpleEntry<Long, Integer>>();
92
93 /**
94 * An object tracking received frame numbers.
95 * Updated when receiving callbacks from ICameraDeviceCallbacks.
96 */
97 private final FrameNumberTracker mFrameNumberTracker = new FrameNumberTracker();
98
Igor Murashkin0b27d342014-05-30 09:45:05 -070099 private CameraCaptureSessionImpl mCurrentSession;
100
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700101 // Runnables for all state transitions, except error, which needs the
102 // error code argument
103
104 private final Runnable mCallOnOpened = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700105 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700106 public void run() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700107 try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
108 if (scopedLock == null) return; // Camera already closed
109
Igor Murashkin0b27d342014-05-30 09:45:05 -0700110 StateListener sessionListener = mSessionStateListener;
111 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700112 sessionListener.onOpened(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700113 }
Sol Boucher4b3f8002014-06-05 13:47:24 -0700114 mDeviceListener.onOpened(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700115 }
116 }
117 };
118
119 private final Runnable mCallOnUnconfigured = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700120 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700121 public void run() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700122 try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
123 if (scopedLock == null) return; // Camera already closed
124
Igor Murashkin0b27d342014-05-30 09:45:05 -0700125 StateListener sessionListener = mSessionStateListener;
126 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700127 sessionListener.onUnconfigured(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700128 }
Sol Boucher4b3f8002014-06-05 13:47:24 -0700129 mDeviceListener.onUnconfigured(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700130 }
131 }
132 };
133
134 private final Runnable mCallOnActive = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700135 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700136 public void run() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700137 try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
138 if (scopedLock == null) return; // Camera already closed
139
Igor Murashkin0b27d342014-05-30 09:45:05 -0700140 StateListener sessionListener = mSessionStateListener;
141 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700142 sessionListener.onActive(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700143 }
Sol Boucher4b3f8002014-06-05 13:47:24 -0700144 mDeviceListener.onActive(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700145 }
146 }
147 };
148
149 private final Runnable mCallOnBusy = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700150 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700151 public void run() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700152 try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
153 if (scopedLock == null) return; // Camera already closed
154
Igor Murashkin0b27d342014-05-30 09:45:05 -0700155 StateListener sessionListener = mSessionStateListener;
156 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700157 sessionListener.onBusy(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700158 }
Sol Boucher4b3f8002014-06-05 13:47:24 -0700159 mDeviceListener.onBusy(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700160 }
161 }
162 };
163
164 private final Runnable mCallOnClosed = new Runnable() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700165 private boolean mClosedOnce = false;
166
Jianing Weid2c3a822014-03-27 18:27:43 -0700167 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700168 public void run() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700169 if (mClosedOnce) {
170 throw new AssertionError("Don't post #onClosed more than once");
171 }
172
Igor Murashkin0b27d342014-05-30 09:45:05 -0700173 StateListener sessionListener = mSessionStateListener;
174 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700175 sessionListener.onClosed(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700176 }
Sol Boucher4b3f8002014-06-05 13:47:24 -0700177 mDeviceListener.onClosed(CameraDeviceImpl.this);
Igor Murashkin49b2b132014-06-18 19:03:00 -0700178 mClosedOnce = true;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700179 }
180 };
181
182 private final Runnable mCallOnIdle = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700183 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700184 public void run() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700185 try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
186 if (scopedLock == null) return; // Camera already closed
187
Igor Murashkin0b27d342014-05-30 09:45:05 -0700188 StateListener sessionListener = mSessionStateListener;
189 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700190 sessionListener.onIdle(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700191 }
Sol Boucher4b3f8002014-06-05 13:47:24 -0700192 mDeviceListener.onIdle(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700193 }
194 }
195 };
196
197 private final Runnable mCallOnDisconnected = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700198 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700199 public void run() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700200 try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
201 if (scopedLock == null) return; // Camera already closed
202
Igor Murashkin0b27d342014-05-30 09:45:05 -0700203 StateListener sessionListener = mSessionStateListener;
204 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700205 sessionListener.onDisconnected(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700206 }
Sol Boucher4b3f8002014-06-05 13:47:24 -0700207 mDeviceListener.onDisconnected(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700208 }
209 }
210 };
211
Igor Murashkin21547d62014-06-04 15:21:42 -0700212 public CameraDeviceImpl(String cameraId, StateListener listener, Handler handler,
Ruben Brunk57493682014-05-27 18:58:08 -0700213 CameraCharacteristics characteristics) {
Zhijun He83159152014-07-16 11:32:59 -0700214 if (cameraId == null || listener == null || handler == null || characteristics == null) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700215 throw new IllegalArgumentException("Null argument given");
216 }
Igor Murashkin70725502013-06-25 20:27:06 +0000217 mCameraId = cameraId;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700218 mDeviceListener = listener;
219 mDeviceHandler = handler;
Ruben Brunk57493682014-05-27 18:58:08 -0700220 mCharacteristics = characteristics;
Igor Murashkin49b2b132014-06-18 19:03:00 -0700221 mCloseLock = new CloseableLock(/*name*/"CD-" + mCameraId);
Eino-Ville Talvalab72d1ef2014-04-28 13:21:18 -0700222
223 final int MAX_TAG_LEN = 23;
224 String tag = String.format("CameraDevice-JV-%s", mCameraId);
225 if (tag.length() > MAX_TAG_LEN) {
226 tag = tag.substring(0, MAX_TAG_LEN);
227 }
228 TAG = tag;
Zhijun Heecb323e2013-07-31 09:40:27 -0700229 DEBUG = Log.isLoggable(TAG, Log.DEBUG);
Zhijun He83159152014-07-16 11:32:59 -0700230
231 Integer partialCount =
232 mCharacteristics.get(CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT);
233 if (partialCount == null) {
234 // 1 means partial result is not supported.
235 mTotalPartialCount = 1;
236 } else {
237 mTotalPartialCount = partialCount;
238 }
Igor Murashkin70725502013-06-25 20:27:06 +0000239 }
240
241 public CameraDeviceCallbacks getCallbacks() {
242 return mCallbacks;
243 }
244
Igor Murashkin70725502013-06-25 20:27:06 +0000245 public void setRemoteDevice(ICameraDeviceUser remoteDevice) {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700246 try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
Eino-Ville Talvala5afd3e92013-08-21 10:37:04 -0700247 // TODO: Move from decorator to direct binder-mediated exceptions
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700248 // If setRemoteFailure already called, do nothing
249 if (mInError) return;
250
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700251 mRemoteDevice = CameraBinderDecorator.newInstance(remoteDevice);
252
253 mDeviceHandler.post(mCallOnOpened);
254 mDeviceHandler.post(mCallOnUnconfigured);
255 }
Igor Murashkin70725502013-06-25 20:27:06 +0000256 }
257
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700258 /**
259 * Call to indicate failed connection to a remote camera device.
260 *
261 * <p>This places the camera device in the error state and informs the listener.
262 * Use in place of setRemoteDevice() when startup fails.</p>
263 */
264 public void setRemoteFailure(final CameraRuntimeException failure) {
265 int failureCode = StateListener.ERROR_CAMERA_DEVICE;
266 boolean failureIsError = true;
267
268 switch (failure.getReason()) {
269 case CameraAccessException.CAMERA_IN_USE:
270 failureCode = StateListener.ERROR_CAMERA_IN_USE;
271 break;
272 case CameraAccessException.MAX_CAMERAS_IN_USE:
273 failureCode = StateListener.ERROR_MAX_CAMERAS_IN_USE;
274 break;
275 case CameraAccessException.CAMERA_DISABLED:
276 failureCode = StateListener.ERROR_CAMERA_DISABLED;
277 break;
278 case CameraAccessException.CAMERA_DISCONNECTED:
279 failureIsError = false;
280 break;
281 case CameraAccessException.CAMERA_ERROR:
282 failureCode = StateListener.ERROR_CAMERA_DEVICE;
283 break;
284 default:
285 Log.wtf(TAG, "Unknown failure in opening camera device: " + failure.getReason());
286 break;
287 }
288 final int code = failureCode;
289 final boolean isError = failureIsError;
Igor Murashkin49b2b132014-06-18 19:03:00 -0700290 try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
291 if (scopedLock == null) return; // Camera already closed, can't go to error state
292
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700293 mInError = true;
294 mDeviceHandler.post(new Runnable() {
Igor Murashkine1442202014-06-09 17:51:24 -0700295 @Override
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700296 public void run() {
297 if (isError) {
298 mDeviceListener.onError(CameraDeviceImpl.this, code);
299 } else {
300 mDeviceListener.onDisconnected(CameraDeviceImpl.this);
301 }
302 }
303 });
304 }
305 }
306
Igor Murashkin70725502013-06-25 20:27:06 +0000307 @Override
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700308 public String getId() {
309 return mCameraId;
310 }
311
Igor Murashkin70725502013-06-25 20:27:06 +0000312 public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700313 // Treat a null input the same an empty list
314 if (outputs == null) {
315 outputs = new ArrayList<Surface>();
316 }
Igor Murashkin49b2b132014-06-18 19:03:00 -0700317 try (ScopedLock scopedLock = mCloseLock.acquireExclusiveLock()) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700318 checkIfCameraClosedOrInError();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700319
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700320 HashSet<Surface> addSet = new HashSet<Surface>(outputs); // Streams to create
321 List<Integer> deleteList = new ArrayList<Integer>(); // Streams to delete
322
323 // Determine which streams need to be created, which to be deleted
324 for (int i = 0; i < mConfiguredOutputs.size(); ++i) {
325 int streamId = mConfiguredOutputs.keyAt(i);
326 Surface s = mConfiguredOutputs.valueAt(i);
327
328 if (!outputs.contains(s)) {
329 deleteList.add(streamId);
330 } else {
331 addSet.remove(s); // Don't create a stream previously created
332 }
333 }
334
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700335 mDeviceHandler.post(mCallOnBusy);
336 stopRepeating();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700337
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700338 try {
Ruben Brunkdecfe952013-10-29 11:00:32 -0700339 waitUntilIdle();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700340
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700341 mRemoteDevice.beginConfigure();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700342 // Delete all streams first (to free up HW resources)
343 for (Integer streamId : deleteList) {
344 mRemoteDevice.deleteStream(streamId);
345 mConfiguredOutputs.delete(streamId);
346 }
347
348 // Add all new streams
349 for (Surface s : addSet) {
Igor Murashkin70725502013-06-25 20:27:06 +0000350 // TODO: remove width,height,format since we are ignoring
351 // it.
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700352 int streamId = mRemoteDevice.createStream(0, 0, 0, s);
353 mConfiguredOutputs.put(streamId, s);
Igor Murashkin70725502013-06-25 20:27:06 +0000354 }
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700355
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700356 mRemoteDevice.endConfigure();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700357 } catch (CameraRuntimeException e) {
358 if (e.getReason() == CAMERA_IN_USE) {
359 throw new IllegalStateException("The camera is currently busy." +
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700360 " You must wait until the previous operation completes.");
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700361 }
362
363 throw e.asChecked();
364 } catch (RemoteException e) {
365 // impossible
366 return;
Igor Murashkin70725502013-06-25 20:27:06 +0000367 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700368
369 if (outputs.size() > 0) {
370 mDeviceHandler.post(mCallOnIdle);
371 } else {
372 mDeviceHandler.post(mCallOnUnconfigured);
373 }
Igor Murashkin70725502013-06-25 20:27:06 +0000374 }
375 }
376
377 @Override
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700378 public void createCaptureSession(List<Surface> outputs,
379 CameraCaptureSession.StateListener listener, Handler handler)
380 throws CameraAccessException {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700381 try (ScopedLock scopedLock = mCloseLock.acquireExclusiveLock()) {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700382 if (DEBUG) {
383 Log.d(TAG, "createCaptureSession");
384 }
385
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700386 checkIfCameraClosedOrInError();
Igor Murashkin0b27d342014-05-30 09:45:05 -0700387
388 // TODO: we must be in UNCONFIGURED mode to begin with, or using another session
389
390 // TODO: dont block for this
391 boolean configureSuccess = true;
392 CameraAccessException pendingException = null;
393 try {
394 configureOutputs(outputs); // and then block until IDLE
395 } catch (CameraAccessException e) {
396 configureSuccess = false;
397 pendingException = e;
Igor Murashkine1442202014-06-09 17:51:24 -0700398 if (DEBUG) {
399 Log.v(TAG, "createCaptureSession - failed with exception ", e);
400 }
Igor Murashkin0b27d342014-05-30 09:45:05 -0700401 }
402
403 // Fire onConfigured if configureOutputs succeeded, fire onConfigureFailed otherwise.
404 CameraCaptureSessionImpl newSession =
405 new CameraCaptureSessionImpl(outputs, listener, handler, this, mDeviceHandler,
406 configureSuccess);
407
408 if (mCurrentSession != null) {
409 mCurrentSession.replaceSessionClose(newSession);
410 }
411
412 // TODO: wait until current session closes, then create the new session
413 mCurrentSession = newSession;
414
415 if (pendingException != null) {
416 throw pendingException;
417 }
418
419 mSessionStateListener = mCurrentSession.getDeviceStateListener();
420 }
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700421 }
422
423 @Override
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700424 public CaptureRequest.Builder createCaptureRequest(int templateType)
425 throws CameraAccessException {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700426 try (ScopedLock scopedLock = mCloseLock.acquireExclusiveLock()) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700427 checkIfCameraClosedOrInError();
Igor Murashkin70725502013-06-25 20:27:06 +0000428
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700429 CameraMetadataNative templatedRequest = new CameraMetadataNative();
Igor Murashkin70725502013-06-25 20:27:06 +0000430
431 try {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700432 mRemoteDevice.createDefaultRequest(templateType, /*out*/templatedRequest);
Igor Murashkin70725502013-06-25 20:27:06 +0000433 } catch (CameraRuntimeException e) {
434 throw e.asChecked();
435 } catch (RemoteException e) {
436 // impossible
437 return null;
438 }
439
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700440 CaptureRequest.Builder builder =
441 new CaptureRequest.Builder(templatedRequest);
Igor Murashkin70725502013-06-25 20:27:06 +0000442
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700443 return builder;
Igor Murashkin70725502013-06-25 20:27:06 +0000444 }
445 }
446
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700447 public int capture(CaptureRequest request, CaptureListener listener, Handler handler)
Igor Murashkin70725502013-06-25 20:27:06 +0000448 throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700449 if (DEBUG) {
450 Log.d(TAG, "calling capture");
451 }
452 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
453 requestList.add(request);
454 return submitCaptureRequest(requestList, listener, handler, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000455 }
456
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700457 public int captureBurst(List<CaptureRequest> requests, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700458 Handler handler) throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700459 if (requests == null || requests.isEmpty()) {
460 throw new IllegalArgumentException("At least one request must be given");
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700461 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700462 return submitCaptureRequest(requests, listener, handler, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000463 }
464
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700465 /**
466 * This method checks lastFrameNumber returned from ICameraDeviceUser methods for
467 * starting and stopping repeating request and flushing.
468 *
469 * <p>If lastFrameNumber is NO_FRAMES_CAPTURED, it means that the request was never
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700470 * sent to HAL. Then onCaptureSequenceAborted is immediately triggered.
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700471 * If lastFrameNumber is non-negative, then the requestId and lastFrameNumber pair
472 * is added to the list mFrameNumberRequestPairs.</p>
473 *
474 * @param requestId the request ID of the current repeating request.
475 *
476 * @param lastFrameNumber last frame number returned from binder.
477 */
478 private void checkEarlyTriggerSequenceComplete(
479 final int requestId, final long lastFrameNumber) {
480 // lastFrameNumber being equal to NO_FRAMES_CAPTURED means that the request
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700481 // was never sent to HAL. Should trigger onCaptureSequenceAborted immediately.
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700482 if (lastFrameNumber == CaptureListener.NO_FRAMES_CAPTURED) {
483 final CaptureListenerHolder holder;
484 int index = mCaptureListenerMap.indexOfKey(requestId);
485 holder = (index >= 0) ? mCaptureListenerMap.valueAt(index) : null;
486 if (holder != null) {
487 mCaptureListenerMap.removeAt(index);
Jianing Weibaf0c652014-04-18 17:35:00 -0700488 if (DEBUG) {
489 Log.v(TAG, String.format(
490 "remove holder for requestId %d, "
491 + "because lastFrame is %d.",
492 requestId, lastFrameNumber));
493 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700494 }
495
496 if (holder != null) {
497 if (DEBUG) {
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700498 Log.v(TAG, "immediately trigger onCaptureSequenceAborted because"
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700499 + " request did not reach HAL");
500 }
501
502 Runnable resultDispatch = new Runnable() {
503 @Override
504 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700505 if (!CameraDeviceImpl.this.isClosed()) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700506 if (DEBUG) {
507 Log.d(TAG, String.format(
508 "early trigger sequence complete for request %d",
509 requestId));
510 }
511 if (lastFrameNumber < Integer.MIN_VALUE
512 || lastFrameNumber > Integer.MAX_VALUE) {
513 throw new AssertionError(lastFrameNumber + " cannot be cast to int");
514 }
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700515 holder.getListener().onCaptureSequenceAborted(
Igor Murashkin21547d62014-06-04 15:21:42 -0700516 CameraDeviceImpl.this,
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700517 requestId);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700518 }
519 }
520 };
521 holder.getHandler().post(resultDispatch);
522 } else {
523 Log.w(TAG, String.format(
524 "did not register listener to request %d",
525 requestId));
526 }
527 } else {
528 mFrameNumberRequestPairs.add(
529 new SimpleEntry<Long, Integer>(lastFrameNumber,
530 requestId));
531 }
532 }
533
Jianing Weid2c3a822014-03-27 18:27:43 -0700534 private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700535 Handler handler, boolean repeating) throws CameraAccessException {
536
537 // Need a valid handler, or current thread needs to have a looper, if
538 // listener is valid
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700539 if (listener != null) {
540 handler = checkHandler(handler);
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700541 }
Igor Murashkin70725502013-06-25 20:27:06 +0000542
Ruben Brunk7f2372b2014-07-02 11:05:08 -0700543 // Make sure that there all requests have at least 1 surface; all surfaces are non-null
544 for (CaptureRequest request : requestList) {
545 if (request.getTargets().isEmpty()) {
546 throw new IllegalArgumentException(
547 "Each request must have at least one Surface target");
548 }
549
550 for (Surface surface : request.getTargets()) {
551 if (surface == null) {
552 throw new IllegalArgumentException("Null Surface targets are not allowed");
553 }
554 }
555 }
556
Igor Murashkin49b2b132014-06-18 19:03:00 -0700557 try (ScopedLock scopedLock = mCloseLock.acquireExclusiveLock()) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700558 checkIfCameraClosedOrInError();
Igor Murashkin70725502013-06-25 20:27:06 +0000559 int requestId;
560
Ruben Brunke73b41b2013-11-07 19:30:43 -0800561 if (repeating) {
562 stopRepeating();
563 }
564
Jianing Weid2c3a822014-03-27 18:27:43 -0700565 LongParcelable lastFrameNumberRef = new LongParcelable();
Igor Murashkin70725502013-06-25 20:27:06 +0000566 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700567 requestId = mRemoteDevice.submitRequestList(requestList, repeating,
568 /*out*/lastFrameNumberRef);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700569 if (DEBUG) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700570 Log.v(TAG, "last frame number " + lastFrameNumberRef.getNumber());
571 }
Igor Murashkin70725502013-06-25 20:27:06 +0000572 } catch (CameraRuntimeException e) {
573 throw e.asChecked();
574 } catch (RemoteException e) {
575 // impossible
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700576 return -1;
Igor Murashkin70725502013-06-25 20:27:06 +0000577 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700578
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700579 if (listener != null) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700580 mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener,
581 requestList, handler, repeating));
Jianing Weibaf0c652014-04-18 17:35:00 -0700582 } else {
583 if (DEBUG) {
584 Log.d(TAG, "Listen for request " + requestId + " is null");
585 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700586 }
Igor Murashkin70725502013-06-25 20:27:06 +0000587
Jianing Weid2c3a822014-03-27 18:27:43 -0700588 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700589
Igor Murashkin70725502013-06-25 20:27:06 +0000590 if (repeating) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700591 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700592 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700593 }
Ruben Brunkdecfe952013-10-29 11:00:32 -0700594 mRepeatingRequestId = requestId;
Jianing Weid2c3a822014-03-27 18:27:43 -0700595 } else {
596 mFrameNumberRequestPairs.add(
597 new SimpleEntry<Long, Integer>(lastFrameNumber, requestId));
Igor Murashkin70725502013-06-25 20:27:06 +0000598 }
599
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700600 if (mIdle) {
601 mDeviceHandler.post(mCallOnActive);
602 }
603 mIdle = false;
604
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700605 return requestId;
Igor Murashkin70725502013-06-25 20:27:06 +0000606 }
607 }
608
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700609 public int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700610 Handler handler) throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700611 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
612 requestList.add(request);
613 return submitCaptureRequest(requestList, listener, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000614 }
615
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700616 public int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700617 Handler handler) throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700618 if (requests == null || requests.isEmpty()) {
619 throw new IllegalArgumentException("At least one request must be given");
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700620 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700621 return submitCaptureRequest(requests, listener, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000622 }
623
Igor Murashkin70725502013-06-25 20:27:06 +0000624 public void stopRepeating() throws CameraAccessException {
625
Igor Murashkin49b2b132014-06-18 19:03:00 -0700626 try (ScopedLock scopedLock = mCloseLock.acquireExclusiveLock()) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700627 checkIfCameraClosedOrInError();
Ruben Brunkdecfe952013-10-29 11:00:32 -0700628 if (mRepeatingRequestId != REQUEST_ID_NONE) {
629
630 int requestId = mRepeatingRequestId;
631 mRepeatingRequestId = REQUEST_ID_NONE;
632
633 // Queue for deletion after in-flight requests finish
Zhijun He1a9b6462014-03-31 16:11:33 -0700634 if (mCaptureListenerMap.get(requestId) != null) {
635 mRepeatingRequestIdDeletedList.add(requestId);
636 }
Igor Murashkin70725502013-06-25 20:27:06 +0000637
638 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700639 LongParcelable lastFrameNumberRef = new LongParcelable();
640 mRemoteDevice.cancelRequest(requestId, /*out*/lastFrameNumberRef);
641 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700642
643 checkEarlyTriggerSequenceComplete(requestId, lastFrameNumber);
644
Igor Murashkin70725502013-06-25 20:27:06 +0000645 } catch (CameraRuntimeException e) {
646 throw e.asChecked();
647 } catch (RemoteException e) {
648 // impossible
649 return;
650 }
651 }
652 }
653 }
654
Zhijun Hed842fcd2013-12-26 14:14:04 -0800655 private void waitUntilIdle() throws CameraAccessException {
Zhijun He7f4d3142013-07-23 07:54:38 -0700656
Igor Murashkin49b2b132014-06-18 19:03:00 -0700657 try (ScopedLock scopedLock = mCloseLock.acquireExclusiveLock()) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700658 checkIfCameraClosedOrInError();
Ruben Brunkdecfe952013-10-29 11:00:32 -0700659 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Zhijun He7f4d3142013-07-23 07:54:38 -0700660 throw new IllegalStateException("Active repeating request ongoing");
661 }
662
663 try {
664 mRemoteDevice.waitUntilIdle();
665 } catch (CameraRuntimeException e) {
666 throw e.asChecked();
667 } catch (RemoteException e) {
668 // impossible
669 return;
670 }
Ruben Brunkdecfe952013-10-29 11:00:32 -0700671
672 mRepeatingRequestId = REQUEST_ID_NONE;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700673 }
Igor Murashkin70725502013-06-25 20:27:06 +0000674 }
675
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700676 public void flush() throws CameraAccessException {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700677 try (ScopedLock scopedLock = mCloseLock.acquireExclusiveLock()) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700678 checkIfCameraClosedOrInError();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700679
680 mDeviceHandler.post(mCallOnBusy);
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700681 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700682 LongParcelable lastFrameNumberRef = new LongParcelable();
683 mRemoteDevice.flush(/*out*/lastFrameNumberRef);
684 if (mRepeatingRequestId != REQUEST_ID_NONE) {
685 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700686 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700687 mRepeatingRequestId = REQUEST_ID_NONE;
688 }
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700689 } catch (CameraRuntimeException e) {
690 throw e.asChecked();
691 } catch (RemoteException e) {
692 // impossible
693 return;
694 }
695 }
696 }
697
698 @Override
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700699 public void close() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700700 mClosing = true;
701 // Acquire exclusive lock, close, release (idempotent)
702 mCloseLock.close();
Igor Murashkin70725502013-06-25 20:27:06 +0000703
Igor Murashkin49b2b132014-06-18 19:03:00 -0700704 /*
705 * The rest of this is safe, since no other methods will be able to execute
706 * (they will throw ISE instead; the callbacks will get dropped)
707 */
708 {
Igor Murashkin70725502013-06-25 20:27:06 +0000709 try {
Igor Murashkin2a3eced2013-08-28 17:35:10 -0700710 if (mRemoteDevice != null) {
711 mRemoteDevice.disconnect();
712 }
Igor Murashkin70725502013-06-25 20:27:06 +0000713 } catch (CameraRuntimeException e) {
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700714 Log.e(TAG, "Exception while closing: ", e.asChecked());
Igor Murashkin70725502013-06-25 20:27:06 +0000715 } catch (RemoteException e) {
716 // impossible
717 }
718
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700719 // Only want to fire the onClosed callback once;
720 // either a normal close where the remote device is valid
721 // or a close after a startup error (no remote device but in error state)
722 if (mRemoteDevice != null || mInError) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700723 mDeviceHandler.post(mCallOnClosed);
724 }
Igor Murashkin70725502013-06-25 20:27:06 +0000725
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700726 mRemoteDevice = null;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700727 mInError = false;
Igor Murashkin70725502013-06-25 20:27:06 +0000728 }
729 }
730
731 @Override
732 protected void finalize() throws Throwable {
733 try {
734 close();
Igor Murashkin70725502013-06-25 20:27:06 +0000735 }
736 finally {
737 super.finalize();
738 }
739 }
740
741 static class CaptureListenerHolder {
742
743 private final boolean mRepeating;
744 private final CaptureListener mListener;
Jianing Weid2c3a822014-03-27 18:27:43 -0700745 private final List<CaptureRequest> mRequestList;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700746 private final Handler mHandler;
Igor Murashkin70725502013-06-25 20:27:06 +0000747
Jianing Weid2c3a822014-03-27 18:27:43 -0700748 CaptureListenerHolder(CaptureListener listener, List<CaptureRequest> requestList,
749 Handler handler, boolean repeating) {
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700750 if (listener == null || handler == null) {
751 throw new UnsupportedOperationException(
752 "Must have a valid handler and a valid listener");
753 }
Igor Murashkin70725502013-06-25 20:27:06 +0000754 mRepeating = repeating;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700755 mHandler = handler;
Jianing Weid2c3a822014-03-27 18:27:43 -0700756 mRequestList = new ArrayList<CaptureRequest>(requestList);
Igor Murashkin70725502013-06-25 20:27:06 +0000757 mListener = listener;
758 }
759
760 public boolean isRepeating() {
761 return mRepeating;
762 }
763
764 public CaptureListener getListener() {
765 return mListener;
766 }
767
Jianing Weid2c3a822014-03-27 18:27:43 -0700768 public CaptureRequest getRequest(int subsequenceId) {
769 if (subsequenceId >= mRequestList.size()) {
770 throw new IllegalArgumentException(
771 String.format(
772 "Requested subsequenceId %d is larger than request list size %d.",
773 subsequenceId, mRequestList.size()));
774 } else {
775 if (subsequenceId < 0) {
776 throw new IllegalArgumentException(String.format(
777 "Requested subsequenceId %d is negative", subsequenceId));
778 } else {
779 return mRequestList.get(subsequenceId);
780 }
781 }
782 }
783
Igor Murashkin70725502013-06-25 20:27:06 +0000784 public CaptureRequest getRequest() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700785 return getRequest(0);
Igor Murashkin70725502013-06-25 20:27:06 +0000786 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700787
788 public Handler getHandler() {
789 return mHandler;
790 }
791
Igor Murashkin70725502013-06-25 20:27:06 +0000792 }
793
Jianing Weid2c3a822014-03-27 18:27:43 -0700794 /**
795 * This class tracks the last frame number for submitted requests.
796 */
797 public class FrameNumberTracker {
798
799 private long mCompletedFrameNumber = -1;
800 private final TreeSet<Long> mFutureErrorSet = new TreeSet<Long>();
801
802 private void update() {
803 Iterator<Long> iter = mFutureErrorSet.iterator();
804 while (iter.hasNext()) {
805 long errorFrameNumber = iter.next();
806 if (errorFrameNumber == mCompletedFrameNumber + 1) {
807 mCompletedFrameNumber++;
808 iter.remove();
809 } else {
810 break;
811 }
812 }
813 }
814
815 /**
816 * This function is called every time when a result or an error is received.
817 * @param frameNumber: the frame number corresponding to the result or error
818 * @param isError: true if it is an error, false if it is not an error
819 */
820 public void updateTracker(long frameNumber, boolean isError) {
821 if (isError) {
822 mFutureErrorSet.add(frameNumber);
823 } else {
824 /**
825 * HAL cannot send an OnResultReceived for frame N unless it knows for
826 * sure that all frames prior to N have either errored out or completed.
827 * So if the current frame is not an error, then all previous frames
828 * should have arrived. The following line checks whether this holds.
829 */
830 if (frameNumber != mCompletedFrameNumber + 1) {
Zhijun He22589b42014-05-01 10:37:36 -0700831 Log.e(TAG, String.format(
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700832 "result frame number %d comes out of order, should be %d + 1",
833 frameNumber, mCompletedFrameNumber));
Jianing Weid2c3a822014-03-27 18:27:43 -0700834 }
835 mCompletedFrameNumber++;
836 }
837 update();
838 }
839
840 public long getCompletedFrameNumber() {
841 return mCompletedFrameNumber;
842 }
843
844 }
845
846 private void checkAndFireSequenceComplete() {
847 long completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber();
848 Iterator<SimpleEntry<Long, Integer> > iter = mFrameNumberRequestPairs.iterator();
849 while (iter.hasNext()) {
850 final SimpleEntry<Long, Integer> frameNumberRequestPair = iter.next();
851 if (frameNumberRequestPair.getKey() <= completedFrameNumber) {
852
853 // remove request from mCaptureListenerMap
854 final int requestId = frameNumberRequestPair.getValue();
855 final CaptureListenerHolder holder;
Igor Murashkin49b2b132014-06-18 19:03:00 -0700856 try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
857 if (scopedLock == null) {
858 Log.w(TAG, "Camera closed while checking sequences");
859 return;
860 }
861
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700862 int index = mCaptureListenerMap.indexOfKey(requestId);
863 holder = (index >= 0) ? mCaptureListenerMap.valueAt(index)
Jianing Weid2c3a822014-03-27 18:27:43 -0700864 : null;
865 if (holder != null) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700866 mCaptureListenerMap.removeAt(index);
867 if (DEBUG) {
868 Log.v(TAG, String.format(
869 "remove holder for requestId %d, "
870 + "because lastFrame %d is <= %d",
871 requestId, frameNumberRequestPair.getKey(),
872 completedFrameNumber));
873 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700874 }
875 }
876 iter.remove();
877
878 // Call onCaptureSequenceCompleted
879 if (holder != null) {
880 Runnable resultDispatch = new Runnable() {
881 @Override
882 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700883 if (!CameraDeviceImpl.this.isClosed()){
Jianing Weid2c3a822014-03-27 18:27:43 -0700884 if (DEBUG) {
885 Log.d(TAG, String.format(
886 "fire sequence complete for request %d",
887 requestId));
888 }
889
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700890 long lastFrameNumber = frameNumberRequestPair.getKey();
891 if (lastFrameNumber < Integer.MIN_VALUE
892 || lastFrameNumber > Integer.MAX_VALUE) {
893 throw new AssertionError(lastFrameNumber
894 + " cannot be cast to int");
895 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700896 holder.getListener().onCaptureSequenceCompleted(
Igor Murashkin21547d62014-06-04 15:21:42 -0700897 CameraDeviceImpl.this,
Jianing Weid2c3a822014-03-27 18:27:43 -0700898 requestId,
Igor Murashkindb075af2014-05-21 10:07:08 -0700899 lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700900 }
901 }
902 };
903 holder.getHandler().post(resultDispatch);
904 }
905
906 }
907 }
908 }
909
Zhijun Heecb323e2013-07-31 09:40:27 -0700910 public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
Igor Murashkin70725502013-06-25 20:27:06 +0000911
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700912 //
913 // Constants below need to be kept up-to-date with
914 // frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
915 //
916
917 //
918 // Error codes for onCameraError
919 //
920
921 /**
922 * Camera has been disconnected
923 */
924 static final int ERROR_CAMERA_DISCONNECTED = 0;
925
926 /**
927 * Camera has encountered a device-level error
928 * Matches CameraDevice.StateListener#ERROR_CAMERA_DEVICE
929 */
930 static final int ERROR_CAMERA_DEVICE = 1;
931
932 /**
933 * Camera has encountered a service-level error
934 * Matches CameraDevice.StateListener#ERROR_CAMERA_SERVICE
935 */
936 static final int ERROR_CAMERA_SERVICE = 2;
937
Igor Murashkin70725502013-06-25 20:27:06 +0000938 @Override
939 public IBinder asBinder() {
940 return this;
941 }
942
Igor Murashkin70725502013-06-25 20:27:06 +0000943 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -0700944 public void onCameraError(final int errorCode, CaptureResultExtras resultExtras) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700945 Runnable r = null;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700946
Igor Murashkin49b2b132014-06-18 19:03:00 -0700947 try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
948 if (scopedLock == null) {
949 return; // Camera already closed
950 }
951
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700952 mInError = true;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700953 switch (errorCode) {
954 case ERROR_CAMERA_DISCONNECTED:
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700955 r = mCallOnDisconnected;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700956 break;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700957 default:
958 Log.e(TAG, "Unknown error from camera device: " + errorCode);
959 // no break
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700960 case ERROR_CAMERA_DEVICE:
961 case ERROR_CAMERA_SERVICE:
962 r = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700963 @Override
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700964 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700965 if (!CameraDeviceImpl.this.isClosed()) {
966 mDeviceListener.onError(CameraDeviceImpl.this, errorCode);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700967 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700968 }
969 };
970 break;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700971 }
Igor Murashkin21547d62014-06-04 15:21:42 -0700972 CameraDeviceImpl.this.mDeviceHandler.post(r);
Jianing Weid2c3a822014-03-27 18:27:43 -0700973
Igor Murashkin49b2b132014-06-18 19:03:00 -0700974 // Fire onCaptureSequenceCompleted
975 if (DEBUG) {
976 Log.v(TAG, String.format("got error frame %d", resultExtras.getFrameNumber()));
977 }
978 mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(), /*error*/true);
979 checkAndFireSequenceComplete();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700980 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700981 }
982
983 @Override
984 public void onCameraIdle() {
985 if (DEBUG) {
986 Log.d(TAG, "Camera now idle");
987 }
Igor Murashkin49b2b132014-06-18 19:03:00 -0700988 try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
989 if (scopedLock == null) return; // Camera already closed
990
Igor Murashkin21547d62014-06-04 15:21:42 -0700991 if (!CameraDeviceImpl.this.mIdle) {
992 CameraDeviceImpl.this.mDeviceHandler.post(mCallOnIdle);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700993 }
Igor Murashkin21547d62014-06-04 15:21:42 -0700994 CameraDeviceImpl.this.mIdle = true;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700995 }
996 }
997
998 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -0700999 public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) {
1000 int requestId = resultExtras.getRequestId();
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001001 if (DEBUG) {
1002 Log.d(TAG, "Capture started for id " + requestId);
1003 }
1004 final CaptureListenerHolder holder;
1005
Igor Murashkin49b2b132014-06-18 19:03:00 -07001006 try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
1007 if (scopedLock == null) return; // Camera already closed
1008
1009 // Get the listener for this frame ID, if there is one
Igor Murashkin21547d62014-06-04 15:21:42 -07001010 holder = CameraDeviceImpl.this.mCaptureListenerMap.get(requestId);
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001011
Igor Murashkin49b2b132014-06-18 19:03:00 -07001012 if (holder == null) {
1013 return;
1014 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001015
Igor Murashkin49b2b132014-06-18 19:03:00 -07001016 if (isClosed()) return;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001017
Igor Murashkin49b2b132014-06-18 19:03:00 -07001018 // Dispatch capture start notice
1019 holder.getHandler().post(
1020 new Runnable() {
1021 @Override
1022 public void run() {
1023 if (!CameraDeviceImpl.this.isClosed()) {
1024 holder.getListener().onCaptureStarted(
1025 CameraDeviceImpl.this,
1026 holder.getRequest(resultExtras.getSubsequenceId()),
1027 timestamp);
1028 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001029 }
Igor Murashkin49b2b132014-06-18 19:03:00 -07001030 });
1031
1032 }
Igor Murashkin70725502013-06-25 20:27:06 +00001033 }
1034
1035 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -07001036 public void onResultReceived(CameraMetadataNative result,
1037 CaptureResultExtras resultExtras) throws RemoteException {
Ruben Brunk57493682014-05-27 18:58:08 -07001038
Jianing Weid2c3a822014-03-27 18:27:43 -07001039 int requestId = resultExtras.getRequestId();
Zhijun Heecb323e2013-07-31 09:40:27 -07001040 if (DEBUG) {
Jianing Weibaf0c652014-04-18 17:35:00 -07001041 Log.v(TAG, "Received result frame " + resultExtras.getFrameNumber() + " for id "
1042 + requestId);
Zhijun Heecb323e2013-07-31 09:40:27 -07001043 }
Ruben Brunk57493682014-05-27 18:58:08 -07001044
Igor Murashkin49b2b132014-06-18 19:03:00 -07001045 try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
1046 if (scopedLock == null) return; // Camera already closed
Ruben Brunk57493682014-05-27 18:58:08 -07001047
Igor Murashkin49b2b132014-06-18 19:03:00 -07001048 // TODO: Handle CameraCharacteristics access from CaptureResult correctly.
1049 result.set(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE,
1050 getCharacteristics().get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE));
Ruben Brunk57493682014-05-27 18:58:08 -07001051
Igor Murashkin49b2b132014-06-18 19:03:00 -07001052 final CaptureListenerHolder holder =
1053 CameraDeviceImpl.this.mCaptureListenerMap.get(requestId);
Igor Murashkin70725502013-06-25 20:27:06 +00001054
Zhijun He83159152014-07-16 11:32:59 -07001055 boolean isPartialResult =
1056 (resultExtras.getPartialResultCount() < mTotalPartialCount);
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001057
Igor Murashkin49b2b132014-06-18 19:03:00 -07001058 // Update tracker (increment counter) when it's not a partial result.
Zhijun He83159152014-07-16 11:32:59 -07001059 if (!isPartialResult) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001060 mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(),
1061 /*error*/false);
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001062 }
Igor Murashkin70725502013-06-25 20:27:06 +00001063
Igor Murashkin49b2b132014-06-18 19:03:00 -07001064 // Check if we have a listener for this
1065 if (holder == null) {
1066 if (DEBUG) {
1067 Log.d(TAG,
1068 "holder is null, early return at frame "
1069 + resultExtras.getFrameNumber());
1070 }
1071 return;
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001072 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001073
Igor Murashkin49b2b132014-06-18 19:03:00 -07001074 if (isClosed()) {
1075 if (DEBUG) {
1076 Log.d(TAG,
1077 "camera is closed, early return at frame "
1078 + resultExtras.getFrameNumber());
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001079 }
Igor Murashkin49b2b132014-06-18 19:03:00 -07001080 return;
1081 }
Igor Murashkindb075af2014-05-21 10:07:08 -07001082
Igor Murashkin49b2b132014-06-18 19:03:00 -07001083 final CaptureRequest request = holder.getRequest(resultExtras.getSubsequenceId());
1084
1085
1086 Runnable resultDispatch = null;
1087
1088 // Either send a partial result or the final capture completed result
Zhijun He83159152014-07-16 11:32:59 -07001089 if (isPartialResult) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001090 final CaptureResult resultAsCapture =
1091 new CaptureResult(result, request, requestId);
1092
1093 // Partial result
1094 resultDispatch = new Runnable() {
1095 @Override
1096 public void run() {
1097 if (!CameraDeviceImpl.this.isClosed()){
1098 holder.getListener().onCapturePartial(
1099 CameraDeviceImpl.this,
1100 request,
1101 resultAsCapture);
1102 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001103 }
Igor Murashkin49b2b132014-06-18 19:03:00 -07001104 };
1105 } else {
1106 final TotalCaptureResult resultAsCapture =
1107 new TotalCaptureResult(result, request, requestId);
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001108
Igor Murashkin49b2b132014-06-18 19:03:00 -07001109 // Final capture result
1110 resultDispatch = new Runnable() {
1111 @Override
1112 public void run() {
1113 if (!CameraDeviceImpl.this.isClosed()){
1114 holder.getListener().onCaptureCompleted(
1115 CameraDeviceImpl.this,
1116 request,
1117 resultAsCapture);
1118 }
1119 }
1120 };
1121 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001122
Igor Murashkin49b2b132014-06-18 19:03:00 -07001123 holder.getHandler().post(resultDispatch);
1124
1125 // Fire onCaptureSequenceCompleted
Zhijun He83159152014-07-16 11:32:59 -07001126 if (!isPartialResult) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001127 checkAndFireSequenceComplete();
1128 }
1129
Jianing Weid2c3a822014-03-27 18:27:43 -07001130 }
Igor Murashkin70725502013-06-25 20:27:06 +00001131 }
1132
1133 }
1134
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001135 /**
Igor Murashkin0b27d342014-05-30 09:45:05 -07001136 * Default handler management.
1137 *
1138 * <p>
1139 * If handler is null, get the current thread's
1140 * Looper to create a Handler with. If no looper exists, throw {@code IllegalArgumentException}.
1141 * </p>
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001142 */
Igor Murashkin0b27d342014-05-30 09:45:05 -07001143 static Handler checkHandler(Handler handler) {
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001144 if (handler == null) {
1145 Looper looper = Looper.myLooper();
1146 if (looper == null) {
1147 throw new IllegalArgumentException(
1148 "No handler given, and current thread has no looper!");
1149 }
1150 handler = new Handler(looper);
1151 }
1152 return handler;
1153 }
1154
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -07001155 private void checkIfCameraClosedOrInError() throws CameraAccessException {
1156 if (mInError) {
1157 throw new CameraAccessException(CameraAccessException.CAMERA_ERROR,
1158 "The camera device has encountered a serious error");
1159 }
Zhijun He7f4d3142013-07-23 07:54:38 -07001160 if (mRemoteDevice == null) {
1161 throw new IllegalStateException("CameraDevice was already closed");
1162 }
1163 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001164
Igor Murashkin49b2b132014-06-18 19:03:00 -07001165 /** Whether the camera device has started to close (may not yet have finished) */
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001166 private boolean isClosed() {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001167 return mClosing;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001168 }
Ruben Brunk57493682014-05-27 18:58:08 -07001169
1170 private CameraCharacteristics getCharacteristics() {
1171 return mCharacteristics;
1172 }
Igor Murashkin70725502013-06-25 20:27:06 +00001173}