blob: e55ee6777740c12c316679efec5c103c55378fab [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;
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() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700106 try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
107 if (scopedLock == null) return; // Camera already closed
108
Igor Murashkin0b27d342014-05-30 09:45:05 -0700109 StateListener sessionListener = mSessionStateListener;
110 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700111 sessionListener.onOpened(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700112 }
Sol Boucher4b3f8002014-06-05 13:47:24 -0700113 mDeviceListener.onOpened(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700114 }
115 }
116 };
117
118 private final Runnable mCallOnUnconfigured = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700119 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700120 public void run() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700121 try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
122 if (scopedLock == null) return; // Camera already closed
123
Igor Murashkin0b27d342014-05-30 09:45:05 -0700124 StateListener sessionListener = mSessionStateListener;
125 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700126 sessionListener.onUnconfigured(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700127 }
Sol Boucher4b3f8002014-06-05 13:47:24 -0700128 mDeviceListener.onUnconfigured(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700129 }
130 }
131 };
132
133 private final Runnable mCallOnActive = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700134 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700135 public void run() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700136 try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
137 if (scopedLock == null) return; // Camera already closed
138
Igor Murashkin0b27d342014-05-30 09:45:05 -0700139 StateListener sessionListener = mSessionStateListener;
140 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700141 sessionListener.onActive(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700142 }
Sol Boucher4b3f8002014-06-05 13:47:24 -0700143 mDeviceListener.onActive(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700144 }
145 }
146 };
147
148 private final Runnable mCallOnBusy = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700149 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700150 public void run() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700151 try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
152 if (scopedLock == null) return; // Camera already closed
153
Igor Murashkin0b27d342014-05-30 09:45:05 -0700154 StateListener sessionListener = mSessionStateListener;
155 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700156 sessionListener.onBusy(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700157 }
Sol Boucher4b3f8002014-06-05 13:47:24 -0700158 mDeviceListener.onBusy(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700159 }
160 }
161 };
162
163 private final Runnable mCallOnClosed = new Runnable() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700164 private boolean mClosedOnce = false;
165
Jianing Weid2c3a822014-03-27 18:27:43 -0700166 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700167 public void run() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700168 if (mClosedOnce) {
169 throw new AssertionError("Don't post #onClosed more than once");
170 }
171
Igor Murashkin0b27d342014-05-30 09:45:05 -0700172 StateListener sessionListener = mSessionStateListener;
173 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700174 sessionListener.onClosed(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700175 }
Sol Boucher4b3f8002014-06-05 13:47:24 -0700176 mDeviceListener.onClosed(CameraDeviceImpl.this);
Igor Murashkin49b2b132014-06-18 19:03:00 -0700177 mClosedOnce = true;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700178 }
179 };
180
181 private final Runnable mCallOnIdle = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700182 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700183 public void run() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700184 try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
185 if (scopedLock == null) return; // Camera already closed
186
Igor Murashkin0b27d342014-05-30 09:45:05 -0700187 StateListener sessionListener = mSessionStateListener;
188 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700189 sessionListener.onIdle(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700190 }
Sol Boucher4b3f8002014-06-05 13:47:24 -0700191 mDeviceListener.onIdle(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700192 }
193 }
194 };
195
196 private final Runnable mCallOnDisconnected = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700197 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700198 public void run() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700199 try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
200 if (scopedLock == null) return; // Camera already closed
201
Igor Murashkin0b27d342014-05-30 09:45:05 -0700202 StateListener sessionListener = mSessionStateListener;
203 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700204 sessionListener.onDisconnected(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700205 }
Sol Boucher4b3f8002014-06-05 13:47:24 -0700206 mDeviceListener.onDisconnected(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700207 }
208 }
209 };
210
Igor Murashkin21547d62014-06-04 15:21:42 -0700211 public CameraDeviceImpl(String cameraId, StateListener listener, Handler handler,
Ruben Brunk57493682014-05-27 18:58:08 -0700212 CameraCharacteristics characteristics) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700213 if (cameraId == null || listener == null || handler == null) {
214 throw new IllegalArgumentException("Null argument given");
215 }
Igor Murashkin70725502013-06-25 20:27:06 +0000216 mCameraId = cameraId;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700217 mDeviceListener = listener;
218 mDeviceHandler = handler;
Ruben Brunk57493682014-05-27 18:58:08 -0700219 mCharacteristics = characteristics;
Igor Murashkin49b2b132014-06-18 19:03:00 -0700220 mCloseLock = new CloseableLock(/*name*/"CD-" + mCameraId);
Eino-Ville Talvalab72d1ef2014-04-28 13:21:18 -0700221
222 final int MAX_TAG_LEN = 23;
223 String tag = String.format("CameraDevice-JV-%s", mCameraId);
224 if (tag.length() > MAX_TAG_LEN) {
225 tag = tag.substring(0, MAX_TAG_LEN);
226 }
227 TAG = tag;
Zhijun Heecb323e2013-07-31 09:40:27 -0700228 DEBUG = Log.isLoggable(TAG, Log.DEBUG);
Igor Murashkin70725502013-06-25 20:27:06 +0000229 }
230
231 public CameraDeviceCallbacks getCallbacks() {
232 return mCallbacks;
233 }
234
Igor Murashkin70725502013-06-25 20:27:06 +0000235 public void setRemoteDevice(ICameraDeviceUser remoteDevice) {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700236 try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
Eino-Ville Talvala5afd3e92013-08-21 10:37:04 -0700237 // TODO: Move from decorator to direct binder-mediated exceptions
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700238 // If setRemoteFailure already called, do nothing
239 if (mInError) return;
240
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700241 mRemoteDevice = CameraBinderDecorator.newInstance(remoteDevice);
242
243 mDeviceHandler.post(mCallOnOpened);
244 mDeviceHandler.post(mCallOnUnconfigured);
245 }
Igor Murashkin70725502013-06-25 20:27:06 +0000246 }
247
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700248 /**
249 * Call to indicate failed connection to a remote camera device.
250 *
251 * <p>This places the camera device in the error state and informs the listener.
252 * Use in place of setRemoteDevice() when startup fails.</p>
253 */
254 public void setRemoteFailure(final CameraRuntimeException failure) {
255 int failureCode = StateListener.ERROR_CAMERA_DEVICE;
256 boolean failureIsError = true;
257
258 switch (failure.getReason()) {
259 case CameraAccessException.CAMERA_IN_USE:
260 failureCode = StateListener.ERROR_CAMERA_IN_USE;
261 break;
262 case CameraAccessException.MAX_CAMERAS_IN_USE:
263 failureCode = StateListener.ERROR_MAX_CAMERAS_IN_USE;
264 break;
265 case CameraAccessException.CAMERA_DISABLED:
266 failureCode = StateListener.ERROR_CAMERA_DISABLED;
267 break;
268 case CameraAccessException.CAMERA_DISCONNECTED:
269 failureIsError = false;
270 break;
271 case CameraAccessException.CAMERA_ERROR:
272 failureCode = StateListener.ERROR_CAMERA_DEVICE;
273 break;
274 default:
275 Log.wtf(TAG, "Unknown failure in opening camera device: " + failure.getReason());
276 break;
277 }
278 final int code = failureCode;
279 final boolean isError = failureIsError;
Igor Murashkin49b2b132014-06-18 19:03:00 -0700280 try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
281 if (scopedLock == null) return; // Camera already closed, can't go to error state
282
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700283 mInError = true;
284 mDeviceHandler.post(new Runnable() {
Igor Murashkine1442202014-06-09 17:51:24 -0700285 @Override
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700286 public void run() {
287 if (isError) {
288 mDeviceListener.onError(CameraDeviceImpl.this, code);
289 } else {
290 mDeviceListener.onDisconnected(CameraDeviceImpl.this);
291 }
292 }
293 });
294 }
295 }
296
Igor Murashkin70725502013-06-25 20:27:06 +0000297 @Override
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700298 public String getId() {
299 return mCameraId;
300 }
301
302 @Override
Igor Murashkin70725502013-06-25 20:27:06 +0000303 public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700304 // Treat a null input the same an empty list
305 if (outputs == null) {
306 outputs = new ArrayList<Surface>();
307 }
Igor Murashkin49b2b132014-06-18 19:03:00 -0700308 try (ScopedLock scopedLock = mCloseLock.acquireExclusiveLock()) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700309 checkIfCameraClosedOrInError();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700310
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700311 HashSet<Surface> addSet = new HashSet<Surface>(outputs); // Streams to create
312 List<Integer> deleteList = new ArrayList<Integer>(); // Streams to delete
313
314 // Determine which streams need to be created, which to be deleted
315 for (int i = 0; i < mConfiguredOutputs.size(); ++i) {
316 int streamId = mConfiguredOutputs.keyAt(i);
317 Surface s = mConfiguredOutputs.valueAt(i);
318
319 if (!outputs.contains(s)) {
320 deleteList.add(streamId);
321 } else {
322 addSet.remove(s); // Don't create a stream previously created
323 }
324 }
325
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700326 mDeviceHandler.post(mCallOnBusy);
327 stopRepeating();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700328
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700329 try {
Ruben Brunkdecfe952013-10-29 11:00:32 -0700330 waitUntilIdle();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700331
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700332 mRemoteDevice.beginConfigure();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700333 // Delete all streams first (to free up HW resources)
334 for (Integer streamId : deleteList) {
335 mRemoteDevice.deleteStream(streamId);
336 mConfiguredOutputs.delete(streamId);
337 }
338
339 // Add all new streams
340 for (Surface s : addSet) {
Igor Murashkin70725502013-06-25 20:27:06 +0000341 // TODO: remove width,height,format since we are ignoring
342 // it.
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700343 int streamId = mRemoteDevice.createStream(0, 0, 0, s);
344 mConfiguredOutputs.put(streamId, s);
Igor Murashkin70725502013-06-25 20:27:06 +0000345 }
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700346
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700347 mRemoteDevice.endConfigure();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700348 } catch (CameraRuntimeException e) {
349 if (e.getReason() == CAMERA_IN_USE) {
350 throw new IllegalStateException("The camera is currently busy." +
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700351 " You must wait until the previous operation completes.");
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700352 }
353
354 throw e.asChecked();
355 } catch (RemoteException e) {
356 // impossible
357 return;
Igor Murashkin70725502013-06-25 20:27:06 +0000358 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700359
360 if (outputs.size() > 0) {
361 mDeviceHandler.post(mCallOnIdle);
362 } else {
363 mDeviceHandler.post(mCallOnUnconfigured);
364 }
Igor Murashkin70725502013-06-25 20:27:06 +0000365 }
366 }
367
368 @Override
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700369 public void createCaptureSession(List<Surface> outputs,
370 CameraCaptureSession.StateListener listener, Handler handler)
371 throws CameraAccessException {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700372 try (ScopedLock scopedLock = mCloseLock.acquireExclusiveLock()) {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700373 if (DEBUG) {
374 Log.d(TAG, "createCaptureSession");
375 }
376
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700377 checkIfCameraClosedOrInError();
Igor Murashkin0b27d342014-05-30 09:45:05 -0700378
379 // TODO: we must be in UNCONFIGURED mode to begin with, or using another session
380
381 // TODO: dont block for this
382 boolean configureSuccess = true;
383 CameraAccessException pendingException = null;
384 try {
385 configureOutputs(outputs); // and then block until IDLE
386 } catch (CameraAccessException e) {
387 configureSuccess = false;
388 pendingException = e;
Igor Murashkine1442202014-06-09 17:51:24 -0700389 if (DEBUG) {
390 Log.v(TAG, "createCaptureSession - failed with exception ", e);
391 }
Igor Murashkin0b27d342014-05-30 09:45:05 -0700392 }
393
394 // Fire onConfigured if configureOutputs succeeded, fire onConfigureFailed otherwise.
395 CameraCaptureSessionImpl newSession =
396 new CameraCaptureSessionImpl(outputs, listener, handler, this, mDeviceHandler,
397 configureSuccess);
398
399 if (mCurrentSession != null) {
400 mCurrentSession.replaceSessionClose(newSession);
401 }
402
403 // TODO: wait until current session closes, then create the new session
404 mCurrentSession = newSession;
405
406 if (pendingException != null) {
407 throw pendingException;
408 }
409
410 mSessionStateListener = mCurrentSession.getDeviceStateListener();
411 }
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700412 }
413
414 @Override
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700415 public CaptureRequest.Builder createCaptureRequest(int templateType)
416 throws CameraAccessException {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700417 try (ScopedLock scopedLock = mCloseLock.acquireExclusiveLock()) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700418 checkIfCameraClosedOrInError();
Igor Murashkin70725502013-06-25 20:27:06 +0000419
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700420 CameraMetadataNative templatedRequest = new CameraMetadataNative();
Igor Murashkin70725502013-06-25 20:27:06 +0000421
422 try {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700423 mRemoteDevice.createDefaultRequest(templateType, /*out*/templatedRequest);
Igor Murashkin70725502013-06-25 20:27:06 +0000424 } catch (CameraRuntimeException e) {
425 throw e.asChecked();
426 } catch (RemoteException e) {
427 // impossible
428 return null;
429 }
430
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700431 CaptureRequest.Builder builder =
432 new CaptureRequest.Builder(templatedRequest);
Igor Murashkin70725502013-06-25 20:27:06 +0000433
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700434 return builder;
Igor Murashkin70725502013-06-25 20:27:06 +0000435 }
436 }
437
438 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700439 public int capture(CaptureRequest request, CaptureListener listener, Handler handler)
Igor Murashkin70725502013-06-25 20:27:06 +0000440 throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700441 if (DEBUG) {
442 Log.d(TAG, "calling capture");
443 }
444 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
445 requestList.add(request);
446 return submitCaptureRequest(requestList, listener, handler, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000447 }
448
449 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700450 public int captureBurst(List<CaptureRequest> requests, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700451 Handler handler) throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700452 if (requests == null || requests.isEmpty()) {
453 throw new IllegalArgumentException("At least one request must be given");
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700454 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700455 return submitCaptureRequest(requests, listener, handler, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000456 }
457
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700458 /**
459 * This method checks lastFrameNumber returned from ICameraDeviceUser methods for
460 * starting and stopping repeating request and flushing.
461 *
462 * <p>If lastFrameNumber is NO_FRAMES_CAPTURED, it means that the request was never
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700463 * sent to HAL. Then onCaptureSequenceAborted is immediately triggered.
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700464 * If lastFrameNumber is non-negative, then the requestId and lastFrameNumber pair
465 * is added to the list mFrameNumberRequestPairs.</p>
466 *
467 * @param requestId the request ID of the current repeating request.
468 *
469 * @param lastFrameNumber last frame number returned from binder.
470 */
471 private void checkEarlyTriggerSequenceComplete(
472 final int requestId, final long lastFrameNumber) {
473 // lastFrameNumber being equal to NO_FRAMES_CAPTURED means that the request
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700474 // was never sent to HAL. Should trigger onCaptureSequenceAborted immediately.
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700475 if (lastFrameNumber == CaptureListener.NO_FRAMES_CAPTURED) {
476 final CaptureListenerHolder holder;
477 int index = mCaptureListenerMap.indexOfKey(requestId);
478 holder = (index >= 0) ? mCaptureListenerMap.valueAt(index) : null;
479 if (holder != null) {
480 mCaptureListenerMap.removeAt(index);
Jianing Weibaf0c652014-04-18 17:35:00 -0700481 if (DEBUG) {
482 Log.v(TAG, String.format(
483 "remove holder for requestId %d, "
484 + "because lastFrame is %d.",
485 requestId, lastFrameNumber));
486 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700487 }
488
489 if (holder != null) {
490 if (DEBUG) {
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700491 Log.v(TAG, "immediately trigger onCaptureSequenceAborted because"
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700492 + " request did not reach HAL");
493 }
494
495 Runnable resultDispatch = new Runnable() {
496 @Override
497 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700498 if (!CameraDeviceImpl.this.isClosed()) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700499 if (DEBUG) {
500 Log.d(TAG, String.format(
501 "early trigger sequence complete for request %d",
502 requestId));
503 }
504 if (lastFrameNumber < Integer.MIN_VALUE
505 || lastFrameNumber > Integer.MAX_VALUE) {
506 throw new AssertionError(lastFrameNumber + " cannot be cast to int");
507 }
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700508 holder.getListener().onCaptureSequenceAborted(
Igor Murashkin21547d62014-06-04 15:21:42 -0700509 CameraDeviceImpl.this,
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700510 requestId);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700511 }
512 }
513 };
514 holder.getHandler().post(resultDispatch);
515 } else {
516 Log.w(TAG, String.format(
517 "did not register listener to request %d",
518 requestId));
519 }
520 } else {
521 mFrameNumberRequestPairs.add(
522 new SimpleEntry<Long, Integer>(lastFrameNumber,
523 requestId));
524 }
525 }
526
Jianing Weid2c3a822014-03-27 18:27:43 -0700527 private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700528 Handler handler, boolean repeating) throws CameraAccessException {
529
530 // Need a valid handler, or current thread needs to have a looper, if
531 // listener is valid
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700532 if (listener != null) {
533 handler = checkHandler(handler);
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700534 }
Igor Murashkin70725502013-06-25 20:27:06 +0000535
Ruben Brunk7f2372b2014-07-02 11:05:08 -0700536 // Make sure that there all requests have at least 1 surface; all surfaces are non-null
537 for (CaptureRequest request : requestList) {
538 if (request.getTargets().isEmpty()) {
539 throw new IllegalArgumentException(
540 "Each request must have at least one Surface target");
541 }
542
543 for (Surface surface : request.getTargets()) {
544 if (surface == null) {
545 throw new IllegalArgumentException("Null Surface targets are not allowed");
546 }
547 }
548 }
549
Igor Murashkin49b2b132014-06-18 19:03:00 -0700550 try (ScopedLock scopedLock = mCloseLock.acquireExclusiveLock()) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700551 checkIfCameraClosedOrInError();
Igor Murashkin70725502013-06-25 20:27:06 +0000552 int requestId;
553
Ruben Brunke73b41b2013-11-07 19:30:43 -0800554 if (repeating) {
555 stopRepeating();
556 }
557
Jianing Weid2c3a822014-03-27 18:27:43 -0700558 LongParcelable lastFrameNumberRef = new LongParcelable();
Igor Murashkin70725502013-06-25 20:27:06 +0000559 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700560 requestId = mRemoteDevice.submitRequestList(requestList, repeating,
561 /*out*/lastFrameNumberRef);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700562 if (DEBUG) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700563 Log.v(TAG, "last frame number " + lastFrameNumberRef.getNumber());
564 }
Igor Murashkin70725502013-06-25 20:27:06 +0000565 } catch (CameraRuntimeException e) {
566 throw e.asChecked();
567 } catch (RemoteException e) {
568 // impossible
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700569 return -1;
Igor Murashkin70725502013-06-25 20:27:06 +0000570 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700571
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700572 if (listener != null) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700573 mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener,
574 requestList, handler, repeating));
Jianing Weibaf0c652014-04-18 17:35:00 -0700575 } else {
576 if (DEBUG) {
577 Log.d(TAG, "Listen for request " + requestId + " is null");
578 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700579 }
Igor Murashkin70725502013-06-25 20:27:06 +0000580
Jianing Weid2c3a822014-03-27 18:27:43 -0700581 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700582
Igor Murashkin70725502013-06-25 20:27:06 +0000583 if (repeating) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700584 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700585 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700586 }
Ruben Brunkdecfe952013-10-29 11:00:32 -0700587 mRepeatingRequestId = requestId;
Jianing Weid2c3a822014-03-27 18:27:43 -0700588 } else {
589 mFrameNumberRequestPairs.add(
590 new SimpleEntry<Long, Integer>(lastFrameNumber, requestId));
Igor Murashkin70725502013-06-25 20:27:06 +0000591 }
592
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700593 if (mIdle) {
594 mDeviceHandler.post(mCallOnActive);
595 }
596 mIdle = false;
597
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700598 return requestId;
Igor Murashkin70725502013-06-25 20:27:06 +0000599 }
600 }
601
602 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700603 public int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700604 Handler handler) throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700605 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
606 requestList.add(request);
607 return submitCaptureRequest(requestList, listener, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000608 }
609
610 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700611 public int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700612 Handler handler) throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700613 if (requests == null || requests.isEmpty()) {
614 throw new IllegalArgumentException("At least one request must be given");
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700615 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700616 return submitCaptureRequest(requests, listener, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000617 }
618
619 @Override
620 public void stopRepeating() throws CameraAccessException {
621
Igor Murashkin49b2b132014-06-18 19:03:00 -0700622 try (ScopedLock scopedLock = mCloseLock.acquireExclusiveLock()) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700623 checkIfCameraClosedOrInError();
Ruben Brunkdecfe952013-10-29 11:00:32 -0700624 if (mRepeatingRequestId != REQUEST_ID_NONE) {
625
626 int requestId = mRepeatingRequestId;
627 mRepeatingRequestId = REQUEST_ID_NONE;
628
629 // Queue for deletion after in-flight requests finish
Zhijun He1a9b6462014-03-31 16:11:33 -0700630 if (mCaptureListenerMap.get(requestId) != null) {
631 mRepeatingRequestIdDeletedList.add(requestId);
632 }
Igor Murashkin70725502013-06-25 20:27:06 +0000633
634 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700635 LongParcelable lastFrameNumberRef = new LongParcelable();
636 mRemoteDevice.cancelRequest(requestId, /*out*/lastFrameNumberRef);
637 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700638
639 checkEarlyTriggerSequenceComplete(requestId, lastFrameNumber);
640
Igor Murashkin70725502013-06-25 20:27:06 +0000641 } catch (CameraRuntimeException e) {
642 throw e.asChecked();
643 } catch (RemoteException e) {
644 // impossible
645 return;
646 }
647 }
648 }
649 }
650
Zhijun Hed842fcd2013-12-26 14:14:04 -0800651 private void waitUntilIdle() throws CameraAccessException {
Zhijun He7f4d3142013-07-23 07:54:38 -0700652
Igor Murashkin49b2b132014-06-18 19:03:00 -0700653 try (ScopedLock scopedLock = mCloseLock.acquireExclusiveLock()) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700654 checkIfCameraClosedOrInError();
Ruben Brunkdecfe952013-10-29 11:00:32 -0700655 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Zhijun He7f4d3142013-07-23 07:54:38 -0700656 throw new IllegalStateException("Active repeating request ongoing");
657 }
658
659 try {
660 mRemoteDevice.waitUntilIdle();
661 } catch (CameraRuntimeException e) {
662 throw e.asChecked();
663 } catch (RemoteException e) {
664 // impossible
665 return;
666 }
Ruben Brunkdecfe952013-10-29 11:00:32 -0700667
668 mRepeatingRequestId = REQUEST_ID_NONE;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700669 }
Igor Murashkin70725502013-06-25 20:27:06 +0000670 }
671
672 @Override
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700673 public void flush() throws CameraAccessException {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700674 try (ScopedLock scopedLock = mCloseLock.acquireExclusiveLock()) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700675 checkIfCameraClosedOrInError();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700676
677 mDeviceHandler.post(mCallOnBusy);
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700678 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700679 LongParcelable lastFrameNumberRef = new LongParcelable();
680 mRemoteDevice.flush(/*out*/lastFrameNumberRef);
681 if (mRepeatingRequestId != REQUEST_ID_NONE) {
682 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700683 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700684 mRepeatingRequestId = REQUEST_ID_NONE;
685 }
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700686 } catch (CameraRuntimeException e) {
687 throw e.asChecked();
688 } catch (RemoteException e) {
689 // impossible
690 return;
691 }
692 }
693 }
694
695 @Override
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700696 public void close() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700697 mClosing = true;
698 // Acquire exclusive lock, close, release (idempotent)
699 mCloseLock.close();
Igor Murashkin70725502013-06-25 20:27:06 +0000700
Igor Murashkin49b2b132014-06-18 19:03:00 -0700701 /*
702 * The rest of this is safe, since no other methods will be able to execute
703 * (they will throw ISE instead; the callbacks will get dropped)
704 */
705 {
Igor Murashkin70725502013-06-25 20:27:06 +0000706 try {
Igor Murashkin2a3eced2013-08-28 17:35:10 -0700707 if (mRemoteDevice != null) {
708 mRemoteDevice.disconnect();
709 }
Igor Murashkin70725502013-06-25 20:27:06 +0000710 } catch (CameraRuntimeException e) {
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700711 Log.e(TAG, "Exception while closing: ", e.asChecked());
Igor Murashkin70725502013-06-25 20:27:06 +0000712 } catch (RemoteException e) {
713 // impossible
714 }
715
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700716 // Only want to fire the onClosed callback once;
717 // either a normal close where the remote device is valid
718 // or a close after a startup error (no remote device but in error state)
719 if (mRemoteDevice != null || mInError) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700720 mDeviceHandler.post(mCallOnClosed);
721 }
Igor Murashkin70725502013-06-25 20:27:06 +0000722
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700723 mRemoteDevice = null;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700724 mInError = false;
Igor Murashkin70725502013-06-25 20:27:06 +0000725 }
726 }
727
728 @Override
729 protected void finalize() throws Throwable {
730 try {
731 close();
Igor Murashkin70725502013-06-25 20:27:06 +0000732 }
733 finally {
734 super.finalize();
735 }
736 }
737
738 static class CaptureListenerHolder {
739
740 private final boolean mRepeating;
741 private final CaptureListener mListener;
Jianing Weid2c3a822014-03-27 18:27:43 -0700742 private final List<CaptureRequest> mRequestList;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700743 private final Handler mHandler;
Igor Murashkin70725502013-06-25 20:27:06 +0000744
Jianing Weid2c3a822014-03-27 18:27:43 -0700745 CaptureListenerHolder(CaptureListener listener, List<CaptureRequest> requestList,
746 Handler handler, boolean repeating) {
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700747 if (listener == null || handler == null) {
748 throw new UnsupportedOperationException(
749 "Must have a valid handler and a valid listener");
750 }
Igor Murashkin70725502013-06-25 20:27:06 +0000751 mRepeating = repeating;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700752 mHandler = handler;
Jianing Weid2c3a822014-03-27 18:27:43 -0700753 mRequestList = new ArrayList<CaptureRequest>(requestList);
Igor Murashkin70725502013-06-25 20:27:06 +0000754 mListener = listener;
755 }
756
757 public boolean isRepeating() {
758 return mRepeating;
759 }
760
761 public CaptureListener getListener() {
762 return mListener;
763 }
764
Jianing Weid2c3a822014-03-27 18:27:43 -0700765 public CaptureRequest getRequest(int subsequenceId) {
766 if (subsequenceId >= mRequestList.size()) {
767 throw new IllegalArgumentException(
768 String.format(
769 "Requested subsequenceId %d is larger than request list size %d.",
770 subsequenceId, mRequestList.size()));
771 } else {
772 if (subsequenceId < 0) {
773 throw new IllegalArgumentException(String.format(
774 "Requested subsequenceId %d is negative", subsequenceId));
775 } else {
776 return mRequestList.get(subsequenceId);
777 }
778 }
779 }
780
Igor Murashkin70725502013-06-25 20:27:06 +0000781 public CaptureRequest getRequest() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700782 return getRequest(0);
Igor Murashkin70725502013-06-25 20:27:06 +0000783 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700784
785 public Handler getHandler() {
786 return mHandler;
787 }
788
Igor Murashkin70725502013-06-25 20:27:06 +0000789 }
790
Jianing Weid2c3a822014-03-27 18:27:43 -0700791 /**
792 * This class tracks the last frame number for submitted requests.
793 */
794 public class FrameNumberTracker {
795
796 private long mCompletedFrameNumber = -1;
797 private final TreeSet<Long> mFutureErrorSet = new TreeSet<Long>();
798
799 private void update() {
800 Iterator<Long> iter = mFutureErrorSet.iterator();
801 while (iter.hasNext()) {
802 long errorFrameNumber = iter.next();
803 if (errorFrameNumber == mCompletedFrameNumber + 1) {
804 mCompletedFrameNumber++;
805 iter.remove();
806 } else {
807 break;
808 }
809 }
810 }
811
812 /**
813 * This function is called every time when a result or an error is received.
814 * @param frameNumber: the frame number corresponding to the result or error
815 * @param isError: true if it is an error, false if it is not an error
816 */
817 public void updateTracker(long frameNumber, boolean isError) {
818 if (isError) {
819 mFutureErrorSet.add(frameNumber);
820 } else {
821 /**
822 * HAL cannot send an OnResultReceived for frame N unless it knows for
823 * sure that all frames prior to N have either errored out or completed.
824 * So if the current frame is not an error, then all previous frames
825 * should have arrived. The following line checks whether this holds.
826 */
827 if (frameNumber != mCompletedFrameNumber + 1) {
Zhijun He22589b42014-05-01 10:37:36 -0700828 Log.e(TAG, String.format(
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700829 "result frame number %d comes out of order, should be %d + 1",
830 frameNumber, mCompletedFrameNumber));
Jianing Weid2c3a822014-03-27 18:27:43 -0700831 }
832 mCompletedFrameNumber++;
833 }
834 update();
835 }
836
837 public long getCompletedFrameNumber() {
838 return mCompletedFrameNumber;
839 }
840
841 }
842
843 private void checkAndFireSequenceComplete() {
844 long completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber();
845 Iterator<SimpleEntry<Long, Integer> > iter = mFrameNumberRequestPairs.iterator();
846 while (iter.hasNext()) {
847 final SimpleEntry<Long, Integer> frameNumberRequestPair = iter.next();
848 if (frameNumberRequestPair.getKey() <= completedFrameNumber) {
849
850 // remove request from mCaptureListenerMap
851 final int requestId = frameNumberRequestPair.getValue();
852 final CaptureListenerHolder holder;
Igor Murashkin49b2b132014-06-18 19:03:00 -0700853 try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
854 if (scopedLock == null) {
855 Log.w(TAG, "Camera closed while checking sequences");
856 return;
857 }
858
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700859 int index = mCaptureListenerMap.indexOfKey(requestId);
860 holder = (index >= 0) ? mCaptureListenerMap.valueAt(index)
Jianing Weid2c3a822014-03-27 18:27:43 -0700861 : null;
862 if (holder != null) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700863 mCaptureListenerMap.removeAt(index);
864 if (DEBUG) {
865 Log.v(TAG, String.format(
866 "remove holder for requestId %d, "
867 + "because lastFrame %d is <= %d",
868 requestId, frameNumberRequestPair.getKey(),
869 completedFrameNumber));
870 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700871 }
872 }
873 iter.remove();
874
875 // Call onCaptureSequenceCompleted
876 if (holder != null) {
877 Runnable resultDispatch = new Runnable() {
878 @Override
879 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700880 if (!CameraDeviceImpl.this.isClosed()){
Jianing Weid2c3a822014-03-27 18:27:43 -0700881 if (DEBUG) {
882 Log.d(TAG, String.format(
883 "fire sequence complete for request %d",
884 requestId));
885 }
886
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700887 long lastFrameNumber = frameNumberRequestPair.getKey();
888 if (lastFrameNumber < Integer.MIN_VALUE
889 || lastFrameNumber > Integer.MAX_VALUE) {
890 throw new AssertionError(lastFrameNumber
891 + " cannot be cast to int");
892 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700893 holder.getListener().onCaptureSequenceCompleted(
Igor Murashkin21547d62014-06-04 15:21:42 -0700894 CameraDeviceImpl.this,
Jianing Weid2c3a822014-03-27 18:27:43 -0700895 requestId,
Igor Murashkindb075af2014-05-21 10:07:08 -0700896 lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700897 }
898 }
899 };
900 holder.getHandler().post(resultDispatch);
901 }
902
903 }
904 }
905 }
906
Zhijun Heecb323e2013-07-31 09:40:27 -0700907 public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
Igor Murashkin70725502013-06-25 20:27:06 +0000908
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700909 //
910 // Constants below need to be kept up-to-date with
911 // frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
912 //
913
914 //
915 // Error codes for onCameraError
916 //
917
918 /**
919 * Camera has been disconnected
920 */
921 static final int ERROR_CAMERA_DISCONNECTED = 0;
922
923 /**
924 * Camera has encountered a device-level error
925 * Matches CameraDevice.StateListener#ERROR_CAMERA_DEVICE
926 */
927 static final int ERROR_CAMERA_DEVICE = 1;
928
929 /**
930 * Camera has encountered a service-level error
931 * Matches CameraDevice.StateListener#ERROR_CAMERA_SERVICE
932 */
933 static final int ERROR_CAMERA_SERVICE = 2;
934
Igor Murashkin70725502013-06-25 20:27:06 +0000935 @Override
936 public IBinder asBinder() {
937 return this;
938 }
939
Igor Murashkin70725502013-06-25 20:27:06 +0000940 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -0700941 public void onCameraError(final int errorCode, CaptureResultExtras resultExtras) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700942 Runnable r = null;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700943
Igor Murashkin49b2b132014-06-18 19:03:00 -0700944 try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
945 if (scopedLock == null) {
946 return; // Camera already closed
947 }
948
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700949 mInError = true;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700950 switch (errorCode) {
951 case ERROR_CAMERA_DISCONNECTED:
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700952 r = mCallOnDisconnected;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700953 break;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700954 default:
955 Log.e(TAG, "Unknown error from camera device: " + errorCode);
956 // no break
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700957 case ERROR_CAMERA_DEVICE:
958 case ERROR_CAMERA_SERVICE:
959 r = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700960 @Override
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700961 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700962 if (!CameraDeviceImpl.this.isClosed()) {
963 mDeviceListener.onError(CameraDeviceImpl.this, errorCode);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700964 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700965 }
966 };
967 break;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700968 }
Igor Murashkin21547d62014-06-04 15:21:42 -0700969 CameraDeviceImpl.this.mDeviceHandler.post(r);
Jianing Weid2c3a822014-03-27 18:27:43 -0700970
Igor Murashkin49b2b132014-06-18 19:03:00 -0700971 // Fire onCaptureSequenceCompleted
972 if (DEBUG) {
973 Log.v(TAG, String.format("got error frame %d", resultExtras.getFrameNumber()));
974 }
975 mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(), /*error*/true);
976 checkAndFireSequenceComplete();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700977 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700978 }
979
980 @Override
981 public void onCameraIdle() {
982 if (DEBUG) {
983 Log.d(TAG, "Camera now idle");
984 }
Igor Murashkin49b2b132014-06-18 19:03:00 -0700985 try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
986 if (scopedLock == null) return; // Camera already closed
987
Igor Murashkin21547d62014-06-04 15:21:42 -0700988 if (!CameraDeviceImpl.this.mIdle) {
989 CameraDeviceImpl.this.mDeviceHandler.post(mCallOnIdle);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700990 }
Igor Murashkin21547d62014-06-04 15:21:42 -0700991 CameraDeviceImpl.this.mIdle = true;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700992 }
993 }
994
995 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -0700996 public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) {
997 int requestId = resultExtras.getRequestId();
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700998 if (DEBUG) {
999 Log.d(TAG, "Capture started for id " + requestId);
1000 }
1001 final CaptureListenerHolder holder;
1002
Igor Murashkin49b2b132014-06-18 19:03:00 -07001003 try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
1004 if (scopedLock == null) return; // Camera already closed
1005
1006 // Get the listener for this frame ID, if there is one
Igor Murashkin21547d62014-06-04 15:21:42 -07001007 holder = CameraDeviceImpl.this.mCaptureListenerMap.get(requestId);
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001008
Igor Murashkin49b2b132014-06-18 19:03:00 -07001009 if (holder == null) {
1010 return;
1011 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001012
Igor Murashkin49b2b132014-06-18 19:03:00 -07001013 if (isClosed()) return;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001014
Igor Murashkin49b2b132014-06-18 19:03:00 -07001015 // Dispatch capture start notice
1016 holder.getHandler().post(
1017 new Runnable() {
1018 @Override
1019 public void run() {
1020 if (!CameraDeviceImpl.this.isClosed()) {
1021 holder.getListener().onCaptureStarted(
1022 CameraDeviceImpl.this,
1023 holder.getRequest(resultExtras.getSubsequenceId()),
1024 timestamp);
1025 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001026 }
Igor Murashkin49b2b132014-06-18 19:03:00 -07001027 });
1028
1029 }
Igor Murashkin70725502013-06-25 20:27:06 +00001030 }
1031
1032 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -07001033 public void onResultReceived(CameraMetadataNative result,
1034 CaptureResultExtras resultExtras) throws RemoteException {
Ruben Brunk57493682014-05-27 18:58:08 -07001035
Jianing Weid2c3a822014-03-27 18:27:43 -07001036 int requestId = resultExtras.getRequestId();
Zhijun Heecb323e2013-07-31 09:40:27 -07001037 if (DEBUG) {
Jianing Weibaf0c652014-04-18 17:35:00 -07001038 Log.v(TAG, "Received result frame " + resultExtras.getFrameNumber() + " for id "
1039 + requestId);
Zhijun Heecb323e2013-07-31 09:40:27 -07001040 }
Ruben Brunk57493682014-05-27 18:58:08 -07001041
Igor Murashkin49b2b132014-06-18 19:03:00 -07001042 try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
1043 if (scopedLock == null) return; // Camera already closed
Ruben Brunk57493682014-05-27 18:58:08 -07001044
Igor Murashkin49b2b132014-06-18 19:03:00 -07001045 // TODO: Handle CameraCharacteristics access from CaptureResult correctly.
1046 result.set(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE,
1047 getCharacteristics().get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE));
Ruben Brunk57493682014-05-27 18:58:08 -07001048
Igor Murashkin49b2b132014-06-18 19:03:00 -07001049 final CaptureListenerHolder holder =
1050 CameraDeviceImpl.this.mCaptureListenerMap.get(requestId);
Igor Murashkin70725502013-06-25 20:27:06 +00001051
Igor Murashkin49b2b132014-06-18 19:03:00 -07001052 Boolean quirkPartial = result.get(CaptureResult.QUIRKS_PARTIAL_RESULT);
1053 boolean quirkIsPartialResult = (quirkPartial != null && quirkPartial);
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001054
Igor Murashkin49b2b132014-06-18 19:03:00 -07001055 // Update tracker (increment counter) when it's not a partial result.
1056 if (!quirkIsPartialResult) {
1057 mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(),
1058 /*error*/false);
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001059 }
Igor Murashkin70725502013-06-25 20:27:06 +00001060
Igor Murashkin49b2b132014-06-18 19:03:00 -07001061 // Check if we have a listener for this
1062 if (holder == null) {
1063 if (DEBUG) {
1064 Log.d(TAG,
1065 "holder is null, early return at frame "
1066 + resultExtras.getFrameNumber());
1067 }
1068 return;
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001069 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001070
Igor Murashkin49b2b132014-06-18 19:03:00 -07001071 if (isClosed()) {
1072 if (DEBUG) {
1073 Log.d(TAG,
1074 "camera is closed, early return at frame "
1075 + resultExtras.getFrameNumber());
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001076 }
Igor Murashkin49b2b132014-06-18 19:03:00 -07001077 return;
1078 }
Igor Murashkindb075af2014-05-21 10:07:08 -07001079
Igor Murashkin49b2b132014-06-18 19:03:00 -07001080 final CaptureRequest request = holder.getRequest(resultExtras.getSubsequenceId());
1081
1082
1083 Runnable resultDispatch = null;
1084
1085 // Either send a partial result or the final capture completed result
1086 if (quirkIsPartialResult) {
1087 final CaptureResult resultAsCapture =
1088 new CaptureResult(result, request, requestId);
1089
1090 // Partial result
1091 resultDispatch = new Runnable() {
1092 @Override
1093 public void run() {
1094 if (!CameraDeviceImpl.this.isClosed()){
1095 holder.getListener().onCapturePartial(
1096 CameraDeviceImpl.this,
1097 request,
1098 resultAsCapture);
1099 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001100 }
Igor Murashkin49b2b132014-06-18 19:03:00 -07001101 };
1102 } else {
1103 final TotalCaptureResult resultAsCapture =
1104 new TotalCaptureResult(result, request, requestId);
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001105
Igor Murashkin49b2b132014-06-18 19:03:00 -07001106 // Final capture result
1107 resultDispatch = new Runnable() {
1108 @Override
1109 public void run() {
1110 if (!CameraDeviceImpl.this.isClosed()){
1111 holder.getListener().onCaptureCompleted(
1112 CameraDeviceImpl.this,
1113 request,
1114 resultAsCapture);
1115 }
1116 }
1117 };
1118 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001119
Igor Murashkin49b2b132014-06-18 19:03:00 -07001120 holder.getHandler().post(resultDispatch);
1121
1122 // Fire onCaptureSequenceCompleted
1123 if (!quirkIsPartialResult) {
1124 checkAndFireSequenceComplete();
1125 }
1126
Jianing Weid2c3a822014-03-27 18:27:43 -07001127 }
Igor Murashkin70725502013-06-25 20:27:06 +00001128 }
1129
1130 }
1131
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001132 /**
Igor Murashkin0b27d342014-05-30 09:45:05 -07001133 * Default handler management.
1134 *
1135 * <p>
1136 * If handler is null, get the current thread's
1137 * Looper to create a Handler with. If no looper exists, throw {@code IllegalArgumentException}.
1138 * </p>
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001139 */
Igor Murashkin0b27d342014-05-30 09:45:05 -07001140 static Handler checkHandler(Handler handler) {
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001141 if (handler == null) {
1142 Looper looper = Looper.myLooper();
1143 if (looper == null) {
1144 throw new IllegalArgumentException(
1145 "No handler given, and current thread has no looper!");
1146 }
1147 handler = new Handler(looper);
1148 }
1149 return handler;
1150 }
1151
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -07001152 private void checkIfCameraClosedOrInError() throws CameraAccessException {
1153 if (mInError) {
1154 throw new CameraAccessException(CameraAccessException.CAMERA_ERROR,
1155 "The camera device has encountered a serious error");
1156 }
Zhijun He7f4d3142013-07-23 07:54:38 -07001157 if (mRemoteDevice == null) {
1158 throw new IllegalStateException("CameraDevice was already closed");
1159 }
1160 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001161
Igor Murashkin49b2b132014-06-18 19:03:00 -07001162 /** Whether the camera device has started to close (may not yet have finished) */
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001163 private boolean isClosed() {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001164 return mClosing;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001165 }
Ruben Brunk57493682014-05-27 18:58:08 -07001166
1167 private CameraCharacteristics getCharacteristics() {
1168 return mCharacteristics;
1169 }
Igor Murashkin70725502013-06-25 20:27:06 +00001170}