blob: 9587680a41d9c491e5ea623fdc42b12ce68f1ec1 [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
Eino-Ville Talvala2f1a2e42013-07-25 17:12:05 -070019import android.hardware.camera2.CameraMetadata;
20import android.hardware.camera2.CaptureResult;
21import android.hardware.camera2.ICameraDeviceUser;
22import android.hardware.camera2.ICameraDeviceCallbacks;
23import android.hardware.camera2.CameraAccessException;
24import android.hardware.camera2.CameraProperties;
25import android.hardware.camera2.CaptureRequest;
26import android.hardware.camera2.utils.CameraRuntimeException;
Igor Murashkin70725502013-06-25 20:27:06 +000027import android.os.Binder;
28import android.os.IBinder;
29import android.os.RemoteException;
30import android.util.Log;
31import android.view.Surface;
32
33import java.util.HashMap;
34import java.util.List;
35import java.util.Stack;
36
37/**
38 * HAL2.1+ implementation of CameraDevice Use CameraManager#open to instantiate
39 */
Eino-Ville Talvala2f1a2e42013-07-25 17:12:05 -070040public class CameraDevice implements android.hardware.camera2.CameraDevice {
Igor Murashkin70725502013-06-25 20:27:06 +000041
42 private final String TAG;
43
44 // TODO: guard every function with if (!mRemoteDevice) check (if it was closed)
45 private ICameraDeviceUser mRemoteDevice;
46
47 private final Object mLock = new Object();
48 private final CameraDeviceCallbacks mCallbacks = new CameraDeviceCallbacks();
49
50 // XX: Make this a WeakReference<CaptureListener> ?
Igor Murashkind7bf1772013-07-12 18:01:31 -070051 // TODO: Convert to SparseIntArray
Igor Murashkin70725502013-06-25 20:27:06 +000052 private final HashMap<Integer, CaptureListenerHolder> mCaptureListenerMap =
53 new HashMap<Integer, CaptureListenerHolder>();
54
55 private final Stack<Integer> mRepeatingRequestIdStack = new Stack<Integer>();
56
57 private final String mCameraId;
58
59 public CameraDevice(String cameraId) {
60 mCameraId = cameraId;
61 TAG = String.format("CameraDevice-%s-JV", mCameraId);
62 }
63
64 public CameraDeviceCallbacks getCallbacks() {
65 return mCallbacks;
66 }
67
Igor Murashkin70725502013-06-25 20:27:06 +000068 public void setRemoteDevice(ICameraDeviceUser remoteDevice) {
69 mRemoteDevice = remoteDevice;
70 }
71
72 @Override
73 public CameraProperties getProperties() throws CameraAccessException {
Igor Murashkind7bf1772013-07-12 18:01:31 -070074
75 CameraProperties properties = new CameraProperties();
76 CameraMetadata info = new CameraMetadata();
77
78 try {
79 mRemoteDevice.getCameraInfo(/*out*/info);
80 } catch(CameraRuntimeException e) {
81 throw e.asChecked();
82 } catch(RemoteException e) {
83 // impossible
84 return null;
85 }
86
87 properties.swap(info);
88 return properties;
Igor Murashkin70725502013-06-25 20:27:06 +000089 }
90
91 @Override
92 public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
93 synchronized (mLock) {
94 // TODO: delete outputs that aren't in this list that were configured previously
95 for (Surface s : outputs) {
96 try {
97 // TODO: remove width,height,format since we are ignoring
98 // it.
99 mRemoteDevice.createStream(0, 0, 0, s);
100 } catch (CameraRuntimeException e) {
101 throw e.asChecked();
102 } catch (RemoteException e) {
103 // impossible
104 return;
105 }
106 }
107 }
108 }
109
110 @Override
111 public CaptureRequest createCaptureRequest(int templateType) throws CameraAccessException {
112
113 synchronized (mLock) {
114
115 CameraMetadata templatedRequest = new CameraMetadata();
116
117 try {
118 mRemoteDevice.createDefaultRequest(templateType, /* out */templatedRequest);
119 } catch (CameraRuntimeException e) {
120 throw e.asChecked();
121 } catch (RemoteException e) {
122 // impossible
123 return null;
124 }
125
126 CaptureRequest request = new CaptureRequest();
Igor Murashkin70725502013-06-25 20:27:06 +0000127 request.swap(templatedRequest);
128
129 return request;
130
131 }
132 }
133
134 @Override
135 public void capture(CaptureRequest request, CaptureListener listener)
136 throws CameraAccessException {
137 submitCaptureRequest(request, listener, /*streaming*/false);
138 }
139
140 @Override
141 public void captureBurst(List<CaptureRequest> requests, CaptureListener listener)
142 throws CameraAccessException {
143 // TODO
144 throw new UnsupportedOperationException("Burst capture implemented yet");
145
146 }
147
148 private void submitCaptureRequest(CaptureRequest request, CaptureListener listener,
149 boolean repeating) throws CameraAccessException {
150
151 synchronized (mLock) {
152
153 int requestId;
154
155 try {
156 requestId = mRemoteDevice.submitRequest(request, repeating);
157 } catch (CameraRuntimeException e) {
158 throw e.asChecked();
159 } catch (RemoteException e) {
160 // impossible
161 return;
162 }
163
164 mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener, request,
165 repeating));
166
167 if (repeating) {
168 mRepeatingRequestIdStack.add(requestId);
169 }
170
171 }
172 }
173
174 @Override
175 public void setRepeatingRequest(CaptureRequest request, CaptureListener listener)
176 throws CameraAccessException {
177 submitCaptureRequest(request, listener, /*streaming*/true);
178 }
179
180 @Override
181 public void setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener)
182 throws CameraAccessException {
183 // TODO
184 throw new UnsupportedOperationException("Burst capture implemented yet");
185 }
186
187 @Override
188 public void stopRepeating() throws CameraAccessException {
189
190 synchronized (mLock) {
191
192 while (!mRepeatingRequestIdStack.isEmpty()) {
193 int requestId = mRepeatingRequestIdStack.pop();
194
195 try {
196 mRemoteDevice.cancelRequest(requestId);
197 } catch (CameraRuntimeException e) {
198 throw e.asChecked();
199 } catch (RemoteException e) {
200 // impossible
201 return;
202 }
203 }
204 }
205 }
206
207 @Override
208 public void waitUntilIdle() throws CameraAccessException {
Zhijun He7f4d3142013-07-23 07:54:38 -0700209
210 synchronized (mLock) {
211 checkIfCameraClosed();
212 if (!mRepeatingRequestIdStack.isEmpty()) {
213 throw new IllegalStateException("Active repeating request ongoing");
214 }
215
216 try {
217 mRemoteDevice.waitUntilIdle();
218 } catch (CameraRuntimeException e) {
219 throw e.asChecked();
220 } catch (RemoteException e) {
221 // impossible
222 return;
223 }
224 }
Igor Murashkin70725502013-06-25 20:27:06 +0000225 }
226
227 @Override
228 public void setErrorListener(ErrorListener listener) {
229 // TODO Auto-generated method stub
230
231 }
232
233 @Override
234 public void close() throws Exception {
235
236 // TODO: every method should throw IllegalStateException after close has been called
237
238 synchronized (mLock) {
239
240 try {
241 mRemoteDevice.disconnect();
242 } catch (CameraRuntimeException e) {
243 throw e.asChecked();
244 } catch (RemoteException e) {
245 // impossible
246 }
247
248 mRemoteDevice = null;
249
250 }
251 }
252
253 @Override
254 protected void finalize() throws Throwable {
255 try {
256 close();
257 } catch (CameraRuntimeException e) {
258 Log.e(TAG, "Got error while trying to finalize, ignoring: " + e.getMessage());
259 }
260 finally {
261 super.finalize();
262 }
263 }
264
265 static class CaptureListenerHolder {
266
267 private final boolean mRepeating;
268 private final CaptureListener mListener;
269 private final CaptureRequest mRequest;
270
271 CaptureListenerHolder(CaptureListener listener, CaptureRequest request, boolean repeating) {
272 mRepeating = repeating;
273 mRequest = request;
274 mListener = listener;
275 }
276
277 public boolean isRepeating() {
278 return mRepeating;
279 }
280
281 public CaptureListener getListener() {
282 return mListener;
283 }
284
285 public CaptureRequest getRequest() {
286 return mRequest;
287 }
288 }
289
290 // TODO: unit tests
291 public class CameraDeviceCallbacks extends Binder implements ICameraDeviceCallbacks {
292
293 @Override
294 public IBinder asBinder() {
295 return this;
296 }
297
298 // TODO: consider rename to onMessageReceived
299 @Override
300 public void notifyCallback(int msgType, int ext1, int ext2) throws RemoteException {
301 Log.d(TAG, "Got message " + msgType + " ext1: " + ext1 + " , ext2: " + ext2);
302 // TODO implement rest
303 }
304
305 @Override
306 public void onResultReceived(int frameId, CameraMetadata result) throws RemoteException {
307 Log.d(TAG, "Received result for frameId " + frameId);
308
309 CaptureListenerHolder holder;
310
311 synchronized (mLock) {
312 // TODO: move this whole map into this class to make it more testable,
313 // exposing the methods necessary like subscribeToRequest, unsubscribe..
314 // TODO: make class static class
315
316 holder = CameraDevice.this.mCaptureListenerMap.get(frameId);
317
318 // Clean up listener once we no longer expect to see it.
319
320 // TODO: how to handle repeating listeners?
321 // we probably want cancelRequest to return # of times it already enqueued and
322 // keep a counter.
323 if (holder != null && !holder.isRepeating()) {
324 CameraDevice.this.mCaptureListenerMap.remove(frameId);
325 }
326 }
327
328 if (holder == null) {
329 Log.e(TAG, "Result had no listener holder associated with it, dropping result");
330 return;
331 }
332
333 CaptureResult resultAsCapture = new CaptureResult();
334 resultAsCapture.swap(result);
335
336 if (holder.getListener() != null) {
337 holder.getListener().onCaptureComplete(CameraDevice.this, holder.getRequest(),
338 resultAsCapture);
339 }
340 }
341
342 }
343
Zhijun He7f4d3142013-07-23 07:54:38 -0700344 private void checkIfCameraClosed() {
345 if (mRemoteDevice == null) {
346 throw new IllegalStateException("CameraDevice was already closed");
347 }
348 }
Igor Murashkin70725502013-06-25 20:27:06 +0000349}