blob: 3a94e02fc1c1c9432880a89c42ef6acddabca478 [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 Murashkin9c595172014-05-12 13:56:20 -070031import android.hardware.camera2.utils.LongParcelable;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070032import android.os.Handler;
Ruben Brunkdecfe952013-10-29 11:00:32 -070033import android.os.IBinder;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070034import android.os.Looper;
Ruben Brunkdecfe952013-10-29 11:00:32 -070035import android.os.RemoteException;
Igor Murashkin70725502013-06-25 20:27:06 +000036import android.util.Log;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070037import android.util.SparseArray;
Igor Murashkin70725502013-06-25 20:27:06 +000038import android.view.Surface;
39
Jianing Weid2c3a822014-03-27 18:27:43 -070040import java.util.AbstractMap.SimpleEntry;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070041import java.util.ArrayList;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070042import java.util.HashSet;
Ruben Brunkdecfe952013-10-29 11:00:32 -070043import java.util.Iterator;
Igor Murashkin70725502013-06-25 20:27:06 +000044import java.util.List;
Jianing Weid2c3a822014-03-27 18:27:43 -070045import java.util.TreeSet;
Igor Murashkin70725502013-06-25 20:27:06 +000046
47/**
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070048 * HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
Igor Murashkin70725502013-06-25 20:27:06 +000049 */
Igor Murashkin21547d62014-06-04 15:21:42 -070050public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
Igor Murashkin70725502013-06-25 20:27:06 +000051
52 private final String TAG;
Zhijun Heecb323e2013-07-31 09:40:27 -070053 private final boolean DEBUG;
Igor Murashkin70725502013-06-25 20:27:06 +000054
Ruben Brunkdecfe952013-10-29 11:00:32 -070055 private static final int REQUEST_ID_NONE = -1;
56
Igor Murashkin70725502013-06-25 20:27:06 +000057 // TODO: guard every function with if (!mRemoteDevice) check (if it was closed)
58 private ICameraDeviceUser mRemoteDevice;
59
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -070060 // Lock to synchronize cross-thread access to device public interface
61 private final Object mInterfaceLock = new Object();
Igor Murashkin70725502013-06-25 20:27:06 +000062 private final CameraDeviceCallbacks mCallbacks = new CameraDeviceCallbacks();
63
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070064 private final StateListener mDeviceListener;
Igor Murashkin0b27d342014-05-30 09:45:05 -070065 private volatile StateListener mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070066 private final Handler mDeviceHandler;
67
Igor Murashkin49b2b132014-06-18 19:03:00 -070068 private volatile boolean mClosing = false;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -070069 private boolean mInError = false;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070070 private boolean mIdle = true;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070071
Igor Murashkin21547d62014-06-04 15:21:42 -070072 /** map request IDs to listener/request data */
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070073 private final SparseArray<CaptureListenerHolder> mCaptureListenerMap =
74 new SparseArray<CaptureListenerHolder>();
Igor Murashkin70725502013-06-25 20:27:06 +000075
Ruben Brunkdecfe952013-10-29 11:00:32 -070076 private int mRepeatingRequestId = REQUEST_ID_NONE;
77 private final ArrayList<Integer> mRepeatingRequestIdDeletedList = new ArrayList<Integer>();
Igor Murashkin57ea59b2013-08-23 16:55:57 -070078 // Map stream IDs to Surfaces
79 private final SparseArray<Surface> mConfiguredOutputs = new SparseArray<Surface>();
Igor Murashkin70725502013-06-25 20:27:06 +000080
81 private final String mCameraId;
Ruben Brunk57493682014-05-27 18:58:08 -070082 private final CameraCharacteristics mCharacteristics;
Zhijun He83159152014-07-16 11:32:59 -070083 private final int mTotalPartialCount;
Igor Murashkin70725502013-06-25 20:27:06 +000084
Jianing Weid2c3a822014-03-27 18:27:43 -070085 /**
86 * A list tracking request and its expected last frame.
87 * Updated when calling ICameraDeviceUser methods.
88 */
89 private final List<SimpleEntry</*frameNumber*/Long, /*requestId*/Integer>>
90 mFrameNumberRequestPairs = new ArrayList<SimpleEntry<Long, Integer>>();
91
92 /**
93 * An object tracking received frame numbers.
94 * Updated when receiving callbacks from ICameraDeviceCallbacks.
95 */
96 private final FrameNumberTracker mFrameNumberTracker = new FrameNumberTracker();
97
Igor Murashkin0b27d342014-05-30 09:45:05 -070098 private CameraCaptureSessionImpl mCurrentSession;
99
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700100 // Runnables for all state transitions, except error, which needs the
101 // error code argument
102
103 private final Runnable mCallOnOpened = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700104 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700105 public void run() {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700106 StateListener sessionListener = null;
107 synchronized(mInterfaceLock) {
108 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700109
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700110 sessionListener = mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700111 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700112 if (sessionListener != null) {
113 sessionListener.onOpened(CameraDeviceImpl.this);
114 }
115 mDeviceListener.onOpened(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700116 }
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() {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700122 StateListener sessionListener = null;
123 synchronized(mInterfaceLock) {
124 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700125
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700126 sessionListener = mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700127 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700128 if (sessionListener != null) {
129 sessionListener.onUnconfigured(CameraDeviceImpl.this);
130 }
131 mDeviceListener.onUnconfigured(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700132 }
133 };
134
135 private final Runnable mCallOnActive = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700136 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700137 public void run() {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700138 StateListener sessionListener = null;
139 synchronized(mInterfaceLock) {
140 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700141
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700142 sessionListener = mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700143 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700144 if (sessionListener != null) {
145 sessionListener.onActive(CameraDeviceImpl.this);
146 }
147 mDeviceListener.onActive(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700148 }
149 };
150
151 private final Runnable mCallOnBusy = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700152 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700153 public void run() {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700154 StateListener sessionListener = null;
155 synchronized(mInterfaceLock) {
156 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700157
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700158 sessionListener = mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700159 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700160 if (sessionListener != null) {
161 sessionListener.onBusy(CameraDeviceImpl.this);
162 }
163 mDeviceListener.onBusy(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700164 }
165 };
166
167 private final Runnable mCallOnClosed = new Runnable() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700168 private boolean mClosedOnce = false;
169
Jianing Weid2c3a822014-03-27 18:27:43 -0700170 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700171 public void run() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700172 if (mClosedOnce) {
173 throw new AssertionError("Don't post #onClosed more than once");
174 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700175 StateListener sessionListener = null;
176 synchronized(mInterfaceLock) {
177 sessionListener = mSessionStateListener;
178 }
Igor Murashkin0b27d342014-05-30 09:45:05 -0700179 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700180 sessionListener.onClosed(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700181 }
Sol Boucher4b3f8002014-06-05 13:47:24 -0700182 mDeviceListener.onClosed(CameraDeviceImpl.this);
Igor Murashkin49b2b132014-06-18 19:03:00 -0700183 mClosedOnce = true;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700184 }
185 };
186
187 private final Runnable mCallOnIdle = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700188 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700189 public void run() {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700190 StateListener sessionListener = null;
191 synchronized(mInterfaceLock) {
192 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700193
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700194 sessionListener = mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700195 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700196 if (sessionListener != null) {
197 sessionListener.onIdle(CameraDeviceImpl.this);
198 }
199 mDeviceListener.onIdle(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700200 }
201 };
202
203 private final Runnable mCallOnDisconnected = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700204 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700205 public void run() {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700206 StateListener sessionListener = null;
207 synchronized(mInterfaceLock) {
208 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700209
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700210 sessionListener = mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700211 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700212 if (sessionListener != null) {
213 sessionListener.onDisconnected(CameraDeviceImpl.this);
214 }
215 mDeviceListener.onDisconnected(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700216 }
217 };
218
Igor Murashkin21547d62014-06-04 15:21:42 -0700219 public CameraDeviceImpl(String cameraId, StateListener listener, Handler handler,
Ruben Brunk57493682014-05-27 18:58:08 -0700220 CameraCharacteristics characteristics) {
Zhijun He83159152014-07-16 11:32:59 -0700221 if (cameraId == null || listener == null || handler == null || characteristics == null) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700222 throw new IllegalArgumentException("Null argument given");
223 }
Igor Murashkin70725502013-06-25 20:27:06 +0000224 mCameraId = cameraId;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700225 mDeviceListener = listener;
226 mDeviceHandler = handler;
Ruben Brunk57493682014-05-27 18:58:08 -0700227 mCharacteristics = characteristics;
Eino-Ville Talvalab72d1ef2014-04-28 13:21:18 -0700228
229 final int MAX_TAG_LEN = 23;
230 String tag = String.format("CameraDevice-JV-%s", mCameraId);
231 if (tag.length() > MAX_TAG_LEN) {
232 tag = tag.substring(0, MAX_TAG_LEN);
233 }
234 TAG = tag;
Zhijun Heecb323e2013-07-31 09:40:27 -0700235 DEBUG = Log.isLoggable(TAG, Log.DEBUG);
Zhijun He83159152014-07-16 11:32:59 -0700236
237 Integer partialCount =
238 mCharacteristics.get(CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT);
239 if (partialCount == null) {
240 // 1 means partial result is not supported.
241 mTotalPartialCount = 1;
242 } else {
243 mTotalPartialCount = partialCount;
244 }
Igor Murashkin70725502013-06-25 20:27:06 +0000245 }
246
247 public CameraDeviceCallbacks getCallbacks() {
248 return mCallbacks;
249 }
250
Igor Murashkin70725502013-06-25 20:27:06 +0000251 public void setRemoteDevice(ICameraDeviceUser remoteDevice) {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700252 synchronized(mInterfaceLock) {
253 // TODO: Move from decorator to direct binder-mediated exceptions
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700254 // If setRemoteFailure already called, do nothing
255 if (mInError) return;
256
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700257 mRemoteDevice = CameraBinderDecorator.newInstance(remoteDevice);
258
259 mDeviceHandler.post(mCallOnOpened);
260 mDeviceHandler.post(mCallOnUnconfigured);
261 }
Igor Murashkin70725502013-06-25 20:27:06 +0000262 }
263
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700264 /**
265 * Call to indicate failed connection to a remote camera device.
266 *
267 * <p>This places the camera device in the error state and informs the listener.
268 * Use in place of setRemoteDevice() when startup fails.</p>
269 */
270 public void setRemoteFailure(final CameraRuntimeException failure) {
271 int failureCode = StateListener.ERROR_CAMERA_DEVICE;
272 boolean failureIsError = true;
273
274 switch (failure.getReason()) {
275 case CameraAccessException.CAMERA_IN_USE:
276 failureCode = StateListener.ERROR_CAMERA_IN_USE;
277 break;
278 case CameraAccessException.MAX_CAMERAS_IN_USE:
279 failureCode = StateListener.ERROR_MAX_CAMERAS_IN_USE;
280 break;
281 case CameraAccessException.CAMERA_DISABLED:
282 failureCode = StateListener.ERROR_CAMERA_DISABLED;
283 break;
284 case CameraAccessException.CAMERA_DISCONNECTED:
285 failureIsError = false;
286 break;
287 case CameraAccessException.CAMERA_ERROR:
288 failureCode = StateListener.ERROR_CAMERA_DEVICE;
289 break;
290 default:
291 Log.wtf(TAG, "Unknown failure in opening camera device: " + failure.getReason());
292 break;
293 }
294 final int code = failureCode;
295 final boolean isError = failureIsError;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700296 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700297 mInError = true;
298 mDeviceHandler.post(new Runnable() {
Igor Murashkine1442202014-06-09 17:51:24 -0700299 @Override
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700300 public void run() {
301 if (isError) {
302 mDeviceListener.onError(CameraDeviceImpl.this, code);
303 } else {
304 mDeviceListener.onDisconnected(CameraDeviceImpl.this);
305 }
306 }
307 });
308 }
309 }
310
Igor Murashkin70725502013-06-25 20:27:06 +0000311 @Override
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700312 public String getId() {
313 return mCameraId;
314 }
315
Igor Murashkinbdf366c2014-07-25 16:54:20 -0700316 @Override
Igor Murashkin70725502013-06-25 20:27:06 +0000317 public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700318 // Treat a null input the same an empty list
319 if (outputs == null) {
320 outputs = new ArrayList<Surface>();
321 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700322 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700323 checkIfCameraClosedOrInError();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700324
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700325 HashSet<Surface> addSet = new HashSet<Surface>(outputs); // Streams to create
326 List<Integer> deleteList = new ArrayList<Integer>(); // Streams to delete
327
328 // Determine which streams need to be created, which to be deleted
329 for (int i = 0; i < mConfiguredOutputs.size(); ++i) {
330 int streamId = mConfiguredOutputs.keyAt(i);
331 Surface s = mConfiguredOutputs.valueAt(i);
332
333 if (!outputs.contains(s)) {
334 deleteList.add(streamId);
335 } else {
336 addSet.remove(s); // Don't create a stream previously created
337 }
338 }
339
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700340 mDeviceHandler.post(mCallOnBusy);
341 stopRepeating();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700342
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700343 try {
Ruben Brunkdecfe952013-10-29 11:00:32 -0700344 waitUntilIdle();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700345
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700346 mRemoteDevice.beginConfigure();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700347 // Delete all streams first (to free up HW resources)
348 for (Integer streamId : deleteList) {
349 mRemoteDevice.deleteStream(streamId);
350 mConfiguredOutputs.delete(streamId);
351 }
352
353 // Add all new streams
354 for (Surface s : addSet) {
Igor Murashkin70725502013-06-25 20:27:06 +0000355 // TODO: remove width,height,format since we are ignoring
356 // it.
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700357 int streamId = mRemoteDevice.createStream(0, 0, 0, s);
358 mConfiguredOutputs.put(streamId, s);
Igor Murashkin70725502013-06-25 20:27:06 +0000359 }
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700360
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700361 mRemoteDevice.endConfigure();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700362 } catch (CameraRuntimeException e) {
363 if (e.getReason() == CAMERA_IN_USE) {
364 throw new IllegalStateException("The camera is currently busy." +
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700365 " You must wait until the previous operation completes.");
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700366 }
367
368 throw e.asChecked();
369 } catch (RemoteException e) {
370 // impossible
371 return;
Igor Murashkin70725502013-06-25 20:27:06 +0000372 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700373
374 if (outputs.size() > 0) {
375 mDeviceHandler.post(mCallOnIdle);
376 } else {
377 mDeviceHandler.post(mCallOnUnconfigured);
378 }
Igor Murashkin70725502013-06-25 20:27:06 +0000379 }
380 }
381
382 @Override
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700383 public void createCaptureSession(List<Surface> outputs,
384 CameraCaptureSession.StateListener listener, Handler handler)
385 throws CameraAccessException {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700386 synchronized(mInterfaceLock) {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700387 if (DEBUG) {
388 Log.d(TAG, "createCaptureSession");
389 }
390
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700391 checkIfCameraClosedOrInError();
Igor Murashkin0b27d342014-05-30 09:45:05 -0700392
393 // TODO: we must be in UNCONFIGURED mode to begin with, or using another session
394
395 // TODO: dont block for this
396 boolean configureSuccess = true;
397 CameraAccessException pendingException = null;
398 try {
399 configureOutputs(outputs); // and then block until IDLE
400 } catch (CameraAccessException e) {
401 configureSuccess = false;
402 pendingException = e;
Igor Murashkine1442202014-06-09 17:51:24 -0700403 if (DEBUG) {
404 Log.v(TAG, "createCaptureSession - failed with exception ", e);
405 }
Igor Murashkin0b27d342014-05-30 09:45:05 -0700406 }
407
408 // Fire onConfigured if configureOutputs succeeded, fire onConfigureFailed otherwise.
409 CameraCaptureSessionImpl newSession =
410 new CameraCaptureSessionImpl(outputs, listener, handler, this, mDeviceHandler,
411 configureSuccess);
412
413 if (mCurrentSession != null) {
414 mCurrentSession.replaceSessionClose(newSession);
415 }
416
417 // TODO: wait until current session closes, then create the new session
418 mCurrentSession = newSession;
419
420 if (pendingException != null) {
421 throw pendingException;
422 }
423
424 mSessionStateListener = mCurrentSession.getDeviceStateListener();
425 }
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700426 }
427
428 @Override
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700429 public CaptureRequest.Builder createCaptureRequest(int templateType)
430 throws CameraAccessException {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700431 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700432 checkIfCameraClosedOrInError();
Igor Murashkin70725502013-06-25 20:27:06 +0000433
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700434 CameraMetadataNative templatedRequest = new CameraMetadataNative();
Igor Murashkin70725502013-06-25 20:27:06 +0000435
436 try {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700437 mRemoteDevice.createDefaultRequest(templateType, /*out*/templatedRequest);
Igor Murashkin70725502013-06-25 20:27:06 +0000438 } catch (CameraRuntimeException e) {
439 throw e.asChecked();
440 } catch (RemoteException e) {
441 // impossible
442 return null;
443 }
444
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700445 CaptureRequest.Builder builder =
446 new CaptureRequest.Builder(templatedRequest);
Igor Murashkin70725502013-06-25 20:27:06 +0000447
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700448 return builder;
Igor Murashkin70725502013-06-25 20:27:06 +0000449 }
450 }
451
Igor Murashkinbdf366c2014-07-25 16:54:20 -0700452 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700453 public int capture(CaptureRequest request, CaptureListener listener, Handler handler)
Igor Murashkin70725502013-06-25 20:27:06 +0000454 throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700455 if (DEBUG) {
456 Log.d(TAG, "calling capture");
457 }
458 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
459 requestList.add(request);
460 return submitCaptureRequest(requestList, listener, handler, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000461 }
462
Igor Murashkinbdf366c2014-07-25 16:54:20 -0700463 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700464 public int captureBurst(List<CaptureRequest> requests, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700465 Handler handler) throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700466 if (requests == null || requests.isEmpty()) {
467 throw new IllegalArgumentException("At least one request must be given");
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700468 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700469 return submitCaptureRequest(requests, listener, handler, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000470 }
471
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700472 /**
473 * This method checks lastFrameNumber returned from ICameraDeviceUser methods for
474 * starting and stopping repeating request and flushing.
475 *
476 * <p>If lastFrameNumber is NO_FRAMES_CAPTURED, it means that the request was never
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700477 * sent to HAL. Then onCaptureSequenceAborted is immediately triggered.
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700478 * If lastFrameNumber is non-negative, then the requestId and lastFrameNumber pair
479 * is added to the list mFrameNumberRequestPairs.</p>
480 *
481 * @param requestId the request ID of the current repeating request.
482 *
483 * @param lastFrameNumber last frame number returned from binder.
484 */
485 private void checkEarlyTriggerSequenceComplete(
486 final int requestId, final long lastFrameNumber) {
487 // lastFrameNumber being equal to NO_FRAMES_CAPTURED means that the request
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700488 // was never sent to HAL. Should trigger onCaptureSequenceAborted immediately.
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700489 if (lastFrameNumber == CaptureListener.NO_FRAMES_CAPTURED) {
490 final CaptureListenerHolder holder;
491 int index = mCaptureListenerMap.indexOfKey(requestId);
492 holder = (index >= 0) ? mCaptureListenerMap.valueAt(index) : null;
493 if (holder != null) {
494 mCaptureListenerMap.removeAt(index);
Jianing Weibaf0c652014-04-18 17:35:00 -0700495 if (DEBUG) {
496 Log.v(TAG, String.format(
497 "remove holder for requestId %d, "
498 + "because lastFrame is %d.",
499 requestId, lastFrameNumber));
500 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700501 }
502
503 if (holder != null) {
504 if (DEBUG) {
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700505 Log.v(TAG, "immediately trigger onCaptureSequenceAborted because"
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700506 + " request did not reach HAL");
507 }
508
509 Runnable resultDispatch = new Runnable() {
510 @Override
511 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700512 if (!CameraDeviceImpl.this.isClosed()) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700513 if (DEBUG) {
514 Log.d(TAG, String.format(
515 "early trigger sequence complete for request %d",
516 requestId));
517 }
518 if (lastFrameNumber < Integer.MIN_VALUE
519 || lastFrameNumber > Integer.MAX_VALUE) {
520 throw new AssertionError(lastFrameNumber + " cannot be cast to int");
521 }
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700522 holder.getListener().onCaptureSequenceAborted(
Igor Murashkin21547d62014-06-04 15:21:42 -0700523 CameraDeviceImpl.this,
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700524 requestId);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700525 }
526 }
527 };
528 holder.getHandler().post(resultDispatch);
529 } else {
530 Log.w(TAG, String.format(
531 "did not register listener to request %d",
532 requestId));
533 }
534 } else {
535 mFrameNumberRequestPairs.add(
536 new SimpleEntry<Long, Integer>(lastFrameNumber,
537 requestId));
538 }
539 }
540
Jianing Weid2c3a822014-03-27 18:27:43 -0700541 private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700542 Handler handler, boolean repeating) throws CameraAccessException {
543
544 // Need a valid handler, or current thread needs to have a looper, if
545 // listener is valid
Eino-Ville Talvala7875a882014-07-31 12:47:07 -0700546 handler = checkHandler(handler, listener);
Igor Murashkin70725502013-06-25 20:27:06 +0000547
Ruben Brunk7f2372b2014-07-02 11:05:08 -0700548 // Make sure that there all requests have at least 1 surface; all surfaces are non-null
549 for (CaptureRequest request : requestList) {
550 if (request.getTargets().isEmpty()) {
551 throw new IllegalArgumentException(
552 "Each request must have at least one Surface target");
553 }
554
555 for (Surface surface : request.getTargets()) {
556 if (surface == null) {
557 throw new IllegalArgumentException("Null Surface targets are not allowed");
558 }
559 }
560 }
561
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700562 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700563 checkIfCameraClosedOrInError();
Igor Murashkin70725502013-06-25 20:27:06 +0000564 int requestId;
565
Ruben Brunke73b41b2013-11-07 19:30:43 -0800566 if (repeating) {
567 stopRepeating();
568 }
569
Jianing Weid2c3a822014-03-27 18:27:43 -0700570 LongParcelable lastFrameNumberRef = new LongParcelable();
Igor Murashkin70725502013-06-25 20:27:06 +0000571 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700572 requestId = mRemoteDevice.submitRequestList(requestList, repeating,
573 /*out*/lastFrameNumberRef);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700574 if (DEBUG) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700575 Log.v(TAG, "last frame number " + lastFrameNumberRef.getNumber());
576 }
Igor Murashkin70725502013-06-25 20:27:06 +0000577 } catch (CameraRuntimeException e) {
578 throw e.asChecked();
579 } catch (RemoteException e) {
580 // impossible
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700581 return -1;
Igor Murashkin70725502013-06-25 20:27:06 +0000582 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700583
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700584 if (listener != null) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700585 mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener,
586 requestList, handler, repeating));
Jianing Weibaf0c652014-04-18 17:35:00 -0700587 } else {
588 if (DEBUG) {
589 Log.d(TAG, "Listen for request " + requestId + " is null");
590 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700591 }
Igor Murashkin70725502013-06-25 20:27:06 +0000592
Jianing Weid2c3a822014-03-27 18:27:43 -0700593 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700594
Igor Murashkin70725502013-06-25 20:27:06 +0000595 if (repeating) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700596 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700597 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700598 }
Ruben Brunkdecfe952013-10-29 11:00:32 -0700599 mRepeatingRequestId = requestId;
Jianing Weid2c3a822014-03-27 18:27:43 -0700600 } else {
601 mFrameNumberRequestPairs.add(
602 new SimpleEntry<Long, Integer>(lastFrameNumber, requestId));
Igor Murashkin70725502013-06-25 20:27:06 +0000603 }
604
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700605 if (mIdle) {
606 mDeviceHandler.post(mCallOnActive);
607 }
608 mIdle = false;
609
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700610 return requestId;
Igor Murashkin70725502013-06-25 20:27:06 +0000611 }
612 }
613
Igor Murashkinbdf366c2014-07-25 16:54:20 -0700614 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700615 public int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700616 Handler handler) throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700617 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
618 requestList.add(request);
619 return submitCaptureRequest(requestList, listener, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000620 }
621
Igor Murashkinbdf366c2014-07-25 16:54:20 -0700622 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700623 public int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700624 Handler handler) throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700625 if (requests == null || requests.isEmpty()) {
626 throw new IllegalArgumentException("At least one request must be given");
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700627 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700628 return submitCaptureRequest(requests, listener, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000629 }
630
Igor Murashkinbdf366c2014-07-25 16:54:20 -0700631 @Override
Igor Murashkin70725502013-06-25 20:27:06 +0000632 public void stopRepeating() throws CameraAccessException {
633
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700634 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700635 checkIfCameraClosedOrInError();
Ruben Brunkdecfe952013-10-29 11:00:32 -0700636 if (mRepeatingRequestId != REQUEST_ID_NONE) {
637
638 int requestId = mRepeatingRequestId;
639 mRepeatingRequestId = REQUEST_ID_NONE;
640
641 // Queue for deletion after in-flight requests finish
Zhijun He1a9b6462014-03-31 16:11:33 -0700642 if (mCaptureListenerMap.get(requestId) != null) {
643 mRepeatingRequestIdDeletedList.add(requestId);
644 }
Igor Murashkin70725502013-06-25 20:27:06 +0000645
646 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700647 LongParcelable lastFrameNumberRef = new LongParcelable();
648 mRemoteDevice.cancelRequest(requestId, /*out*/lastFrameNumberRef);
649 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700650
651 checkEarlyTriggerSequenceComplete(requestId, lastFrameNumber);
652
Igor Murashkin70725502013-06-25 20:27:06 +0000653 } catch (CameraRuntimeException e) {
654 throw e.asChecked();
655 } catch (RemoteException e) {
656 // impossible
657 return;
658 }
659 }
660 }
661 }
662
Zhijun Hed842fcd2013-12-26 14:14:04 -0800663 private void waitUntilIdle() throws CameraAccessException {
Zhijun He7f4d3142013-07-23 07:54:38 -0700664
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700665 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700666 checkIfCameraClosedOrInError();
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700667
Ruben Brunkdecfe952013-10-29 11:00:32 -0700668 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Zhijun He7f4d3142013-07-23 07:54:38 -0700669 throw new IllegalStateException("Active repeating request ongoing");
670 }
Zhijun He7f4d3142013-07-23 07:54:38 -0700671 try {
672 mRemoteDevice.waitUntilIdle();
673 } catch (CameraRuntimeException e) {
674 throw e.asChecked();
675 } catch (RemoteException e) {
676 // impossible
677 return;
678 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700679 }
Igor Murashkin70725502013-06-25 20:27:06 +0000680 }
681
Igor Murashkinbdf366c2014-07-25 16:54:20 -0700682 @Override
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700683 public void flush() throws CameraAccessException {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700684 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700685 checkIfCameraClosedOrInError();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700686
687 mDeviceHandler.post(mCallOnBusy);
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700688 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700689 LongParcelable lastFrameNumberRef = new LongParcelable();
690 mRemoteDevice.flush(/*out*/lastFrameNumberRef);
691 if (mRepeatingRequestId != REQUEST_ID_NONE) {
692 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700693 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700694 mRepeatingRequestId = REQUEST_ID_NONE;
695 }
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700696 } catch (CameraRuntimeException e) {
697 throw e.asChecked();
698 } catch (RemoteException e) {
699 // impossible
700 return;
701 }
702 }
703 }
704
705 @Override
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700706 public void close() {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700707 synchronized (mInterfaceLock) {
Igor Murashkin70725502013-06-25 20:27:06 +0000708 try {
Igor Murashkin2a3eced2013-08-28 17:35:10 -0700709 if (mRemoteDevice != null) {
710 mRemoteDevice.disconnect();
711 }
Igor Murashkin70725502013-06-25 20:27:06 +0000712 } catch (CameraRuntimeException e) {
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700713 Log.e(TAG, "Exception while closing: ", e.asChecked());
Igor Murashkin70725502013-06-25 20:27:06 +0000714 } catch (RemoteException e) {
715 // impossible
716 }
717
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700718 // Only want to fire the onClosed callback once;
719 // either a normal close where the remote device is valid
720 // or a close after a startup error (no remote device but in error state)
721 if (mRemoteDevice != null || mInError) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700722 mDeviceHandler.post(mCallOnClosed);
723 }
Igor Murashkin70725502013-06-25 20:27:06 +0000724
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700725 mRemoteDevice = null;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700726 mInError = false;
Igor Murashkin70725502013-06-25 20:27:06 +0000727 }
728 }
729
730 @Override
731 protected void finalize() throws Throwable {
732 try {
733 close();
Igor Murashkin70725502013-06-25 20:27:06 +0000734 }
735 finally {
736 super.finalize();
737 }
738 }
739
740 static class CaptureListenerHolder {
741
742 private final boolean mRepeating;
743 private final CaptureListener mListener;
Jianing Weid2c3a822014-03-27 18:27:43 -0700744 private final List<CaptureRequest> mRequestList;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700745 private final Handler mHandler;
Igor Murashkin70725502013-06-25 20:27:06 +0000746
Jianing Weid2c3a822014-03-27 18:27:43 -0700747 CaptureListenerHolder(CaptureListener listener, List<CaptureRequest> requestList,
748 Handler handler, boolean repeating) {
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700749 if (listener == null || handler == null) {
750 throw new UnsupportedOperationException(
751 "Must have a valid handler and a valid listener");
752 }
Igor Murashkin70725502013-06-25 20:27:06 +0000753 mRepeating = repeating;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700754 mHandler = handler;
Jianing Weid2c3a822014-03-27 18:27:43 -0700755 mRequestList = new ArrayList<CaptureRequest>(requestList);
Igor Murashkin70725502013-06-25 20:27:06 +0000756 mListener = listener;
757 }
758
759 public boolean isRepeating() {
760 return mRepeating;
761 }
762
763 public CaptureListener getListener() {
764 return mListener;
765 }
766
Jianing Weid2c3a822014-03-27 18:27:43 -0700767 public CaptureRequest getRequest(int subsequenceId) {
768 if (subsequenceId >= mRequestList.size()) {
769 throw new IllegalArgumentException(
770 String.format(
771 "Requested subsequenceId %d is larger than request list size %d.",
772 subsequenceId, mRequestList.size()));
773 } else {
774 if (subsequenceId < 0) {
775 throw new IllegalArgumentException(String.format(
776 "Requested subsequenceId %d is negative", subsequenceId));
777 } else {
778 return mRequestList.get(subsequenceId);
779 }
780 }
781 }
782
Igor Murashkin70725502013-06-25 20:27:06 +0000783 public CaptureRequest getRequest() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700784 return getRequest(0);
Igor Murashkin70725502013-06-25 20:27:06 +0000785 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700786
787 public Handler getHandler() {
788 return mHandler;
789 }
790
Igor Murashkin70725502013-06-25 20:27:06 +0000791 }
792
Jianing Weid2c3a822014-03-27 18:27:43 -0700793 /**
794 * This class tracks the last frame number for submitted requests.
795 */
796 public class FrameNumberTracker {
797
798 private long mCompletedFrameNumber = -1;
799 private final TreeSet<Long> mFutureErrorSet = new TreeSet<Long>();
800
801 private void update() {
802 Iterator<Long> iter = mFutureErrorSet.iterator();
803 while (iter.hasNext()) {
804 long errorFrameNumber = iter.next();
805 if (errorFrameNumber == mCompletedFrameNumber + 1) {
806 mCompletedFrameNumber++;
807 iter.remove();
808 } else {
809 break;
810 }
811 }
812 }
813
814 /**
815 * This function is called every time when a result or an error is received.
816 * @param frameNumber: the frame number corresponding to the result or error
817 * @param isError: true if it is an error, false if it is not an error
818 */
819 public void updateTracker(long frameNumber, boolean isError) {
820 if (isError) {
821 mFutureErrorSet.add(frameNumber);
822 } else {
823 /**
824 * HAL cannot send an OnResultReceived for frame N unless it knows for
825 * sure that all frames prior to N have either errored out or completed.
826 * So if the current frame is not an error, then all previous frames
827 * should have arrived. The following line checks whether this holds.
828 */
829 if (frameNumber != mCompletedFrameNumber + 1) {
Zhijun He22589b42014-05-01 10:37:36 -0700830 Log.e(TAG, String.format(
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700831 "result frame number %d comes out of order, should be %d + 1",
832 frameNumber, mCompletedFrameNumber));
Jianing Weid2c3a822014-03-27 18:27:43 -0700833 }
834 mCompletedFrameNumber++;
835 }
836 update();
837 }
838
839 public long getCompletedFrameNumber() {
840 return mCompletedFrameNumber;
841 }
842
843 }
844
845 private void checkAndFireSequenceComplete() {
846 long completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber();
847 Iterator<SimpleEntry<Long, Integer> > iter = mFrameNumberRequestPairs.iterator();
848 while (iter.hasNext()) {
849 final SimpleEntry<Long, Integer> frameNumberRequestPair = iter.next();
850 if (frameNumberRequestPair.getKey() <= completedFrameNumber) {
851
852 // remove request from mCaptureListenerMap
853 final int requestId = frameNumberRequestPair.getValue();
854 final CaptureListenerHolder holder;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700855 synchronized(mInterfaceLock) {
856 if (mRemoteDevice == null) {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700857 Log.w(TAG, "Camera closed while checking sequences");
858 return;
859 }
860
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700861 int index = mCaptureListenerMap.indexOfKey(requestId);
862 holder = (index >= 0) ? mCaptureListenerMap.valueAt(index)
Jianing Weid2c3a822014-03-27 18:27:43 -0700863 : null;
864 if (holder != null) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700865 mCaptureListenerMap.removeAt(index);
866 if (DEBUG) {
867 Log.v(TAG, String.format(
868 "remove holder for requestId %d, "
869 + "because lastFrame %d is <= %d",
870 requestId, frameNumberRequestPair.getKey(),
871 completedFrameNumber));
872 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700873 }
874 }
875 iter.remove();
876
877 // Call onCaptureSequenceCompleted
878 if (holder != null) {
879 Runnable resultDispatch = new Runnable() {
880 @Override
881 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700882 if (!CameraDeviceImpl.this.isClosed()){
Jianing Weid2c3a822014-03-27 18:27:43 -0700883 if (DEBUG) {
884 Log.d(TAG, String.format(
885 "fire sequence complete for request %d",
886 requestId));
887 }
888
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700889 long lastFrameNumber = frameNumberRequestPair.getKey();
890 if (lastFrameNumber < Integer.MIN_VALUE
891 || lastFrameNumber > Integer.MAX_VALUE) {
892 throw new AssertionError(lastFrameNumber
893 + " cannot be cast to int");
894 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700895 holder.getListener().onCaptureSequenceCompleted(
Igor Murashkin21547d62014-06-04 15:21:42 -0700896 CameraDeviceImpl.this,
Jianing Weid2c3a822014-03-27 18:27:43 -0700897 requestId,
Igor Murashkindb075af2014-05-21 10:07:08 -0700898 lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700899 }
900 }
901 };
902 holder.getHandler().post(resultDispatch);
903 }
904
905 }
906 }
907 }
908
Zhijun Heecb323e2013-07-31 09:40:27 -0700909 public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
Igor Murashkin70725502013-06-25 20:27:06 +0000910
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700911 //
912 // Constants below need to be kept up-to-date with
913 // frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
914 //
915
916 //
917 // Error codes for onCameraError
918 //
919
920 /**
921 * Camera has been disconnected
922 */
923 static final int ERROR_CAMERA_DISCONNECTED = 0;
924
925 /**
926 * Camera has encountered a device-level error
927 * Matches CameraDevice.StateListener#ERROR_CAMERA_DEVICE
928 */
929 static final int ERROR_CAMERA_DEVICE = 1;
930
931 /**
932 * Camera has encountered a service-level error
933 * Matches CameraDevice.StateListener#ERROR_CAMERA_SERVICE
934 */
935 static final int ERROR_CAMERA_SERVICE = 2;
936
Igor Murashkin70725502013-06-25 20:27:06 +0000937 @Override
938 public IBinder asBinder() {
939 return this;
940 }
941
Igor Murashkin70725502013-06-25 20:27:06 +0000942 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -0700943 public void onCameraError(final int errorCode, CaptureResultExtras resultExtras) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700944 Runnable r = null;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700945
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700946 synchronized(mInterfaceLock) {
947 if (mRemoteDevice == null) {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700948 return; // Camera already closed
949 }
950
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700951 mInError = true;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700952 switch (errorCode) {
953 case ERROR_CAMERA_DISCONNECTED:
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700954 r = mCallOnDisconnected;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700955 break;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700956 default:
957 Log.e(TAG, "Unknown error from camera device: " + errorCode);
958 // no break
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700959 case ERROR_CAMERA_DEVICE:
960 case ERROR_CAMERA_SERVICE:
961 r = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700962 @Override
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700963 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700964 if (!CameraDeviceImpl.this.isClosed()) {
965 mDeviceListener.onError(CameraDeviceImpl.this, errorCode);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700966 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700967 }
968 };
969 break;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700970 }
Igor Murashkin21547d62014-06-04 15:21:42 -0700971 CameraDeviceImpl.this.mDeviceHandler.post(r);
Jianing Weid2c3a822014-03-27 18:27:43 -0700972
Igor Murashkin49b2b132014-06-18 19:03:00 -0700973 // Fire onCaptureSequenceCompleted
974 if (DEBUG) {
975 Log.v(TAG, String.format("got error frame %d", resultExtras.getFrameNumber()));
976 }
977 mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(), /*error*/true);
978 checkAndFireSequenceComplete();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700979 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700980 }
981
982 @Override
983 public void onCameraIdle() {
984 if (DEBUG) {
985 Log.d(TAG, "Camera now idle");
986 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700987 synchronized(mInterfaceLock) {
988 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700989
Igor Murashkin21547d62014-06-04 15:21:42 -0700990 if (!CameraDeviceImpl.this.mIdle) {
991 CameraDeviceImpl.this.mDeviceHandler.post(mCallOnIdle);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700992 }
Igor Murashkin21547d62014-06-04 15:21:42 -0700993 CameraDeviceImpl.this.mIdle = true;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700994 }
995 }
996
997 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -0700998 public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) {
999 int requestId = resultExtras.getRequestId();
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001000 if (DEBUG) {
1001 Log.d(TAG, "Capture started for id " + requestId);
1002 }
1003 final CaptureListenerHolder holder;
1004
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001005 synchronized(mInterfaceLock) {
1006 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -07001007
1008 // Get the listener for this frame ID, if there is one
Igor Murashkin21547d62014-06-04 15:21:42 -07001009 holder = CameraDeviceImpl.this.mCaptureListenerMap.get(requestId);
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001010
Igor Murashkin49b2b132014-06-18 19:03:00 -07001011 if (holder == null) {
1012 return;
1013 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001014
Igor Murashkin49b2b132014-06-18 19:03:00 -07001015 if (isClosed()) return;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001016
Igor Murashkin49b2b132014-06-18 19:03:00 -07001017 // Dispatch capture start notice
1018 holder.getHandler().post(
1019 new Runnable() {
1020 @Override
1021 public void run() {
1022 if (!CameraDeviceImpl.this.isClosed()) {
1023 holder.getListener().onCaptureStarted(
1024 CameraDeviceImpl.this,
1025 holder.getRequest(resultExtras.getSubsequenceId()),
1026 timestamp);
1027 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001028 }
Igor Murashkin49b2b132014-06-18 19:03:00 -07001029 });
1030
1031 }
Igor Murashkin70725502013-06-25 20:27:06 +00001032 }
1033
1034 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -07001035 public void onResultReceived(CameraMetadataNative result,
1036 CaptureResultExtras resultExtras) throws RemoteException {
Ruben Brunk57493682014-05-27 18:58:08 -07001037
Jianing Weid2c3a822014-03-27 18:27:43 -07001038 int requestId = resultExtras.getRequestId();
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001039 long frameNumber = resultExtras.getFrameNumber();
1040
Zhijun Heecb323e2013-07-31 09:40:27 -07001041 if (DEBUG) {
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001042 Log.v(TAG, "Received result frame " + frameNumber + " for id "
Jianing Weibaf0c652014-04-18 17:35:00 -07001043 + requestId);
Zhijun Heecb323e2013-07-31 09:40:27 -07001044 }
Ruben Brunk57493682014-05-27 18:58:08 -07001045
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001046 synchronized(mInterfaceLock) {
1047 if (mRemoteDevice == null) return; // Camera already closed
Ruben Brunk57493682014-05-27 18:58:08 -07001048
Igor Murashkin49b2b132014-06-18 19:03:00 -07001049 // TODO: Handle CameraCharacteristics access from CaptureResult correctly.
1050 result.set(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE,
1051 getCharacteristics().get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE));
Ruben Brunk57493682014-05-27 18:58:08 -07001052
Igor Murashkin49b2b132014-06-18 19:03:00 -07001053 final CaptureListenerHolder holder =
1054 CameraDeviceImpl.this.mCaptureListenerMap.get(requestId);
Igor Murashkin70725502013-06-25 20:27:06 +00001055
Zhijun He83159152014-07-16 11:32:59 -07001056 boolean isPartialResult =
1057 (resultExtras.getPartialResultCount() < mTotalPartialCount);
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001058
Igor Murashkin49b2b132014-06-18 19:03:00 -07001059 // Update tracker (increment counter) when it's not a partial result.
Zhijun He83159152014-07-16 11:32:59 -07001060 if (!isPartialResult) {
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001061 mFrameNumberTracker.updateTracker(frameNumber,
Igor Murashkin49b2b132014-06-18 19:03:00 -07001062 /*error*/false);
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001063 }
Igor Murashkin70725502013-06-25 20:27:06 +00001064
Igor Murashkin49b2b132014-06-18 19:03:00 -07001065 // Check if we have a listener for this
1066 if (holder == null) {
1067 if (DEBUG) {
1068 Log.d(TAG,
1069 "holder is null, early return at frame "
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001070 + frameNumber);
Igor Murashkin49b2b132014-06-18 19:03:00 -07001071 }
1072 return;
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001073 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001074
Igor Murashkin49b2b132014-06-18 19:03:00 -07001075 if (isClosed()) {
1076 if (DEBUG) {
1077 Log.d(TAG,
1078 "camera is closed, early return at frame "
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001079 + frameNumber);
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001080 }
Igor Murashkin49b2b132014-06-18 19:03:00 -07001081 return;
1082 }
Igor Murashkindb075af2014-05-21 10:07:08 -07001083
Igor Murashkin49b2b132014-06-18 19:03:00 -07001084 final CaptureRequest request = holder.getRequest(resultExtras.getSubsequenceId());
1085
1086
1087 Runnable resultDispatch = null;
1088
1089 // Either send a partial result or the final capture completed result
Zhijun He83159152014-07-16 11:32:59 -07001090 if (isPartialResult) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001091 final CaptureResult resultAsCapture =
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001092 new CaptureResult(result, request, resultExtras);
Igor Murashkin49b2b132014-06-18 19:03:00 -07001093
1094 // Partial result
1095 resultDispatch = new Runnable() {
1096 @Override
1097 public void run() {
1098 if (!CameraDeviceImpl.this.isClosed()){
Zhijun Hefac77c42014-07-18 14:20:48 -07001099 holder.getListener().onCaptureProgressed(
Igor Murashkin49b2b132014-06-18 19:03:00 -07001100 CameraDeviceImpl.this,
1101 request,
1102 resultAsCapture);
1103 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001104 }
Igor Murashkin49b2b132014-06-18 19:03:00 -07001105 };
1106 } else {
1107 final TotalCaptureResult resultAsCapture =
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001108 new TotalCaptureResult(result, request, resultExtras);
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001109
Igor Murashkin49b2b132014-06-18 19:03:00 -07001110 // Final capture result
1111 resultDispatch = new Runnable() {
1112 @Override
1113 public void run() {
1114 if (!CameraDeviceImpl.this.isClosed()){
1115 holder.getListener().onCaptureCompleted(
1116 CameraDeviceImpl.this,
1117 request,
1118 resultAsCapture);
1119 }
1120 }
1121 };
1122 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001123
Igor Murashkin49b2b132014-06-18 19:03:00 -07001124 holder.getHandler().post(resultDispatch);
1125
1126 // Fire onCaptureSequenceCompleted
Zhijun He83159152014-07-16 11:32:59 -07001127 if (!isPartialResult) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001128 checkAndFireSequenceComplete();
1129 }
1130
Jianing Weid2c3a822014-03-27 18:27:43 -07001131 }
Igor Murashkin70725502013-06-25 20:27:06 +00001132 }
1133
1134 }
1135
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001136 /**
Igor Murashkin0b27d342014-05-30 09:45:05 -07001137 * Default handler management.
1138 *
1139 * <p>
1140 * If handler is null, get the current thread's
1141 * Looper to create a Handler with. If no looper exists, throw {@code IllegalArgumentException}.
1142 * </p>
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001143 */
Igor Murashkin0b27d342014-05-30 09:45:05 -07001144 static Handler checkHandler(Handler handler) {
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001145 if (handler == null) {
1146 Looper looper = Looper.myLooper();
1147 if (looper == null) {
1148 throw new IllegalArgumentException(
1149 "No handler given, and current thread has no looper!");
1150 }
1151 handler = new Handler(looper);
1152 }
1153 return handler;
1154 }
1155
Eino-Ville Talvala7875a882014-07-31 12:47:07 -07001156 /**
1157 * Default handler management, conditional on there being a listener.
1158 *
1159 * <p>If the listener isn't null, check the handler, otherwise pass it through.</p>
1160 */
1161 static <T> Handler checkHandler(Handler handler, T listener) {
1162 if (listener != null) {
1163 return checkHandler(handler);
1164 }
1165 return handler;
1166 }
1167
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -07001168 private void checkIfCameraClosedOrInError() throws CameraAccessException {
1169 if (mInError) {
1170 throw new CameraAccessException(CameraAccessException.CAMERA_ERROR,
1171 "The camera device has encountered a serious error");
1172 }
Zhijun He7f4d3142013-07-23 07:54:38 -07001173 if (mRemoteDevice == null) {
1174 throw new IllegalStateException("CameraDevice was already closed");
1175 }
1176 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001177
Igor Murashkin49b2b132014-06-18 19:03:00 -07001178 /** Whether the camera device has started to close (may not yet have finished) */
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001179 private boolean isClosed() {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001180 return mClosing;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001181 }
Ruben Brunk57493682014-05-27 18:58:08 -07001182
1183 private CameraCharacteristics getCharacteristics() {
1184 return mCharacteristics;
1185 }
Igor Murashkin70725502013-06-25 20:27:06 +00001186}