blob: eea5127cfe6250f1f2c035e95aca029cca9fc60c
1 | /* |
2 | * Copyright (C) 2011 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 | |
17 | /* |
18 | * Contains implementation of a class EmulatedCameraFactory that manages cameras |
19 | * available for emulation. |
20 | */ |
21 | |
22 | //#define LOG_NDEBUG 0 |
23 | //#define LOG_NDDEBUG 0 |
24 | //#define LOG_NIDEBUG 0 |
25 | #define LOG_TAG "EmulatedCamera_Factory" |
26 | #include <cutils/log.h> |
27 | #include <cutils/properties.h> |
28 | #include "EmulatedQemuCamera.h" |
29 | #include "EmulatedFakeCamera.h" |
30 | #include "EmulatedFakeCamera2.h" |
31 | #include "EmulatedFakeCamera3.h" |
32 | #include "EmulatedCameraHotplugThread.h" |
33 | #include "EmulatedCameraFactory.h" |
34 | |
35 | extern camera_module_t HAL_MODULE_INFO_SYM; |
36 | volatile int32_t gCamHal_LogLevel = 4; |
37 | |
38 | /* A global instance of EmulatedCameraFactory is statically instantiated and |
39 | * initialized when camera emulation HAL is loaded. |
40 | */ |
41 | android::EmulatedCameraFactory gEmulatedCameraFactory; |
42 | default_camera_hal::VendorTags gVendorTags; |
43 | |
44 | static const char *SENSOR_PATH[]={ |
45 | "/dev/video0", |
46 | "/dev/video1", |
47 | "/dev/video2", |
48 | "/dev/video3", |
49 | "/dev/video4", |
50 | "/dev/video5", |
51 | }; |
52 | |
53 | static int getCameraNum() { |
54 | int iCamerasNum = 0; |
55 | for (int i = 0; i < (int)ARRAY_SIZE(SENSOR_PATH); i++ ) { |
56 | int camera_fd; |
57 | CAMHAL_LOGDB("try access %s\n", SENSOR_PATH[i]); |
58 | if (0 == access(SENSOR_PATH[i], F_OK | R_OK | W_OK)) { |
59 | CAMHAL_LOGDB("access %s success\n", SENSOR_PATH[i]); |
60 | iCamerasNum++; |
61 | } |
62 | } |
63 | |
64 | return iCamerasNum; |
65 | } |
66 | namespace android { |
67 | |
68 | EmulatedCameraFactory::EmulatedCameraFactory() |
69 | : mQemuClient(), |
70 | mEmulatedCameraNum(0), |
71 | mFakeCameraNum(0), |
72 | mConstructedOK(false), |
73 | mCallbacks(NULL) |
74 | { |
75 | status_t res; |
76 | /* Connect to the factory service in the emulator, and create Qemu cameras. */ |
77 | int cameraId = 0; |
78 | |
79 | memset(mEmulatedCameras, 0,(MAX_CAMERA_NUM) * sizeof(EmulatedBaseCamera*)); |
80 | mEmulatedCameraNum = getCameraNum(); |
81 | CAMHAL_LOGDB("Camera num = %d", mEmulatedCameraNum); |
82 | |
83 | for( int i = 0; i < mEmulatedCameraNum; i++ ) { |
84 | cameraId = i; |
85 | mEmulatedCameras[i] = new EmulatedFakeCamera3(cameraId, &HAL_MODULE_INFO_SYM.common); |
86 | if (mEmulatedCameras[i] != NULL) { |
87 | ALOGV("%s: camera device version is %d", __FUNCTION__, |
88 | getFakeCameraHalVersion(cameraId)); |
89 | res = mEmulatedCameras[i]->Initialize(); |
90 | if (res != NO_ERROR) { |
91 | ALOGE("%s: Unable to intialize camera %d: %s (%d)", |
92 | __FUNCTION__, i, strerror(-res), res); |
93 | delete mEmulatedCameras[i]; |
94 | } |
95 | } |
96 | } |
97 | |
98 | CAMHAL_LOGDB("%d cameras are being created", |
99 | mEmulatedCameraNum); |
100 | |
101 | /* Create hotplug thread */ |
102 | { |
103 | Vector<int> cameraIdVector; |
104 | for (int i = 0; i < mEmulatedCameraNum; ++i) { |
105 | cameraIdVector.push_back(i); |
106 | } |
107 | mHotplugThread = new EmulatedCameraHotplugThread(&cameraIdVector[0], |
108 | mEmulatedCameraNum); |
109 | mHotplugThread->run(); |
110 | } |
111 | |
112 | mConstructedOK = true; |
113 | } |
114 | |
115 | EmulatedCameraFactory::~EmulatedCameraFactory() |
116 | { |
117 | CAMHAL_LOGDA("Camera Factory deconstruct the BaseCamera\n"); |
118 | for (int n = 0; n < mEmulatedCameraNum; n++) { |
119 | if (mEmulatedCameras[n] != NULL) { |
120 | delete mEmulatedCameras[n]; |
121 | } |
122 | } |
123 | |
124 | if (mHotplugThread != NULL) { |
125 | mHotplugThread->requestExit(); |
126 | mHotplugThread->join(); |
127 | } |
128 | } |
129 | |
130 | /**************************************************************************** |
131 | * Camera HAL API handlers. |
132 | * |
133 | * Each handler simply verifies existence of an appropriate EmulatedBaseCamera |
134 | * instance, and dispatches the call to that instance. |
135 | * |
136 | ***************************************************************************/ |
137 | |
138 | int EmulatedCameraFactory::cameraDeviceOpen(int camera_id, hw_device_t** device) |
139 | { |
140 | ALOGV("%s: id = %d", __FUNCTION__, camera_id); |
141 | |
142 | *device = NULL; |
143 | |
144 | if (!isConstructedOK()) { |
145 | ALOGE("%s: EmulatedCameraFactory has failed to initialize", __FUNCTION__); |
146 | return -EINVAL; |
147 | } |
148 | |
149 | if (camera_id < 0 || camera_id >= getEmulatedCameraNum()) { |
150 | ALOGE("%s: Camera id %d is out of bounds (%d)", |
151 | __FUNCTION__, camera_id, getEmulatedCameraNum()); |
152 | return -ENODEV; |
153 | } |
154 | |
155 | return mEmulatedCameras[camera_id]->connectCamera(device); |
156 | } |
157 | |
158 | int EmulatedCameraFactory::getCameraInfo(int camera_id, struct camera_info* info) |
159 | { |
160 | ALOGV("%s: id = %d", __FUNCTION__, camera_id); |
161 | |
162 | if (!isConstructedOK()) { |
163 | ALOGE("%s: EmulatedCameraFactory has failed to initialize", __FUNCTION__); |
164 | return -EINVAL; |
165 | } |
166 | |
167 | if (camera_id < 0 || camera_id >= getEmulatedCameraNum()) { |
168 | ALOGE("%s: Camera id %d is out of bounds (%d)", |
169 | __FUNCTION__, camera_id, getEmulatedCameraNum()); |
170 | return -ENODEV; |
171 | } |
172 | |
173 | return mEmulatedCameras[camera_id]->getCameraInfo(info); |
174 | } |
175 | |
176 | int EmulatedCameraFactory::setCallbacks( |
177 | const camera_module_callbacks_t *callbacks) |
178 | { |
179 | ALOGV("%s: callbacks = %p", __FUNCTION__, callbacks); |
180 | |
181 | mCallbacks = callbacks; |
182 | |
183 | return OK; |
184 | } |
185 | |
186 | static int get_tag_count(const vendor_tag_ops_t* ops) |
187 | { |
188 | return gVendorTags.getTagCount(ops); |
189 | } |
190 | static void get_all_tags(const vendor_tag_ops_t* ops, uint32_t* tag_array) |
191 | { |
192 | gVendorTags.getAllTags(ops, tag_array); |
193 | } |
194 | static const char* get_section_name(const vendor_tag_ops_t* ops, uint32_t tag) |
195 | { |
196 | return gVendorTags.getSectionName(ops, tag); |
197 | } |
198 | static const char* get_tag_name(const vendor_tag_ops_t* ops, uint32_t tag) |
199 | { |
200 | return gVendorTags.getTagName(ops, tag); |
201 | } |
202 | static int get_tag_type(const vendor_tag_ops_t* ops, uint32_t tag) |
203 | { |
204 | return gVendorTags.getTagType(ops, tag); |
205 | } |
206 | void EmulatedCameraFactory::getvendortagops(vendor_tag_ops_t* ops) |
207 | { |
208 | ALOGV("%s : ops=%p", __func__, ops); |
209 | ops->get_tag_count = get_tag_count; |
210 | ops->get_all_tags = get_all_tags; |
211 | ops->get_section_name = get_section_name; |
212 | ops->get_tag_name = get_tag_name; |
213 | ops->get_tag_type = get_tag_type; |
214 | } |
215 | /**************************************************************************** |
216 | * Camera HAL API callbacks. |
217 | ***************************************************************************/ |
218 | |
219 | int EmulatedCameraFactory::device_open(const hw_module_t* module, |
220 | const char* name, |
221 | hw_device_t** device) |
222 | { |
223 | /* |
224 | * Simply verify the parameters, and dispatch the call inside the |
225 | * EmulatedCameraFactory instance. |
226 | */ |
227 | |
228 | if (module != &HAL_MODULE_INFO_SYM.common) { |
229 | ALOGE("%s: Invalid module %p expected %p", |
230 | __FUNCTION__, module, &HAL_MODULE_INFO_SYM.common); |
231 | return -EINVAL; |
232 | } |
233 | if (name == NULL) { |
234 | ALOGE("%s: NULL name is not expected here", __FUNCTION__); |
235 | return -EINVAL; |
236 | } |
237 | |
238 | return gEmulatedCameraFactory.cameraDeviceOpen(atoi(name), device); |
239 | } |
240 | |
241 | int EmulatedCameraFactory::get_number_of_cameras(void) |
242 | { |
243 | return gEmulatedCameraFactory.getEmulatedCameraNum(); |
244 | } |
245 | |
246 | int EmulatedCameraFactory::get_camera_info(int camera_id, |
247 | struct camera_info* info) |
248 | { |
249 | return gEmulatedCameraFactory.getCameraInfo(camera_id, info); |
250 | } |
251 | |
252 | int EmulatedCameraFactory::set_callbacks( |
253 | const camera_module_callbacks_t *callbacks) |
254 | { |
255 | return gEmulatedCameraFactory.setCallbacks(callbacks); |
256 | } |
257 | |
258 | void EmulatedCameraFactory::get_vendor_tag_ops(vendor_tag_ops_t* ops) |
259 | { |
260 | gEmulatedCameraFactory.getvendortagops(ops); |
261 | } |
262 | /******************************************************************************** |
263 | * Internal API |
264 | *******************************************************************************/ |
265 | |
266 | /* |
267 | * Camera information tokens passed in response to the "list" factory query. |
268 | */ |
269 | |
270 | /* Device name token. */ |
271 | static const char lListNameToken[] = "name="; |
272 | /* Frame dimensions token. */ |
273 | static const char lListDimsToken[] = "framedims="; |
274 | /* Facing direction token. */ |
275 | static const char lListDirToken[] = "dir="; |
276 | |
277 | void EmulatedCameraFactory::createQemuCameras() |
278 | { |
279 | #if 0 |
280 | /* Obtain camera list. */ |
281 | char* camera_list = NULL; |
282 | status_t res = mQemuClient.listCameras(&camera_list); |
283 | /* Empty list, or list containing just an EOL means that there were no |
284 | * connected cameras found. */ |
285 | if (res != NO_ERROR || camera_list == NULL || *camera_list == '\0' || |
286 | *camera_list == '\n') { |
287 | if (camera_list != NULL) { |
288 | free(camera_list); |
289 | } |
290 | return; |
291 | } |
292 | |
293 | /* |
294 | * Calculate number of connected cameras. Number of EOLs in the camera list |
295 | * is the number of the connected cameras. |
296 | */ |
297 | |
298 | int num = 0; |
299 | const char* eol = strchr(camera_list, '\n'); |
300 | while (eol != NULL) { |
301 | num++; |
302 | eol = strchr(eol + 1, '\n'); |
303 | } |
304 | |
305 | /* Allocate the array for emulated camera instances. Note that we allocate |
306 | * two more entries for back and front fake camera emulation. */ |
307 | mEmulatedCameras = new EmulatedBaseCamera*[num + 2]; |
308 | if (mEmulatedCameras == NULL) { |
309 | ALOGE("%s: Unable to allocate emulated camera array for %d entries", |
310 | __FUNCTION__, num + 1); |
311 | free(camera_list); |
312 | return; |
313 | } |
314 | memset(mEmulatedCameras, 0, sizeof(EmulatedBaseCamera*) * (num + 1)); |
315 | |
316 | /* |
317 | * Iterate the list, creating, and initializin emulated qemu cameras for each |
318 | * entry (line) in the list. |
319 | */ |
320 | |
321 | int index = 0; |
322 | char* cur_entry = camera_list; |
323 | while (cur_entry != NULL && *cur_entry != '\0' && index < num) { |
324 | /* Find the end of the current camera entry, and terminate it with zero |
325 | * for simpler string manipulation. */ |
326 | char* next_entry = strchr(cur_entry, '\n'); |
327 | if (next_entry != NULL) { |
328 | *next_entry = '\0'; |
329 | next_entry++; // Start of the next entry. |
330 | } |
331 | |
332 | /* Find 'name', 'framedims', and 'dir' tokens that are required here. */ |
333 | char* name_start = strstr(cur_entry, lListNameToken); |
334 | char* dim_start = strstr(cur_entry, lListDimsToken); |
335 | char* dir_start = strstr(cur_entry, lListDirToken); |
336 | if (name_start != NULL && dim_start != NULL && dir_start != NULL) { |
337 | /* Advance to the token values. */ |
338 | name_start += strlen(lListNameToken); |
339 | dim_start += strlen(lListDimsToken); |
340 | dir_start += strlen(lListDirToken); |
341 | |
342 | /* Terminate token values with zero. */ |
343 | char* s = strchr(name_start, ' '); |
344 | if (s != NULL) { |
345 | *s = '\0'; |
346 | } |
347 | s = strchr(dim_start, ' '); |
348 | if (s != NULL) { |
349 | *s = '\0'; |
350 | } |
351 | s = strchr(dir_start, ' '); |
352 | if (s != NULL) { |
353 | *s = '\0'; |
354 | } |
355 | |
356 | /* Create and initialize qemu camera. */ |
357 | EmulatedQemuCamera* qemu_cam = |
358 | new EmulatedQemuCamera(index, &HAL_MODULE_INFO_SYM.common); |
359 | if (NULL != qemu_cam) { |
360 | res = qemu_cam->Initialize(name_start, dim_start, dir_start); |
361 | if (res == NO_ERROR) { |
362 | mEmulatedCameras[index] = qemu_cam; |
363 | index++; |
364 | } else { |
365 | delete qemu_cam; |
366 | } |
367 | } else { |
368 | ALOGE("%s: Unable to instantiate EmulatedQemuCamera", |
369 | __FUNCTION__); |
370 | } |
371 | } else { |
372 | ALOGW("%s: Bad camera information: %s", __FUNCTION__, cur_entry); |
373 | } |
374 | |
375 | cur_entry = next_entry; |
376 | } |
377 | |
378 | mEmulatedCameraNum = index; |
379 | #else |
380 | CAMHAL_LOGDA("delete this function"); |
381 | #endif |
382 | } |
383 | |
384 | bool EmulatedCameraFactory::isFakeCameraFacingBack(int cameraId) |
385 | { |
386 | if (cameraId%mEmulatedCameraNum == 1) |
387 | return false; |
388 | |
389 | return true; |
390 | } |
391 | |
392 | int EmulatedCameraFactory::getFakeCameraHalVersion(int cameraId) |
393 | { |
394 | /* Defined by 'qemu.sf.back_camera_hal_version' boot property: if the |
395 | * property doesn't exist, it is assumed to be 1. */ |
396 | #if 0 |
397 | char prop[PROPERTY_VALUE_MAX]; |
398 | if (property_get("qemu.sf.back_camera_hal", prop, NULL) > 0) { |
399 | char *prop_end = prop; |
400 | int val = strtol(prop, &prop_end, 10); |
401 | if (*prop_end == '\0') { |
402 | return val; |
403 | } |
404 | // Badly formatted property, should just be a number |
405 | ALOGE("qemu.sf.back_camera_hal is not a number: %s", prop); |
406 | } |
407 | return 1; |
408 | #else |
409 | cameraId = cameraId; |
410 | return 3; |
411 | #endif |
412 | } |
413 | |
414 | void EmulatedCameraFactory::onStatusChanged(int cameraId, int newStatus) |
415 | { |
416 | status_t res; |
417 | |
418 | EmulatedBaseCamera *cam = mEmulatedCameras[cameraId]; |
419 | const camera_module_callbacks_t* cb = mCallbacks; |
420 | |
421 | CAMHAL_LOGDB("mEmulatedCameraNum =%d\n", mEmulatedCameraNum); |
422 | |
423 | if (!cam) { |
424 | /*suppose only usb camera produce uevent, and it is facing back*/ |
425 | cam = new EmulatedFakeCamera3(cameraId, &HAL_MODULE_INFO_SYM.common); |
426 | if (cam != NULL) { |
427 | CAMHAL_LOGDB("%s: new camera device version is %d", __FUNCTION__, |
428 | getFakeCameraHalVersion(cameraId)); |
429 | //sleep 10ms for /dev/video* create |
430 | usleep(10000); |
431 | res = cam->Initialize(); |
432 | if (res != NO_ERROR) { |
433 | ALOGE("%s: Unable to intialize camera %d: %s (%d)", |
434 | __FUNCTION__, cameraId, strerror(-res), res); |
435 | delete cam; |
436 | } |
437 | } |
438 | |
439 | /* Open the camera. then send the callback to framework*/ |
440 | mEmulatedCameras[cameraId] = cam; |
441 | mEmulatedCameraNum ++; |
442 | cam->plugCamera(); |
443 | if (cb != NULL && cb->camera_device_status_change != NULL) { |
444 | cb->camera_device_status_change(cb, cameraId, newStatus); |
445 | } |
446 | |
447 | return ; |
448 | } |
449 | |
450 | CAMHAL_LOGDB("mEmulatedCameraNum =%d\n", mEmulatedCameraNum); |
451 | |
452 | /** |
453 | * (Order is important) |
454 | * Send the callback first to framework, THEN close the camera. |
455 | */ |
456 | |
457 | if (newStatus == cam->getHotplugStatus()) { |
458 | CAMHAL_LOGDB("%s: Ignoring transition to the same status", __FUNCTION__); |
459 | return; |
460 | } |
461 | |
462 | CAMHAL_LOGDB("mEmulatedCameraNum =%d\n", mEmulatedCameraNum); |
463 | if (cb != NULL && cb->camera_device_status_change != NULL) { |
464 | cb->camera_device_status_change(cb, cameraId, newStatus); |
465 | } |
466 | |
467 | CAMHAL_LOGDB("mEmulatedCameraNum =%d\n", mEmulatedCameraNum); |
468 | if (newStatus == CAMERA_DEVICE_STATUS_NOT_PRESENT) { |
469 | cam->unplugCamera(); |
470 | //// |
471 | delete mEmulatedCameras[cameraId]; |
472 | mEmulatedCameras[cameraId] = NULL; |
473 | mEmulatedCameraNum --; |
474 | //// |
475 | } else if (newStatus == CAMERA_DEVICE_STATUS_PRESENT) { |
476 | CAMHAL_LOGDA("camera plugged again?\n"); |
477 | cam->plugCamera(); |
478 | } |
479 | CAMHAL_LOGDB("mEmulatedCameraNum =%d\n", mEmulatedCameraNum); |
480 | |
481 | } |
482 | |
483 | /******************************************************************************** |
484 | * Initializer for the static member structure. |
485 | *******************************************************************************/ |
486 | |
487 | /* Entry point for camera HAL API. */ |
488 | struct hw_module_methods_t EmulatedCameraFactory::mCameraModuleMethods = { |
489 | open: EmulatedCameraFactory::device_open |
490 | }; |
491 | |
492 | }; /* namespace android */ |
493 |