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 emulated camera service implementation.
19 */
20
21 #include "qemu-common.h"
22 #include "android/globals.h" /* for android_hw */
23 #include "android/hw-qemud.h"
24 #include "android/utils/misc.h"
25 #include "android/utils/system.h"
26 #include "android/utils/debug.h"
27 #include "android/camera/camera-capture.h"
28 #include "android/camera/camera-format-converters.h"
29 #include "android/camera/camera-service.h"
30
31 #define E(...) derror(__VA_ARGS__)
32 #define W(...) dwarning(__VA_ARGS__)
33 #define D(...) VERBOSE_PRINT(camera,__VA_ARGS__)
34 #define D_ACTIVE VERBOSE_CHECK(camera)
35
36 /* the T(...) macro is used to dump traffic */
37 #define T_ACTIVE 0
38
39 #if T_ACTIVE
40 #define T(...) VERBOSE_PRINT(camera,__VA_ARGS__)
41 #else
42 #define T(...) ((void)0)
43 #endif
44
45 /* Defines name of the camera service. */
46 #define SERVICE_NAME "camera"
47
48 /* Maximum number of supported emulated cameras. */
49 #define MAX_CAMERA 8
50
51 /* Camera sevice descriptor. */
52 typedef struct CameraServiceDesc CameraServiceDesc;
53 struct CameraServiceDesc {
54 /* Information about camera devices connected to the host.
55 * Note that once initialized, entries in this array are considered to be
56 * constant. */
57 CameraInfo camera_info[MAX_CAMERA];
58 /* Number of camera devices connected to the host. */
59 int camera_count;
60 };
61
62 /* One and only one camera service. */
63 static CameraServiceDesc _camera_service_desc;
64
65 /********************************************************************************
66 * Helper routines
67 *******************************************************************************/
68
69 /* Extracts query name, and (optionally) query parameters from the query string.
70 * Param:
71 * query - Query string. Query string in the camera service are formatted as such:
72 * "<query name>[ <parameters>]",
73 * where parameters are optional, and if present, must be separated from the
74 * query name with a single ' '. See comments to get_token_value routine
75 * for the format of the parameters string.
76 * query_name - Upon success contains query name extracted from the query
77 * string.
78 * query_name_size - Buffer size for 'query_name' string.
79 * query_param - Upon success contains a pointer to the beginning of the query
80 * parameters. If query has no parameters, NULL will be passed back with
81 * this parameter. This parameter is optional and can be NULL.
82 * Return:
83 * 0 on success, or number of bytes required for query name if 'query_name'
84 * string buffer was too small to contain it.
85 */
86 static int
_parse_query(const char * query,char * query_name,int query_name_size,const char ** query_param)87 _parse_query(const char* query,
88 char* query_name,
89 int query_name_size,
90 const char** query_param)
91 {
92 /* Extract query name. */
93 const char* qend = strchr(query, ' ');
94 if (qend == NULL) {
95 qend = query + strlen(query);
96 }
97 if ((qend - query) >= query_name_size) {
98 return qend - query + 1;
99 }
100 memcpy(query_name, query, qend - query);
101 query_name[qend - query] = '\0';
102
103 /* Calculate query parameters pointer (if needed) */
104 if (query_param != NULL) {
105 if (*qend == ' ') {
106 qend++;
107 }
108 *query_param = (*qend == '\0') ? NULL : qend;
109 }
110
111 return 0;
112 }
113
114 /* Appends one string to another, growing the destination string buffer if
115 * needed.
116 * Param:
117 * str_buffer - Contains pointer to the destination string buffer. Content of
118 * this parameter can be NULL. Note that content of this parameter will
119 * change if string buffer has been reallocated.
120 * str_buf_size - Contains current buffer size of the string, addressed by
121 * 'str_buffer' parameter. Note that content of this parameter will change
122 * if string buffer has been reallocated.
123 * str - String to append.
124 * Return:
125 * 0 on success, or -1 on failure (memory allocation).
126 */
127 static int
_append_string(char ** str_buf,size_t * str_buf_size,const char * str)128 _append_string(char** str_buf, size_t* str_buf_size, const char* str)
129 {
130 const size_t offset = (*str_buf != NULL) ? strlen(*str_buf) : 0;
131 const size_t append_bytes = strlen(str) + 1;
132
133 /* Make sure these two match. */
134 if (*str_buf == NULL) {
135 *str_buf_size = 0;
136 }
137
138 if ((offset + append_bytes) > *str_buf_size) {
139 /* Reallocate string, so it can fit what's being append to it. Note that
140 * we reallocate a bit bigger buffer than is needed in order to minimize
141 * number of memory allocation calls in case there are more "appends"
142 * coming. */
143 const size_t required_mem = offset + append_bytes + 256;
144 char* new_buf = (char*)realloc(*str_buf, required_mem);
145 if (new_buf == NULL) {
146 E("%s: Unable to allocate %d bytes for a string",
147 __FUNCTION__, required_mem);
148 return -1;
149 }
150 *str_buf = new_buf;
151 *str_buf_size = required_mem;
152 }
153 memcpy(*str_buf + offset, str, append_bytes);
154
155 return 0;
156 }
157
158 /* Represents camera information as a string formatted as follows:
159 * 'name=<devname> channel=<num> pix=<format> facing=<direction> framedims=<widh1xheight1,...>\n'
160 * Param:
161 * ci - Camera information descriptor to convert into a string.
162 * str - Pointer to the string buffer where to save the converted camera
163 * information descriptor. On entry, content of this parameter can be NULL.
164 * Note that string buffer addressed with this parameter may be reallocated
165 * in this routine, so (if not NULL) it must contain a buffer allocated with
166 * malloc. The caller is responsible for freeing string buffer returned in
167 * this parameter.
168 * str_size - Contains byte size of the buffer addressed by 'str' parameter.
169 * Return:
170 * 0 on success, or != 0 on failure.
171 */
172 static int
_camera_info_to_string(const CameraInfo * ci,char ** str,size_t * str_size)173 _camera_info_to_string(const CameraInfo* ci, char** str, size_t* str_size) {
174 int res;
175 int n;
176 char tmp[128];
177
178 /* Append device name. */
179 snprintf(tmp, sizeof(tmp), "name=%s ", ci->device_name);
180 res = _append_string(str, str_size, tmp);
181 if (res) {
182 return res;
183 }
184 /* Append input channel. */
185 snprintf(tmp, sizeof(tmp), "channel=%d ", ci->inp_channel);
186 res = _append_string(str, str_size, tmp);
187 if (res) {
188 return res;
189 }
190 /* Append pixel format. */
191 snprintf(tmp, sizeof(tmp), "pix=%d ", ci->pixel_format);
192 res = _append_string(str, str_size, tmp);
193 if (res) {
194 return res;
195 }
196 /* Append direction. */
197 snprintf(tmp, sizeof(tmp), "dir=%s ", ci->direction);
198 res = _append_string(str, str_size, tmp);
199 if (res) {
200 return res;
201 }
202 /* Append supported frame sizes. */
203 snprintf(tmp, sizeof(tmp), "framedims=%dx%d",
204 ci->frame_sizes[0].width, ci->frame_sizes[0].height);
205 res = _append_string(str, str_size, tmp);
206 if (res) {
207 return res;
208 }
209 for (n = 1; n < ci->frame_sizes_num; n++) {
210 snprintf(tmp, sizeof(tmp), ",%dx%d",
211 ci->frame_sizes[n].width, ci->frame_sizes[n].height);
212 res = _append_string(str, str_size, tmp);
213 if (res) {
214 return res;
215 }
216 }
217
218 /* Stringified camera properties should end with EOL. */
219 return _append_string(str, str_size, "\n");
220 }
221
222 /* Gets camera information matching a display name.
223 * Param:
224 * disp_name - Display name to match.
225 * arr - Array of camera informations.
226 * num - Number of elements in the array.
227 * Return:
228 * Matching camera information, or NULL if matching camera information for the
229 * given display name has not been found in the array.
230 */
231 static CameraInfo*
_camera_info_get_by_display_name(const char * disp_name,CameraInfo * arr,int num)232 _camera_info_get_by_display_name(const char* disp_name, CameraInfo* arr, int num)
233 {
234 int n;
235 for (n = 0; n < num; n++) {
236 if (!arr[n].in_use && arr[n].display_name != NULL &&
237 !strcmp(arr[n].display_name, disp_name)) {
238 return &arr[n];
239 }
240 }
241 return NULL;
242 }
243
244 /* Gets camera information matching a device name.
245 * Param:
246 * device_name - Device name to match.
247 * arr - Array of camera informations.
248 * num - Number of elements in the array.
249 * Return:
250 * Matching camera information, or NULL if matching camera information for the
251 * given device name has not been found in the array.
252 */
253 static CameraInfo*
_camera_info_get_by_device_name(const char * device_name,CameraInfo * arr,int num)254 _camera_info_get_by_device_name(const char* device_name, CameraInfo* arr, int num)
255 {
256 int n;
257 for (n = 0; n < num; n++) {
258 if (arr[n].device_name != NULL && !strcmp(arr[n].device_name, device_name)) {
259 return &arr[n];
260 }
261 }
262 return NULL;
263 }
264
265 /********************************************************************************
266 * CameraServiceDesc API
267 *******************************************************************************/
268
269 /* Initialized webcam emulation record in camera service descriptor.
270 * Param:
271 * csd - Camera service descriptor to initialize a record in.
272 * disp_name - Display name of a web camera ('webcam<N>') to use for emulation.
273 * dir - Direction ('back', or 'front') that emulated camera is facing.
274 * ci, ci_cnt - Array of webcam information for enumerated web cameras connected
275 * to the host.
276 */
277 static void
_wecam_setup(CameraServiceDesc * csd,const char * disp_name,const char * dir,CameraInfo * ci,int ci_cnt)278 _wecam_setup(CameraServiceDesc* csd,
279 const char* disp_name,
280 const char* dir,
281 CameraInfo* ci,
282 int ci_cnt)
283 {
284 /* Find webcam record in the list of enumerated web cameras. */
285 CameraInfo* found = _camera_info_get_by_display_name(disp_name, ci, ci_cnt);
286 if (found == NULL) {
287 W("Camera name '%s' is not found in the list of connected cameras.\n"
288 "Use '-webcam-list' emulator option to obtain the list of connected camera names.\n",
289 disp_name);
290 return;
291 }
292
293 /* Save to the camera info array that will be used by the service. */
294 memcpy(csd->camera_info + csd->camera_count, found, sizeof(CameraInfo));
295 /* This camera is taken. */
296 found->in_use = 1;
297 /* Update direction parameter. */
298 if (csd->camera_info[csd->camera_count].direction != NULL) {
299 free(csd->camera_info[csd->camera_count].direction);
300 }
301 csd->camera_info[csd->camera_count].direction = ASTRDUP(dir);
302 D("Camera %d '%s' connected to '%s' facing %s using %.4s pixel format",
303 csd->camera_count, csd->camera_info[csd->camera_count].display_name,
304 csd->camera_info[csd->camera_count].device_name,
305 csd->camera_info[csd->camera_count].direction,
306 (const char*)(&csd->camera_info[csd->camera_count].pixel_format));
307 csd->camera_count++;
308 }
309
310 /* Initializes camera service descriptor.
311 */
312 static void
_camera_service_init(CameraServiceDesc * csd)313 _camera_service_init(CameraServiceDesc* csd)
314 {
315 CameraInfo ci[MAX_CAMERA];
316 int connected_cnt;
317
318 /* Enumerate camera devices connected to the host. */
319 memset(ci, 0, sizeof(CameraInfo) * MAX_CAMERA);
320 memset(csd->camera_info, 0, sizeof(CameraInfo) * MAX_CAMERA);
321 csd->camera_count = 0;
322
323 /* Lets see if HW config uses web cameras. */
324 if (memcmp(android_hw->hw_camera_back, "webcam", 6) &&
325 memcmp(android_hw->hw_camera_front, "webcam", 6)) {
326 /* Web camera emulation is disabled. Skip enumeration of webcameras. */
327 return;
328 }
329
330 /* Enumerate web cameras connected to the host. */
331 connected_cnt = enumerate_camera_devices(ci, MAX_CAMERA);
332 if (connected_cnt <= 0) {
333 /* Nothing is connected - nothing to emulate. */
334 return;
335 }
336
337 /* Set up back camera emulation. */
338 if (!memcmp(android_hw->hw_camera_back, "webcam", 6)) {
339 _wecam_setup(csd, android_hw->hw_camera_back, "back", ci, connected_cnt);
340 }
341
342 /* Set up front camera emulation. */
343 if (!memcmp(android_hw->hw_camera_front, "webcam", 6)) {
344 _wecam_setup(csd, android_hw->hw_camera_front, "front", ci, connected_cnt);
345 }
346 }
347
348 /* Gets camera information for the given camera device name.
349 * Param:
350 * cs - Initialized camera service descriptor.
351 * device_name - Camera's device name to look up the information for.
352 * Return:
353 * Camera information pointer on success, or NULL if no camera information has
354 * been found for the given device name.
355 */
356 static CameraInfo*
_camera_service_get_camera_info_by_device_name(CameraServiceDesc * cs,const char * device_name)357 _camera_service_get_camera_info_by_device_name(CameraServiceDesc* cs,
358 const char* device_name)
359 {
360 return _camera_info_get_by_device_name(device_name, cs->camera_info,
361 cs->camera_count);
362 }
363
364 /********************************************************************************
365 * Helpers for handling camera client queries
366 *******************************************************************************/
367
368 /* Formats paload size according to the protocol, and sends it to the client.
369 * To simplify endianess handling we convert payload size to an eight characters
370 * string, representing payload size value in hexadecimal format.
371 * Param:
372 * qc - Qemu client to send the payload size to.
373 * payload_size - Payload size to report to the client.
374 */
375 static void
_qemu_client_reply_payload(QemudClient * qc,size_t payload_size)376 _qemu_client_reply_payload(QemudClient* qc, size_t payload_size)
377 {
378 char payload_size_str[9];
379 snprintf(payload_size_str, sizeof(payload_size_str), "%08zx", payload_size);
380 qemud_client_send(qc, (const uint8_t*)payload_size_str, 8);
381 }
382
383 /*
384 * Prefixes for replies to camera client queries.
385 */
386
387 /* Success, no data to send in reply. */
388 #define OK_REPLY "ok"
389 /* Failure, no data to send in reply. */
390 #define KO_REPLY "ko"
391 /* Success, there are data to send in reply. */
392 #define OK_REPLY_DATA OK_REPLY ":"
393 /* Failure, there are data to send in reply. */
394 #define KO_REPLY_DATA KO_REPLY ":"
395
396 /* Builds and sends a reply to a query.
397 * All replies to a query in camera service have a prefix indicating whether the
398 * query has succeeded ("ok"), or failed ("ko"). The prefix can be followed by
399 * extra data, containing response to the query. In case there are extra data,
400 * they are separated from the prefix with a ':' character.
401 * Param:
402 * qc - Qemu client to send the reply to.
403 * ok_ko - An "ok", or "ko" selector, where 0 is for "ko", and !0 is for "ok".
404 * extra - Optional extra query data. Can be NULL.
405 * extra_size - Extra data size.
406 */
407 static void
_qemu_client_query_reply(QemudClient * qc,int ok_ko,const void * extra,size_t extra_size)408 _qemu_client_query_reply(QemudClient* qc,
409 int ok_ko,
410 const void* extra,
411 size_t extra_size)
412 {
413 const char* ok_ko_str;
414 size_t payload_size;
415
416 /* Make sure extra_size is 0 if extra is NULL. */
417 if (extra == NULL && extra_size != 0) {
418 W("%s: 'extra' = NULL, while 'extra_size' = %d",
419 __FUNCTION__, (int)extra_size);
420 extra_size = 0;
421 }
422
423 /* Calculate total payload size, and select appropriate 'ok'/'ko' prefix */
424 if (extra_size) {
425 /* 'extra' size + 2 'ok'/'ko' bytes + 1 ':' separator byte. */
426 payload_size = extra_size + 3;
427 ok_ko_str = ok_ko ? OK_REPLY_DATA : KO_REPLY_DATA;
428 } else {
429 /* No extra data: just zero-terminated 'ok'/'ko'. */
430 payload_size = 3;
431 ok_ko_str = ok_ko ? OK_REPLY : KO_REPLY;
432 }
433
434 /* Send payload size first. */
435 _qemu_client_reply_payload(qc, payload_size);
436 /* Send 'ok[:]'/'ko[:]' next. Note that if there is no extra data, we still
437 * need to send a zero-terminator for 'ok'/'ko' string instead of the ':'
438 * separator. So, one way or another, the prefix is always 3 bytes. */
439 qemud_client_send(qc, (const uint8_t*)ok_ko_str, 3);
440 /* Send extra data (if present). */
441 if (extra != NULL) {
442 qemud_client_send(qc, (const uint8_t*)extra, extra_size);
443 }
444 }
445
446 /* Replies query success ("OK") back to the client.
447 * Param:
448 * qc - Qemu client to send the reply to.
449 * ok_str - An optional string containing query results. Can be NULL.
450 */
451 static void
_qemu_client_reply_ok(QemudClient * qc,const char * ok_str)452 _qemu_client_reply_ok(QemudClient* qc, const char* ok_str)
453 {
454 _qemu_client_query_reply(qc, 1, ok_str,
455 (ok_str != NULL) ? (strlen(ok_str) + 1) : 0);
456 }
457
458 /* Replies query failure ("KO") back to the client.
459 * Param:
460 * qc - Qemu client to send the reply to.
461 * ko_str - An optional string containing reason for failure. Can be NULL.
462 */
463 static void
_qemu_client_reply_ko(QemudClient * qc,const char * ko_str)464 _qemu_client_reply_ko(QemudClient* qc, const char* ko_str)
465 {
466 _qemu_client_query_reply(qc, 0, ko_str,
467 (ko_str != NULL) ? (strlen(ko_str) + 1) : 0);
468 }
469
470 /********************************************************************************
471 * Camera Factory API
472 *******************************************************************************/
473
474 /* Handles 'list' query received from the Factory client.
475 * Response to this query is a string that represents each connected camera in
476 * this format: 'name=devname framedims=widh1xheight1,widh2xheight2,widhNxheightN\n'
477 * Strings, representing each camera are separated with EOL symbol.
478 * Param:
479 * csd, client - Factory serivice, and client.
480 * Return:
481 * 0 on success, or != 0 on failure.
482 */
483 static int
_factory_client_list_cameras(CameraServiceDesc * csd,QemudClient * client)484 _factory_client_list_cameras(CameraServiceDesc* csd, QemudClient* client)
485 {
486 int n;
487 size_t reply_size = 0;
488 char* reply = NULL;
489
490 /* Lets see if there was anything found... */
491 if (csd->camera_count == 0) {
492 /* No cameras connected to the host. Reply with "\n" */
493 _qemu_client_reply_ok(client, "\n");
494 return 0;
495 }
496
497 /* "Stringify" each camera information into the reply string. */
498 for (n = 0; n < csd->camera_count; n++) {
499 const int res =
500 _camera_info_to_string(csd->camera_info + n, &reply, &reply_size);
501 if (res) {
502 if (reply != NULL) {
503 free(reply);
504 }
505 _qemu_client_reply_ko(client, "Memory allocation error");
506 return res;
507 }
508 }
509
510 D("%s Replied: %s", __FUNCTION__, reply);
511 _qemu_client_reply_ok(client, reply);
512 free(reply);
513
514 return 0;
515 }
516
517 /* Handles a message received from the emulated camera factory client.
518 * Queries received here are represented as strings:
519 * 'list' - Queries list of cameras connected to the host.
520 * Param:
521 * opaque - Camera service descriptor.
522 * msg, msglen - Message received from the camera factory client.
523 * client - Camera factory client pipe.
524 */
525 static void
_factory_client_recv(void * opaque,uint8_t * msg,int msglen,QemudClient * client)526 _factory_client_recv(void* opaque,
527 uint8_t* msg,
528 int msglen,
529 QemudClient* client)
530 {
531 /*
532 * Emulated camera factory client queries.
533 */
534
535 /* List cameras connected to the host. */
536 static const char _query_list[] = "list";
537
538 CameraServiceDesc* csd = (CameraServiceDesc*)opaque;
539 char query_name[64];
540 const char* query_param = NULL;
541
542 /* Parse the query, extracting query name and parameters. */
543 if (_parse_query((const char*)msg, query_name, sizeof(query_name),
544 &query_param)) {
545 E("%s: Invalid format in query '%s'", __FUNCTION__, (const char*)msg);
546 _qemu_client_reply_ko(client, "Invalid query format");
547 return;
548 }
549
550 D("%s Camera factory query '%s'", __FUNCTION__, query_name);
551
552 /* Dispatch the query to an appropriate handler. */
553 if (!strcmp(query_name, _query_list)) {
554 /* This is a "list" query. */
555 _factory_client_list_cameras(csd, client);
556 } else {
557 E("%s: Unknown camera factory query name in '%s'",
558 __FUNCTION__, (const char*)msg);
559 _qemu_client_reply_ko(client, "Unknown query name");
560 }
561 }
562
563 /* Emulated camera factory client has been disconnected from the service. */
564 static void
_factory_client_close(void * opaque)565 _factory_client_close(void* opaque)
566 {
567 /* There is nothing to clean up here: factory service is just an alias for
568 * the "root" camera service, that doesn't require anything more, than camera
569 * dervice descriptor already provides. */
570 }
571
572 /********************************************************************************
573 * Camera client API
574 *******************************************************************************/
575
576 /* Describes an emulated camera client.
577 */
578 typedef struct CameraClient CameraClient;
579 struct CameraClient
580 {
581 /* Client name.
582 * On Linux this is the name of the camera device.
583 * On Windows this is the name of capturing window.
584 */
585 char* device_name;
586 /* Input channel to use to connect to the camera. */
587 int inp_channel;
588 /* Camera information. */
589 const CameraInfo* camera_info;
590 /* Emulated camera device descriptor. */
591 CameraDevice* camera;
592 /* Buffer allocated for video frames.
593 * Note that memory allocated for this buffer
594 * also contains preview framebuffer. */
595 uint8_t* video_frame;
596 /* Preview frame buffer.
597 * This address points inside the 'video_frame' buffer. */
598 uint16_t* preview_frame;
599 /* Byte size of the videoframe buffer. */
600 size_t video_frame_size;
601 /* Byte size of the preview frame buffer. */
602 size_t preview_frame_size;
603 /* Pixel format required by the guest. */
604 uint32_t pixel_format;
605 /* Frame width. */
606 int width;
607 /* Frame height. */
608 int height;
609 /* Number of pixels in a frame buffer. */
610 int pixel_num;
611 /* Status of video and preview frame cache. */
612 int frames_cached;
613 };
614
615 /* Frees emulated camera client descriptor. */
616 static void
_camera_client_free(CameraClient * cc)617 _camera_client_free(CameraClient* cc)
618 {
619 /* The only exception to the "read only" rule: we have to mark the camera
620 * as being not used when we destroy a service for it. */
621 if (cc->camera_info != NULL) {
622 ((CameraInfo*)cc->camera_info)->in_use = 0;
623 }
624 if (cc->camera != NULL) {
625 camera_device_close(cc->camera);
626 }
627 if (cc->video_frame != NULL) {
628 free(cc->video_frame);
629 }
630 if (cc->device_name != NULL) {
631 free(cc->device_name);
632 }
633
634 AFREE(cc);
635 }
636
637 /* Creates descriptor for a connecting emulated camera client.
638 * Param:
639 * csd - Camera service descriptor.
640 * param - Client parameters. Must be formatted as described in comments to
641 * get_token_value routine, and must contain at least 'name' parameter,
642 * identifiying the camera device to create the service for. Also parameters
643 * may contain a decimal 'inp_channel' parameter, selecting the input
644 * channel to use when communicating with the camera device.
645 * Return:
646 * Emulated camera client descriptor on success, or NULL on failure.
647 */
648 static CameraClient*
_camera_client_create(CameraServiceDesc * csd,const char * param)649 _camera_client_create(CameraServiceDesc* csd, const char* param)
650 {
651 CameraClient* cc;
652 CameraInfo* ci;
653 int res;
654 ANEW0(cc);
655
656 /*
657 * Parse parameter string, containing camera client properties.
658 */
659
660 /* Pull required device name. */
661 if (get_token_value_alloc(param, "name", &cc->device_name)) {
662 E("%s: Allocation failure, or required 'name' parameter is missing, or misformed in '%s'",
663 __FUNCTION__, param);
664 return NULL;
665 }
666
667 /* Pull optional input channel. */
668 res = get_token_value_int(param, "inp_channel", &cc->inp_channel);
669 if (res != 0) {
670 if (res == -1) {
671 /* 'inp_channel' parameter has been ommited. Use default input
672 * channel, which is zero. */
673 cc->inp_channel = 0;
674 } else {
675 E("%s: 'inp_channel' parameter is misformed in '%s'",
676 __FUNCTION__, param);
677 return NULL;
678 }
679 }
680
681 /* Get camera info for the emulated camera represented with this service.
682 * Array of camera information records has been created when the camera
683 * service was enumerating camera devices during the service initialization.
684 * By the camera service protocol, camera service clients must first obtain
685 * list of enumerated cameras via the 'list' query to the camera service, and
686 * then use device name reported in the list to connect to an emulated camera
687 * service. So, if camera information for the given device name is not found
688 * in the array, we fail this connection due to protocol violation. */
689 ci = _camera_service_get_camera_info_by_device_name(csd, cc->device_name);
690 if (ci == NULL) {
691 E("%s: Cannot find camera info for device '%s'",
692 __FUNCTION__, cc->device_name);
693 _camera_client_free(cc);
694 return NULL;
695 }
696
697 /* We can't allow multiple camera services for a single camera device, Lets
698 * make sure that there is no client created for this camera. */
699 if (ci->in_use) {
700 E("%s: Camera device '%s' is in use", __FUNCTION__, cc->device_name);
701 _camera_client_free(cc);
702 return NULL;
703 }
704
705 /* We're done. Set camera in use, and succeed the connection. */
706 ci->in_use = 1;
707 cc->camera_info = ci;
708
709 D("%s: Camera service is created for device '%s' using input channel %d",
710 __FUNCTION__, cc->device_name, cc->inp_channel);
711
712 return cc;
713 }
714
715 /********************************************************************************
716 * Camera client queries
717 *******************************************************************************/
718
719 /* Client has queried conection to the camera.
720 * Param:
721 * cc - Queried camera client descriptor.
722 * qc - Qemu client for the emulated camera.
723 * param - Query parameters. There are no parameters expected for this query.
724 */
725 static void
_camera_client_query_connect(CameraClient * cc,QemudClient * qc,const char * param)726 _camera_client_query_connect(CameraClient* cc, QemudClient* qc, const char* param)
727 {
728 if (cc->camera != NULL) {
729 /* Already connected. */
730 W("%s: Camera '%s' is already connected", __FUNCTION__, cc->device_name);
731 _qemu_client_reply_ok(qc, "Camera is already connected");
732 return;
733 }
734
735 /* Open camera device. */
736 cc->camera = camera_device_open(cc->device_name, cc->inp_channel);
737 if (cc->camera == NULL) {
738 E("%s: Unable to open camera device '%s'", __FUNCTION__, cc->device_name);
739 _qemu_client_reply_ko(qc, "Unable to open camera device.");
740 return;
741 }
742
743 D("%s: Camera device '%s' is now connected", __FUNCTION__, cc->device_name);
744
745 _qemu_client_reply_ok(qc, NULL);
746 }
747
748 /* Client has queried disconection from the camera.
749 * Param:
750 * cc - Queried camera client descriptor.
751 * qc - Qemu client for the emulated camera.
752 * param - Query parameters. There are no parameters expected for this query.
753 */
754 static void
_camera_client_query_disconnect(CameraClient * cc,QemudClient * qc,const char * param)755 _camera_client_query_disconnect(CameraClient* cc,
756 QemudClient* qc,
757 const char* param)
758 {
759 if (cc->camera == NULL) {
760 /* Already disconnected. */
761 W("%s: Camera '%s' is already disconnected", __FUNCTION__, cc->device_name);
762 _qemu_client_reply_ok(qc, "Camera is not connected");
763 return;
764 }
765
766 /* Before we can go ahead and disconnect, we must make sure that camera is
767 * not capturing frames. */
768 if (cc->video_frame != NULL) {
769 E("%s: Cannot disconnect camera '%s' while it is not stopped",
770 __FUNCTION__, cc->device_name);
771 _qemu_client_reply_ko(qc, "Camera is not stopped");
772 return;
773 }
774
775 /* Close camera device. */
776 camera_device_close(cc->camera);
777 cc->camera = NULL;
778
779 D("Camera device '%s' is now disconnected", cc->device_name);
780
781 _qemu_client_reply_ok(qc, NULL);
782 }
783
784 /* Client has queried the client to start capturing video.
785 * Param:
786 * cc - Queried camera client descriptor.
787 * qc - Qemu client for the emulated camera.
788 * param - Query parameters. Parameters for this query must contain a 'dim', and
789 * a 'pix' parameters, where 'dim' must be "dim=<width>x<height>", and 'pix'
790 * must be "pix=<format>", where 'width' and 'height' must be numerical
791 * values for the capturing video frame width, and height, and 'format' must
792 * be a numerical value for the pixel format of the video frames expected by
793 * the client. 'format' must be one of the V4L2_PIX_FMT_XXX values.
794 */
795 static void
_camera_client_query_start(CameraClient * cc,QemudClient * qc,const char * param)796 _camera_client_query_start(CameraClient* cc, QemudClient* qc, const char* param)
797 {
798 char* w;
799 char dim[64];
800 int width, height, pix_format;
801
802 /* Sanity check. */
803 if (cc->camera == NULL) {
804 /* Not connected. */
805 E("%s: Camera '%s' is not connected", __FUNCTION__, cc->device_name);
806 _qemu_client_reply_ko(qc, "Camera is not connected");
807 return;
808 }
809
810 /*
811 * Parse parameters.
812 */
813
814 if (param == NULL) {
815 E("%s: Missing parameters for the query", __FUNCTION__);
816 _qemu_client_reply_ko(qc, "Missing parameters for the query");
817 return;
818 }
819
820 /* Pull required 'dim' parameter. */
821 if (get_token_value(param, "dim", dim, sizeof(dim))) {
822 E("%s: Invalid or missing 'dim' parameter in '%s'", __FUNCTION__, param);
823 _qemu_client_reply_ko(qc, "Invalid or missing 'dim' parameter");
824 return;
825 }
826
827 /* Pull required 'pix' parameter. */
828 if (get_token_value_int(param, "pix", &pix_format)) {
829 E("%s: Invalid or missing 'pix' parameter in '%s'", __FUNCTION__, param);
830 _qemu_client_reply_ko(qc, "Invalid or missing 'pix' parameter");
831 return;
832 }
833
834 /* Parse 'dim' parameter, and get requested frame width and height. */
835 w = strchr(dim, 'x');
836 if (w == NULL || w[1] == '\0') {
837 E("%s: Invalid 'dim' parameter in '%s'", __FUNCTION__, param);
838 _qemu_client_reply_ko(qc, "Invalid 'dim' parameter");
839 return;
840 }
841 *w = '\0'; w++;
842 errno = 0;
843 width = strtoi(dim, NULL, 10);
844 height = strtoi(w, NULL, 10);
845 if (errno) {
846 E("%s: Invalid 'dim' parameter in '%s'", __FUNCTION__, param);
847 _qemu_client_reply_ko(qc, "Invalid 'dim' parameter");
848 return;
849 }
850
851 /* After collecting capture parameters lets see if camera has already
852 * started, and if so, lets see if parameters match. */
853 if (cc->video_frame != NULL) {
854 /* Already started. Match capture parameters. */
855 if (cc->pixel_format != pix_format ||cc->width != width ||
856 cc->height != height) {
857 /* Parameters match. Succeed the query. */
858 W("%s: Camera '%s' is already started", __FUNCTION__, cc->device_name);
859 _qemu_client_reply_ok(qc, "Camera is already started");
860 } else {
861 /* Parameters don't match. Fail the query. */
862 E("%s: Camera '%s' is already started, and parameters don't match:\n"
863 "Current %.4s[%dx%d] != requested %.4s[%dx%d]",
864 __FUNCTION__, cc->device_name, (const char*)&cc->pixel_format,
865 cc->width, cc->height, (const char*)&pix_format, width, height);
866 _qemu_client_reply_ko(qc,
867 "Camera is already started with different capturing parameters");
868 }
869 return;
870 }
871
872 /*
873 * Start the camera.
874 */
875
876 /* Save capturing parameters. */
877 cc->pixel_format = pix_format;
878 cc->width = width;
879 cc->height = height;
880 cc->pixel_num = cc->width * cc->height;
881 cc->frames_cached = 0;
882
883 /* Make sure that pixel format is known, and calculate video framebuffer size
884 * along the lines. */
885 switch (cc->pixel_format) {
886 case V4L2_PIX_FMT_YUV420:
887 case V4L2_PIX_FMT_YVU420:
888 case V4L2_PIX_FMT_NV12:
889 case V4L2_PIX_FMT_NV21:
890 cc->video_frame_size = (cc->pixel_num * 12) / 8;
891 break;
892
893 default:
894 E("%s: Unknown pixel format %.4s",
895 __FUNCTION__, (char*)&cc->pixel_format);
896 _qemu_client_reply_ko(qc, "Pixel format is unknown");
897 return;
898 }
899
900 /* Make sure that we have a converters between the original camera pixel
901 * format and the one that the client expects. Also a converter must exist
902 * for the preview window pixel format (RGB32) */
903 if (!has_converter(cc->camera_info->pixel_format, cc->pixel_format) ||
904 !has_converter(cc->camera_info->pixel_format, V4L2_PIX_FMT_RGB32)) {
905 E("%s: No conversion exist between %.4s and %.4s (or RGB32) pixel formats",
906 __FUNCTION__, (char*)&cc->camera_info->pixel_format, (char*)&cc->pixel_format);
907 _qemu_client_reply_ko(qc, "No conversion exist for the requested pixel format");
908 return;
909 }
910
911 /* TODO: At the moment camera framework in the emulator requires RGB32 pixel
912 * format for preview window. So, we need to keep two framebuffers here: one
913 * for the video, and another for the preview window. Watch out when this
914 * changes (if changes). */
915 cc->preview_frame_size = cc->pixel_num * 4;
916
917 /* Allocate buffer large enough to contain both, video and preview
918 * framebuffers. */
919 cc->video_frame =
920 (uint8_t*)malloc(cc->video_frame_size + cc->preview_frame_size);
921 if (cc->video_frame == NULL) {
922 E("%s: Not enough memory for framebuffers %d + %d",
923 __FUNCTION__, cc->video_frame_size, cc->preview_frame_size);
924 _qemu_client_reply_ko(qc, "Out of memory");
925 return;
926 }
927
928 /* Set framebuffer pointers. */
929 cc->preview_frame = (uint16_t*)(cc->video_frame + cc->video_frame_size);
930
931 /* Start the camera. */
932 if (camera_device_start_capturing(cc->camera, cc->camera_info->pixel_format,
933 cc->width, cc->height)) {
934 E("%s: Cannot start camera '%s' for %.4s[%dx%d]: %s",
935 __FUNCTION__, cc->device_name, (const char*)&cc->pixel_format,
936 cc->width, cc->height, strerror(errno));
937 free(cc->video_frame);
938 cc->video_frame = NULL;
939 _qemu_client_reply_ko(qc, "Cannot start the camera");
940 return;
941 }
942
943 D("%s: Camera '%s' is now started for %.4s[%dx%d]",
944 __FUNCTION__, cc->device_name, (char*)&cc->pixel_format, cc->width,
945 cc->height);
946
947 _qemu_client_reply_ok(qc, NULL);
948 }
949
950 /* Client has queried the client to stop capturing video.
951 * Param:
952 * cc - Queried camera client descriptor.
953 * qc - Qemu client for the emulated camera.
954 * param - Query parameters. There are no parameters expected for this query.
955 */
956 static void
_camera_client_query_stop(CameraClient * cc,QemudClient * qc,const char * param)957 _camera_client_query_stop(CameraClient* cc, QemudClient* qc, const char* param)
958 {
959 if (cc->video_frame == NULL) {
960 /* Not started. */
961 W("%s: Camera '%s' is not started", __FUNCTION__, cc->device_name);
962 _qemu_client_reply_ok(qc, "Camera is not started");
963 return;
964 }
965
966 /* Stop the camera. */
967 if (camera_device_stop_capturing(cc->camera)) {
968 E("%s: Cannot stop camera device '%s': %s",
969 __FUNCTION__, cc->device_name, strerror(errno));
970 _qemu_client_reply_ko(qc, "Cannot stop camera device");
971 return;
972 }
973
974 free(cc->video_frame);
975 cc->video_frame = NULL;
976
977 D("%s: Camera device '%s' is now stopped.", __FUNCTION__, cc->device_name);
978 _qemu_client_reply_ok(qc, NULL);
979 }
980
981 /* Client has queried next frame.
982 * Param:
983 * cc - Queried camera client descriptor.
984 * qc - Qemu client for the emulated camera.
985 * param - Query parameters. Parameters for this query are formatted as such:
986 * video=<size> preview=<size> whiteb=<red>,<green>,<blue> expcomp=<comp>
987 * where:
988 * - 'video', and 'preview' both must be decimal values, defining size of
989 * requested video, and preview frames respectively. Zero value for any
990 * of these parameters means that this particular frame is not requested.
991 * - whiteb contains float values required to calculate whilte balance.
992 * - expcomp contains a float value required to calculate exposure
993 * compensation.
994 */
995 static void
_camera_client_query_frame(CameraClient * cc,QemudClient * qc,const char * param)996 _camera_client_query_frame(CameraClient* cc, QemudClient* qc, const char* param)
997 {
998 int video_size = 0;
999 int preview_size = 0;
1000 int repeat;
1001 ClientFrameBuffer fbs[2];
1002 int fbs_num = 0;
1003 size_t payload_size;
1004 uint64_t tick;
1005 float r_scale = 1.0f, g_scale = 1.0f, b_scale = 1.0f, exp_comp = 1.0f;
1006 char tmp[256];
1007
1008 /* Sanity check. */
1009 if (cc->video_frame == NULL) {
1010 /* Not started. */
1011 E("%s: Camera '%s' is not started", __FUNCTION__, cc->device_name);
1012 _qemu_client_reply_ko(qc, "Camera is not started");
1013 return;
1014 }
1015
1016 /* Pull required parameters. */
1017 if (get_token_value_int(param, "video", &video_size) ||
1018 get_token_value_int(param, "preview", &preview_size)) {
1019 E("%s: Invalid or missing 'video', or 'preview' parameter in '%s'",
1020 __FUNCTION__, param);
1021 _qemu_client_reply_ko(qc,
1022 "Invalid or missing 'video', or 'preview' parameter");
1023 return;
1024 }
1025
1026 /* Pull white balance values. */
1027 if (!get_token_value(param, "whiteb", tmp, sizeof(tmp))) {
1028 if (sscanf(tmp, "%g,%g,%g", &r_scale, &g_scale, &b_scale) != 3) {
1029 D("Invalid value '%s' for parameter 'whiteb'", tmp);
1030 r_scale = g_scale = b_scale = 1.0f;
1031 }
1032 }
1033
1034 /* Pull exposure compensation. */
1035 if (!get_token_value(param, "expcomp", tmp, sizeof(tmp))) {
1036 if (sscanf(tmp, "%g", &exp_comp) != 1) {
1037 D("Invalid value '%s' for parameter 'whiteb'", tmp);
1038 exp_comp = 1.0f;
1039 }
1040 }
1041
1042 /* Verify that framebuffer sizes match the ones that the started camera
1043 * operates with. */
1044 if ((video_size != 0 && cc->video_frame_size != video_size) ||
1045 (preview_size != 0 && cc->preview_frame_size != preview_size)) {
1046 E("%s: Frame sizes don't match for camera '%s':\n"
1047 "Expected %d for video, and %d for preview. Requested %d, and %d",
1048 __FUNCTION__, cc->device_name, cc->video_frame_size,
1049 cc->preview_frame_size, video_size, preview_size);
1050 _qemu_client_reply_ko(qc, "Frame size mismatch");
1051 return;
1052 }
1053
1054 /*
1055 * Initialize framebuffer array for frame read.
1056 */
1057
1058 if (video_size) {
1059 fbs[fbs_num].pixel_format = cc->pixel_format;
1060 fbs[fbs_num].framebuffer = cc->video_frame;
1061 fbs_num++;
1062 }
1063 if (preview_size) {
1064 /* TODO: Watch out for preview format changes! */
1065 fbs[fbs_num].pixel_format = V4L2_PIX_FMT_RGB32;
1066 fbs[fbs_num].framebuffer = cc->preview_frame;
1067 fbs_num++;
1068 }
1069
1070 /* Capture new frame. */
1071 tick = _get_timestamp();
1072 repeat = camera_device_read_frame(cc->camera, fbs, fbs_num,
1073 r_scale, g_scale, b_scale, exp_comp);
1074
1075 /* Note that there is no (known) way how to wait on next frame being
1076 * available, so we could dequeue frame buffer from the device only when we
1077 * know it's available. Instead we're shooting in the dark, and quite often
1078 * device will response with EAGAIN, indicating that it doesn't have frame
1079 * ready. In turn, it means that the last frame we have obtained from the
1080 * device is still good, and we can reply with the cached frames. The only
1081 * case when we need to keep trying to obtain a new frame is when frame cache
1082 * is empty. To prevent ourselves from an indefinite loop in case device got
1083 * stuck on something (observed with some Microsoft devices) we will limit
1084 * the loop by 2 second time period (which is more than enough to obtain
1085 * something from the device) */
1086 while (repeat == 1 && !cc->frames_cached &&
1087 (_get_timestamp() - tick) < 2000000LL) {
1088 /* Sleep for 10 millisec before repeating the attempt. */
1089 _camera_sleep(10);
1090 repeat = camera_device_read_frame(cc->camera, fbs, fbs_num,
1091 r_scale, g_scale, b_scale, exp_comp);
1092 }
1093 if (repeat == 1 && !cc->frames_cached) {
1094 /* Waited too long for the first frame. */
1095 E("%s: Unable to obtain first video frame from the camera '%s' in %d milliseconds: %s.",
1096 __FUNCTION__, cc->device_name,
1097 (uint32_t)(_get_timestamp() - tick) / 1000, strerror(errno));
1098 _qemu_client_reply_ko(qc, "Unable to obtain video frame from the camera");
1099 return;
1100 } else if (repeat < 0) {
1101 /* An I/O error. */
1102 E("%s: Unable to obtain video frame from the camera '%s': %s.",
1103 __FUNCTION__, cc->device_name, strerror(errno));
1104 _qemu_client_reply_ko(qc, strerror(errno));
1105 return;
1106 }
1107
1108 /* We have cached something... */
1109 cc->frames_cached = 1;
1110
1111 /*
1112 * Build the reply.
1113 */
1114
1115 /* Payload includes "ok:" + requested video and preview frames. */
1116 payload_size = 3 + video_size + preview_size;
1117
1118 /* Send payload size first. */
1119 _qemu_client_reply_payload(qc, payload_size);
1120
1121 /* After that send the 'ok:'. Note that if there is no frames sent, we should
1122 * use prefix "ok" instead of "ok:" */
1123 if (video_size || preview_size) {
1124 qemud_client_send(qc, (const uint8_t*)"ok:", 3);
1125 } else {
1126 /* Still 3 bytes: zero terminator is required in this case. */
1127 qemud_client_send(qc, (const uint8_t*)"ok", 3);
1128 }
1129
1130 /* After that send video frame (if requested). */
1131 if (video_size) {
1132 qemud_client_send(qc, cc->video_frame, video_size);
1133 }
1134
1135 /* After that send preview frame (if requested). */
1136 if (preview_size) {
1137 qemud_client_send(qc, (const uint8_t*)cc->preview_frame, preview_size);
1138 }
1139 }
1140
1141 /* Handles a message received from the emulated camera client.
1142 * Queries received here are represented as strings:
1143 * - 'connect' - Connects to the camera device (opens it).
1144 * - 'disconnect' - Disconnexts from the camera device (closes it).
1145 * - 'start' - Starts capturing video from the connected camera device.
1146 * - 'stop' - Stop capturing video from the connected camera device.
1147 * - 'frame' - Queries video and preview frames captured from the camera.
1148 * Param:
1149 * opaque - Camera service descriptor.
1150 * msg, msglen - Message received from the camera factory client.
1151 * client - Camera factory client pipe.
1152 */
1153 static void
_camera_client_recv(void * opaque,uint8_t * msg,int msglen,QemudClient * client)1154 _camera_client_recv(void* opaque,
1155 uint8_t* msg,
1156 int msglen,
1157 QemudClient* client)
1158 {
1159 /*
1160 * Emulated camera client queries.
1161 */
1162
1163 /* Connect to the camera. */
1164 static const char _query_connect[] = "connect";
1165 /* Disconnect from the camera. */
1166 static const char _query_disconnect[] = "disconnect";
1167 /* Start video capturing. */
1168 static const char _query_start[] = "start";
1169 /* Stop video capturing. */
1170 static const char _query_stop[] = "stop";
1171 /* Query frame(s). */
1172 static const char _query_frame[] = "frame";
1173
1174 char query_name[64];
1175 const char* query_param = NULL;
1176 CameraClient* cc = (CameraClient*)opaque;
1177
1178 /*
1179 * Emulated camera queries are formatted as such:
1180 * "<query name> [<parameters>]"
1181 */
1182
1183 T("%s: Camera client query: '%s'", __FUNCTION__, (char*)msg);
1184 if (_parse_query((const char*)msg, query_name, sizeof(query_name),
1185 &query_param)) {
1186 E("%s: Invalid query '%s'", __FUNCTION__, (char*)msg);
1187 _qemu_client_reply_ko(client, "Invalid query");
1188 return;
1189 }
1190
1191 /* Dispatch the query to an appropriate handler. */
1192 if (!strcmp(query_name, _query_frame)) {
1193 /* A frame is queried. */
1194 _camera_client_query_frame(cc, client, query_param);
1195 } else if (!strcmp(query_name, _query_connect)) {
1196 /* Camera connection is queried. */
1197 _camera_client_query_connect(cc, client, query_param);
1198 } else if (!strcmp(query_name, _query_disconnect)) {
1199 /* Camera disnection is queried. */
1200 _camera_client_query_disconnect(cc, client, query_param);
1201 } else if (!strcmp(query_name, _query_start)) {
1202 /* Start capturing is queried. */
1203 _camera_client_query_start(cc, client, query_param);
1204 } else if (!strcmp(query_name, _query_stop)) {
1205 /* Stop capturing is queried. */
1206 _camera_client_query_stop(cc, client, query_param);
1207 } else {
1208 E("%s: Unknown query '%s'", __FUNCTION__, (char*)msg);
1209 _qemu_client_reply_ko(client, "Unknown query");
1210 }
1211 }
1212
1213 /* Emulated camera client has been disconnected from the service. */
1214 static void
_camera_client_close(void * opaque)1215 _camera_client_close(void* opaque)
1216 {
1217 CameraClient* cc = (CameraClient*)opaque;
1218
1219 D("%s: Camera client for device '%s' on input channel %d is now closed",
1220 __FUNCTION__, cc->device_name, cc->inp_channel);
1221
1222 _camera_client_free(cc);
1223 }
1224
1225 /********************************************************************************
1226 * Camera service API
1227 *******************************************************************************/
1228
1229 /* Connects a client to the camera service.
1230 * There are two classes of the client that can connect to the service:
1231 * - Camera factory that is insterested only in listing camera devices attached
1232 * to the host.
1233 * - Camera device emulators that attach to the actual camera devices.
1234 * The distinction between these two classes is made by looking at extra
1235 * parameters passed in client_param variable. If it's NULL, or empty, the client
1236 * connects to a camera factory. Otherwise, parameters describe the camera device
1237 * the client wants to connect to.
1238 */
1239 static QemudClient*
_camera_service_connect(void * opaque,QemudService * serv,int channel,const char * client_param)1240 _camera_service_connect(void* opaque,
1241 QemudService* serv,
1242 int channel,
1243 const char* client_param)
1244 {
1245 QemudClient* client = NULL;
1246 CameraServiceDesc* csd = (CameraServiceDesc*)opaque;
1247
1248 D("%s: Connecting camera client '%s'",
1249 __FUNCTION__, client_param ? client_param : "Factory");
1250 if (client_param == NULL || *client_param == '\0') {
1251 /* This is an emulated camera factory client. */
1252 client = qemud_client_new(serv, channel, client_param, csd,
1253 _factory_client_recv, _factory_client_close,
1254 NULL, NULL);
1255 } else {
1256 /* This is an emulated camera client. */
1257 CameraClient* cc = _camera_client_create(csd, client_param);
1258 if (cc != NULL) {
1259 client = qemud_client_new(serv, channel, client_param, cc,
1260 _camera_client_recv, _camera_client_close,
1261 NULL, NULL);
1262 }
1263 }
1264
1265 return client;
1266 }
1267
1268 void
android_camera_service_init(void)1269 android_camera_service_init(void)
1270 {
1271 static int _inited = 0;
1272
1273 if (!_inited) {
1274 _camera_service_init(&_camera_service_desc);
1275 QemudService* serv = qemud_service_register( SERVICE_NAME, 0,
1276 &_camera_service_desc,
1277 _camera_service_connect,
1278 NULL, NULL);
1279 if (serv == NULL) {
1280 derror("%s: Could not register '%s' service",
1281 __FUNCTION__, SERVICE_NAME);
1282 return;
1283 }
1284 D("%s: Registered '%s' qemud service", __FUNCTION__, SERVICE_NAME);
1285 }
1286 }
1287
1288 void
android_list_web_cameras(void)1289 android_list_web_cameras(void)
1290 {
1291 CameraInfo ci[MAX_CAMERA];
1292 int connected_cnt;
1293 int i;
1294
1295 /* Enumerate camera devices connected to the host. */
1296 connected_cnt = enumerate_camera_devices(ci, MAX_CAMERA);
1297 if (connected_cnt <= 0) {
1298 return;
1299 }
1300
1301 printf("List of web cameras connected to the computer:\n");
1302 for (i = 0; i < connected_cnt; i++) {
1303 printf(" Camera '%s' is connected to device '%s' on channel %d using pixel format '%.4s'\n",
1304 ci[i].display_name, ci[i].device_name, ci[i].inp_channel,
1305 (const char*)&ci[i].pixel_format);
1306 }
1307 printf("\n");
1308 }
1309