blob: 0f6a6fa9a6350b843ffecf2df320de8c804d3b1e
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 | int EmulatedCameraFactory::getValidCameraId() { |
131 | int iValidId = 0; |
132 | for (int i = 0; i < MAX_CAMERA_NUM; i++ ) { |
133 | if (0 == access(SENSOR_PATH[i], F_OK | R_OK | W_OK)) { |
134 | iValidId = i; |
135 | break; |
136 | } |
137 | } |
138 | return iValidId; |
139 | } |
140 | |
141 | /**************************************************************************** |
142 | * Camera HAL API handlers. |
143 | * |
144 | * Each handler simply verifies existence of an appropriate EmulatedBaseCamera |
145 | * instance, and dispatches the call to that instance. |
146 | * |
147 | ***************************************************************************/ |
148 | |
149 | int EmulatedCameraFactory::cameraDeviceOpen(int camera_id, hw_device_t** device) |
150 | { |
151 | ALOGV("%s: id = %d", __FUNCTION__, camera_id); |
152 | int valid_id; |
153 | *device = NULL; |
154 | |
155 | if (!isConstructedOK()) { |
156 | ALOGE("%s: EmulatedCameraFactory has failed to initialize", __FUNCTION__); |
157 | return -EINVAL; |
158 | } |
159 | |
160 | if (camera_id < 0 || camera_id >= getEmulatedCameraNum()) { |
161 | ALOGE("%s: Camera id %d is out of bounds (%d)", |
162 | __FUNCTION__, camera_id, getEmulatedCameraNum()); |
163 | return -ENODEV; |
164 | } |
165 | valid_id = getValidCameraId(); |
166 | //return mEmulatedCameras[camera_id]->connectCamera(device); |
167 | return mEmulatedCameras[valid_id]->connectCamera(device); |
168 | } |
169 | |
170 | int EmulatedCameraFactory::getCameraInfo(int camera_id, struct camera_info* info) |
171 | { |
172 | ALOGV("%s: id = %d", __FUNCTION__, camera_id); |
173 | int valid_id; |
174 | if (!isConstructedOK()) { |
175 | ALOGE("%s: EmulatedCameraFactory has failed to initialize", __FUNCTION__); |
176 | return -EINVAL; |
177 | } |
178 | |
179 | if (camera_id < 0 || camera_id >= getEmulatedCameraNum()) { |
180 | ALOGE("%s: Camera id %d is out of bounds (%d)", |
181 | __FUNCTION__, camera_id, getEmulatedCameraNum()); |
182 | return -ENODEV; |
183 | } |
184 | valid_id = getValidCameraId(); |
185 | //return mEmulatedCameras[camera_id]->getCameraInfo(info); |
186 | return mEmulatedCameras[valid_id]->getCameraInfo(info); |
187 | } |
188 | |
189 | int EmulatedCameraFactory::setCallbacks( |
190 | const camera_module_callbacks_t *callbacks) |
191 | { |
192 | ALOGV("%s: callbacks = %p", __FUNCTION__, callbacks); |
193 | |
194 | mCallbacks = callbacks; |
195 | |
196 | return OK; |
197 | } |
198 | |
199 | static int get_tag_count(const vendor_tag_ops_t* ops) |
200 | { |
201 | return gVendorTags.getTagCount(ops); |
202 | } |
203 | static void get_all_tags(const vendor_tag_ops_t* ops, uint32_t* tag_array) |
204 | { |
205 | gVendorTags.getAllTags(ops, tag_array); |
206 | } |
207 | static const char* get_section_name(const vendor_tag_ops_t* ops, uint32_t tag) |
208 | { |
209 | return gVendorTags.getSectionName(ops, tag); |
210 | } |
211 | static const char* get_tag_name(const vendor_tag_ops_t* ops, uint32_t tag) |
212 | { |
213 | return gVendorTags.getTagName(ops, tag); |
214 | } |
215 | static int get_tag_type(const vendor_tag_ops_t* ops, uint32_t tag) |
216 | { |
217 | return gVendorTags.getTagType(ops, tag); |
218 | } |
219 | void EmulatedCameraFactory::getvendortagops(vendor_tag_ops_t* ops) |
220 | { |
221 | ALOGV("%s : ops=%p", __func__, ops); |
222 | ops->get_tag_count = get_tag_count; |
223 | ops->get_all_tags = get_all_tags; |
224 | ops->get_section_name = get_section_name; |
225 | ops->get_tag_name = get_tag_name; |
226 | ops->get_tag_type = get_tag_type; |
227 | } |
228 | /**************************************************************************** |
229 | * Camera HAL API callbacks. |
230 | ***************************************************************************/ |
231 | |
232 | EmulatedBaseCamera* EmulatedCameraFactory::getValidCameraOject() |
233 | { |
234 | EmulatedBaseCamera* cam = NULL; |
235 | for (int i = 0; i < MAX_CAMERA_NUM; i++) { |
236 | if (mEmulatedCameras[i] != NULL) { |
237 | cam = mEmulatedCameras[i]; |
238 | break; |
239 | } |
240 | } |
241 | return cam; |
242 | } |
243 | |
244 | int EmulatedCameraFactory::getValidCameraOjectId() |
245 | { |
246 | int j =0; |
247 | for (int i = 0; i < MAX_CAMERA_NUM; i++) { |
248 | if (mEmulatedCameras[i] != NULL) { |
249 | j = i; |
250 | break; |
251 | } |
252 | } |
253 | return j; |
254 | } |
255 | |
256 | int EmulatedCameraFactory::device_open(const hw_module_t* module, |
257 | const char* name, |
258 | hw_device_t** device) |
259 | { |
260 | /* |
261 | * Simply verify the parameters, and dispatch the call inside the |
262 | * EmulatedCameraFactory instance. |
263 | */ |
264 | |
265 | if (module != &HAL_MODULE_INFO_SYM.common) { |
266 | ALOGE("%s: Invalid module %p expected %p", |
267 | __FUNCTION__, module, &HAL_MODULE_INFO_SYM.common); |
268 | return -EINVAL; |
269 | } |
270 | if (name == NULL) { |
271 | ALOGE("%s: NULL name is not expected here", __FUNCTION__); |
272 | return -EINVAL; |
273 | } |
274 | |
275 | return gEmulatedCameraFactory.cameraDeviceOpen(atoi(name), device); |
276 | } |
277 | |
278 | int EmulatedCameraFactory::get_number_of_cameras(void) |
279 | { |
280 | int i = 0; |
281 | EmulatedBaseCamera* cam = gEmulatedCameraFactory.getValidCameraOject(); |
282 | while (i < 6) { |
283 | if (cam != NULL) { |
284 | if (!cam->getHotplugStatus()) { |
285 | DBG_LOGA("here we wait usb camera plug"); |
286 | usleep(50000); |
287 | i++; |
288 | } else { |
289 | break; |
290 | } |
291 | } else { |
292 | break; |
293 | } |
294 | } |
295 | return gEmulatedCameraFactory.getEmulatedCameraNum(); |
296 | } |
297 | |
298 | int EmulatedCameraFactory::get_camera_info(int camera_id, |
299 | struct camera_info* info) |
300 | { |
301 | return gEmulatedCameraFactory.getCameraInfo(camera_id, info); |
302 | } |
303 | |
304 | int EmulatedCameraFactory::set_callbacks( |
305 | const camera_module_callbacks_t *callbacks) |
306 | { |
307 | return gEmulatedCameraFactory.setCallbacks(callbacks); |
308 | } |
309 | |
310 | void EmulatedCameraFactory::get_vendor_tag_ops(vendor_tag_ops_t* ops) |
311 | { |
312 | gEmulatedCameraFactory.getvendortagops(ops); |
313 | } |
314 | /******************************************************************************** |
315 | * Internal API |
316 | *******************************************************************************/ |
317 | |
318 | /* |
319 | * Camera information tokens passed in response to the "list" factory query. |
320 | */ |
321 | |
322 | /* Device name token. */ |
323 | static const char lListNameToken[] = "name="; |
324 | /* Frame dimensions token. */ |
325 | static const char lListDimsToken[] = "framedims="; |
326 | /* Facing direction token. */ |
327 | static const char lListDirToken[] = "dir="; |
328 | |
329 | void EmulatedCameraFactory::createQemuCameras() |
330 | { |
331 | #if 0 |
332 | /* Obtain camera list. */ |
333 | char* camera_list = NULL; |
334 | status_t res = mQemuClient.listCameras(&camera_list); |
335 | /* Empty list, or list containing just an EOL means that there were no |
336 | * connected cameras found. */ |
337 | if (res != NO_ERROR || camera_list == NULL || *camera_list == '\0' || |
338 | *camera_list == '\n') { |
339 | if (camera_list != NULL) { |
340 | free(camera_list); |
341 | } |
342 | return; |
343 | } |
344 | |
345 | /* |
346 | * Calculate number of connected cameras. Number of EOLs in the camera list |
347 | * is the number of the connected cameras. |
348 | */ |
349 | |
350 | int num = 0; |
351 | const char* eol = strchr(camera_list, '\n'); |
352 | while (eol != NULL) { |
353 | num++; |
354 | eol = strchr(eol + 1, '\n'); |
355 | } |
356 | |
357 | /* Allocate the array for emulated camera instances. Note that we allocate |
358 | * two more entries for back and front fake camera emulation. */ |
359 | mEmulatedCameras = new EmulatedBaseCamera*[num + 2]; |
360 | if (mEmulatedCameras == NULL) { |
361 | ALOGE("%s: Unable to allocate emulated camera array for %d entries", |
362 | __FUNCTION__, num + 1); |
363 | free(camera_list); |
364 | return; |
365 | } |
366 | memset(mEmulatedCameras, 0, sizeof(EmulatedBaseCamera*) * (num + 1)); |
367 | |
368 | /* |
369 | * Iterate the list, creating, and initializin emulated qemu cameras for each |
370 | * entry (line) in the list. |
371 | */ |
372 | |
373 | int index = 0; |
374 | char* cur_entry = camera_list; |
375 | while (cur_entry != NULL && *cur_entry != '\0' && index < num) { |
376 | /* Find the end of the current camera entry, and terminate it with zero |
377 | * for simpler string manipulation. */ |
378 | char* next_entry = strchr(cur_entry, '\n'); |
379 | if (next_entry != NULL) { |
380 | *next_entry = '\0'; |
381 | next_entry++; // Start of the next entry. |
382 | } |
383 | |
384 | /* Find 'name', 'framedims', and 'dir' tokens that are required here. */ |
385 | char* name_start = strstr(cur_entry, lListNameToken); |
386 | char* dim_start = strstr(cur_entry, lListDimsToken); |
387 | char* dir_start = strstr(cur_entry, lListDirToken); |
388 | if (name_start != NULL && dim_start != NULL && dir_start != NULL) { |
389 | /* Advance to the token values. */ |
390 | name_start += strlen(lListNameToken); |
391 | dim_start += strlen(lListDimsToken); |
392 | dir_start += strlen(lListDirToken); |
393 | |
394 | /* Terminate token values with zero. */ |
395 | char* s = strchr(name_start, ' '); |
396 | if (s != NULL) { |
397 | *s = '\0'; |
398 | } |
399 | s = strchr(dim_start, ' '); |
400 | if (s != NULL) { |
401 | *s = '\0'; |
402 | } |
403 | s = strchr(dir_start, ' '); |
404 | if (s != NULL) { |
405 | *s = '\0'; |
406 | } |
407 | |
408 | /* Create and initialize qemu camera. */ |
409 | EmulatedQemuCamera* qemu_cam = |
410 | new EmulatedQemuCamera(index, &HAL_MODULE_INFO_SYM.common); |
411 | if (NULL != qemu_cam) { |
412 | res = qemu_cam->Initialize(name_start, dim_start, dir_start); |
413 | if (res == NO_ERROR) { |
414 | mEmulatedCameras[index] = qemu_cam; |
415 | index++; |
416 | } else { |
417 | delete qemu_cam; |
418 | } |
419 | } else { |
420 | ALOGE("%s: Unable to instantiate EmulatedQemuCamera", |
421 | __FUNCTION__); |
422 | } |
423 | } else { |
424 | ALOGW("%s: Bad camera information: %s", __FUNCTION__, cur_entry); |
425 | } |
426 | |
427 | cur_entry = next_entry; |
428 | } |
429 | |
430 | mEmulatedCameraNum = index; |
431 | #else |
432 | CAMHAL_LOGDA("delete this function"); |
433 | #endif |
434 | } |
435 | |
436 | bool EmulatedCameraFactory::isFakeCameraFacingBack(int cameraId) |
437 | { |
438 | if (cameraId%mEmulatedCameraNum == 1) |
439 | return false; |
440 | |
441 | return true; |
442 | } |
443 | |
444 | int EmulatedCameraFactory::getFakeCameraHalVersion(int cameraId) |
445 | { |
446 | /* Defined by 'qemu.sf.back_camera_hal_version' boot property: if the |
447 | * property doesn't exist, it is assumed to be 1. */ |
448 | #if 0 |
449 | char prop[PROPERTY_VALUE_MAX]; |
450 | if (property_get("qemu.sf.back_camera_hal", prop, NULL) > 0) { |
451 | char *prop_end = prop; |
452 | int val = strtol(prop, &prop_end, 10); |
453 | if (*prop_end == '\0') { |
454 | return val; |
455 | } |
456 | // Badly formatted property, should just be a number |
457 | ALOGE("qemu.sf.back_camera_hal is not a number: %s", prop); |
458 | } |
459 | return 1; |
460 | #else |
461 | cameraId = cameraId; |
462 | return 3; |
463 | #endif |
464 | } |
465 | |
466 | void EmulatedCameraFactory::onStatusChanged(int cameraId, int newStatus) |
467 | { |
468 | status_t res; |
469 | char dev_name[128]; |
470 | int i = 0 , j = 0; |
471 | int m = 0, n = 0; |
472 | //EmulatedBaseCamera *cam = mEmulatedCameras[cameraId]; |
473 | const camera_module_callbacks_t* cb = mCallbacks; |
474 | sprintf(dev_name, "%s%d", "/dev/video", cameraId); |
475 | |
476 | /* ignore cameraid >= MAX_CAMERA_NUM to avoid overflow, we now have |
477 | * ion device with device like /dev/video13 |
478 | */ |
479 | if (cameraId >= MAX_CAMERA_NUM) |
480 | return; |
481 | |
482 | CAMHAL_LOGDB("mEmulatedCameraNum =%d\n", mEmulatedCameraNum); |
483 | n = getValidCameraOjectId(); |
484 | if ((n != cameraId) && (mEmulatedCameras[n] != NULL)) { |
485 | mEmulatedCameras[n]->unplugCamera(); |
486 | delete mEmulatedCameras[n]; |
487 | mEmulatedCameras[n] = NULL; |
488 | } |
489 | |
490 | EmulatedBaseCamera *cam = mEmulatedCameras[cameraId]; |
491 | |
492 | if ((!cam) && (newStatus == CAMERA_DEVICE_STATUS_PRESENT)) { |
493 | /*suppose only usb camera produce uevent, and it is facing back*/ |
494 | cam = new EmulatedFakeCamera3(cameraId, &HAL_MODULE_INFO_SYM.common); |
495 | if (cam != NULL) { |
496 | CAMHAL_LOGDB("%s: new camera device version is %d", __FUNCTION__, |
497 | getFakeCameraHalVersion(cameraId)); |
498 | //sleep 10ms for /dev/video* create |
499 | usleep(50000); |
500 | while (i < 20) { |
501 | if (0 == access(dev_name, F_OK | R_OK | W_OK)) { |
502 | DBG_LOGB("access %s success\n", dev_name); |
503 | break; |
504 | } else { |
505 | CAMHAL_LOGDB("access %s fail , i = %d .\n", dev_name,i); |
506 | usleep(50000); |
507 | i++; |
508 | } |
509 | } |
510 | res = cam->Initialize(); |
511 | if (res != NO_ERROR) { |
512 | ALOGE("%s: Unable to intialize camera %d: %s (%d)", |
513 | __FUNCTION__, cameraId, strerror(-res), res); |
514 | delete cam; |
515 | return ; |
516 | } |
517 | |
518 | /* Open the camera. then send the callback to framework*/ |
519 | mEmulatedCameras[cameraId] = cam; |
520 | mEmulatedCameraNum ++; |
521 | cam->plugCamera(); |
522 | if (cb != NULL && cb->camera_device_status_change != NULL) { |
523 | cb->camera_device_status_change(cb, cameraId, newStatus); |
524 | } |
525 | } |
526 | return ; |
527 | } |
528 | |
529 | CAMHAL_LOGDB("mEmulatedCameraNum =%d\n", mEmulatedCameraNum); |
530 | |
531 | /** |
532 | * (Order is important) |
533 | * Send the callback first to framework, THEN close the camera. |
534 | */ |
535 | |
536 | if (newStatus == cam->getHotplugStatus()) { |
537 | CAMHAL_LOGDB("%s: Ignoring transition to the same status", __FUNCTION__); |
538 | return; |
539 | } |
540 | |
541 | /*here we don't notify cameraservice close camera, let app to close camera, or will generate crash*/ |
542 | #if 0 |
543 | CAMHAL_LOGDB("mEmulatedCameraNum =%d\n", mEmulatedCameraNum); |
544 | if (cb != NULL && cb->camera_device_status_change != NULL) { |
545 | cb->camera_device_status_change(cb, cameraId, newStatus); |
546 | } |
547 | #endif |
548 | |
549 | CAMHAL_LOGDB("mEmulatedCameraNum =%d\n", mEmulatedCameraNum); |
550 | |
551 | if (newStatus == CAMERA_DEVICE_STATUS_NOT_PRESENT) { |
552 | j = getValidCameraOjectId(); |
553 | while (m < 2000) { |
554 | if (mEmulatedCameras[j] != NULL) { |
555 | if (mEmulatedCameras[j]->getCameraStatus()) { |
556 | DBG_LOGA("start to delete EmulatedFakeCamera3 object"); |
557 | cam->unplugCamera(); |
558 | delete mEmulatedCameras[j]; |
559 | mEmulatedCameras[j] = NULL; |
560 | } else { |
561 | usleep(5000); |
562 | m++; |
563 | } |
564 | } else { |
565 | break; |
566 | } |
567 | } |
568 | mEmulatedCameraNum --; |
569 | } else if (newStatus == CAMERA_DEVICE_STATUS_PRESENT) { |
570 | CAMHAL_LOGDA("camera plugged again?\n"); |
571 | cam->plugCamera(); |
572 | } |
573 | CAMHAL_LOGDB("mEmulatedCameraNum =%d\n", mEmulatedCameraNum); |
574 | |
575 | } |
576 | |
577 | /******************************************************************************** |
578 | * Initializer for the static member structure. |
579 | *******************************************************************************/ |
580 | |
581 | /* Entry point for camera HAL API. */ |
582 | struct hw_module_methods_t EmulatedCameraFactory::mCameraModuleMethods = { |
583 | open: EmulatedCameraFactory::device_open |
584 | }; |
585 | |
586 | }; /* namespace android */ |
587 |