• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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