1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * Contains implementation of a class EmulatedCamera that encapsulates
19 * functionality common to all emulated cameras ("fake", "webcam", "video file",
20 * etc.). Instances of this class (for each emulated camera) are created during
21 * the construction of the EmulatedCameraFactory instance. This class serves as
22 * an entry point for all camera API calls that defined by camera_device_ops_t
23 * API.
24 */
25
26#define LOG_NDEBUG 0
27#define LOG_TAG "EmulatedCamera_Camera"
28#include <cutils/log.h>
29#include <ui/Rect.h>
30#include "EmulatedCamera.h"
31//#include "EmulatedFakeCameraDevice.h"
32#include "Converters.h"
33
34/* Defines whether we should trace parameter changes. */
35#define DEBUG_PARAM 1
36
37namespace android {
38
39static const char* kValidFocusModes[] = {
40    CameraParameters::FOCUS_MODE_AUTO,
41    CameraParameters::FOCUS_MODE_INFINITY,
42    CameraParameters::FOCUS_MODE_MACRO,
43    CameraParameters::FOCUS_MODE_FIXED,
44    CameraParameters::FOCUS_MODE_EDOF,
45    CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO,
46    CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE,
47};
48
49#if DEBUG_PARAM
50/* Calculates and logs parameter changes.
51 * Param:
52 *  current - Current set of camera parameters.
53 *  new_par - String representation of new parameters.
54 */
55static void PrintParamDiff(const CameraParameters& current, const char* new_par);
56#else
57#define PrintParamDiff(current, new_par)   (void(0))
58#endif  /* DEBUG_PARAM */
59
60/* A helper routine that adds a value to the camera parameter.
61 * Param:
62 *  param - Camera parameter to add a value to.
63 *  val - Value to add.
64 * Return:
65 *  A new string containing parameter with the added value on success, or NULL on
66 *  a failure. If non-NULL string is returned, the caller is responsible for
67 *  freeing it with 'free'.
68 */
69static char* AddValue(const char* param, const char* val);
70
71/*
72 * Check if a given string |value| equals at least one of the strings in |list|
73 */
74template<size_t N>
75static bool IsValueInList(const char* value, const char* const (&list)[N])
76{
77    for (size_t i = 0; i < N; ++i) {
78        if (strcmp(value, list[i]) == 0) {
79            return true;
80        }
81    }
82    return false;
83}
84
85static bool StringsEqual(const char* str1, const char* str2) {
86    if (str1 == nullptr && str2 == nullptr) {
87        return true;
88    }
89    if (str1 == nullptr || str2 == nullptr) {
90        return false;
91    }
92    return strcmp(str1, str2) == 0;
93}
94
95static bool GetFourCcFormatFromCameraParam(const char* fmt_str,
96                                           uint32_t* fmt_val) {
97    if (strcmp(fmt_str, CameraParameters::PIXEL_FORMAT_YUV420P) == 0) {
98        // Despite the name above this is a YVU format, specifically YV12
99        *fmt_val = V4L2_PIX_FMT_YVU420;
100        return true;
101    } else if (strcmp(fmt_str, CameraParameters::PIXEL_FORMAT_RGBA8888) == 0) {
102        *fmt_val = V4L2_PIX_FMT_RGB32;
103        return true;
104    } else if (strcmp(fmt_str, CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) {
105        *fmt_val = V4L2_PIX_FMT_NV21;
106        return true;
107    }
108    return false;
109}
110
111EmulatedCamera::EmulatedCamera(int cameraId,
112                               struct hw_module_t* module)
113        : EmulatedBaseCamera(cameraId,
114                HARDWARE_DEVICE_API_VERSION(1, 0),
115                &common,
116                module),
117          mPreviewWindow(),
118          mCallbackNotifier()
119{
120    /* camera_device v1 fields. */
121    common.close = EmulatedCamera::close;
122    ops = &mDeviceOps;
123    priv = this;
124}
125
126EmulatedCamera::~EmulatedCamera()
127{
128}
129
130/****************************************************************************
131 * Public API
132 ***************************************************************************/
133
134status_t EmulatedCamera::Initialize()
135{
136    /* Preview formats supported by this HAL. */
137    char preview_formats[1024];
138    snprintf(preview_formats, sizeof(preview_formats), "%s,%s,%s",
139             CameraParameters::PIXEL_FORMAT_YUV420SP,
140             CameraParameters::PIXEL_FORMAT_YUV420P,
141             CameraParameters::PIXEL_FORMAT_RGBA8888);
142
143    /*
144     * Fake required parameters.
145     */
146
147    mParameters.set(CameraParameters::KEY_RECORDING_HINT,
148                    CameraParameters::FALSE);
149    mParameters.set(CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES, "320x240,0x0");
150
151    mParameters.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, "320");
152    mParameters.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, "240");
153    mParameters.set(CameraParameters::KEY_JPEG_QUALITY, "90");
154    // Camera values for a Logitech B910 HD Webcam
155    //     Focal length: 4.90 mm (from specs)
156    //     Horizontal view angle: 61 degrees for 4:3 sizes,
157    //         70 degrees for 16:9 sizes (empirical)
158    //     Vertical view angle: 45.8 degrees (= 61 * 3 / 4)
159    // (The Mac has only "4:3" image sizes; the correct angle
160    //  is 51.0 degrees. [MacBook Pro (Retina, 15-inch, Mid 2014)])
161    mParameters.set(CameraParameters::KEY_FOCAL_LENGTH, "4.90");
162    mParameters.set(CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE, "61.0");
163    mParameters.set(CameraParameters::KEY_VERTICAL_VIEW_ANGLE, "45.8");
164    mParameters.set(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY, "90");
165
166    /* Preview format settings used here are related to panoramic view only. It's
167     * not related to the preview window that works only with RGB frames, which
168     * is explicitly stated when set_buffers_geometry is called on the preview
169     * window object. */
170    mParameters.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS,
171                    preview_formats);
172    mParameters.setPreviewFormat(CameraParameters::PIXEL_FORMAT_YUV420SP);
173
174    /* We don't rely on the actual frame rates supported by the camera device,
175     * since we will emulate them through timeouts in the emulated camera device
176     * worker thread. */
177    mParameters.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES,
178                    "30,24,20,15,10,5");
179    mParameters.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE, "(24000,24000)");
180    mParameters.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, "24000,24000");
181    mParameters.setPreviewFrameRate(24);
182
183    /* Only PIXEL_FORMAT_YUV420P is accepted by video framework in emulator! */
184    mParameters.set(CameraParameters::KEY_VIDEO_FRAME_FORMAT,
185                    CameraParameters::PIXEL_FORMAT_YUV420P);
186    mParameters.set(CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS,
187                    CameraParameters::PIXEL_FORMAT_JPEG);
188    mParameters.setPictureFormat(CameraParameters::PIXEL_FORMAT_JPEG);
189
190    /* Set exposure compensation. */
191    mParameters.set(CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION, "6");
192    mParameters.set(CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION, "-6");
193    mParameters.set(CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP, "0.5");
194    mParameters.set(CameraParameters::KEY_EXPOSURE_COMPENSATION, "0");
195
196    /* Sets the white balance modes and the device-dependent scale factors. */
197    char supported_white_balance[1024];
198    snprintf(supported_white_balance, sizeof(supported_white_balance),
199             "%s,%s,%s,%s",
200             CameraParameters::WHITE_BALANCE_AUTO,
201             CameraParameters::WHITE_BALANCE_INCANDESCENT,
202             CameraParameters::WHITE_BALANCE_DAYLIGHT,
203             CameraParameters::WHITE_BALANCE_TWILIGHT);
204    mParameters.set(CameraParameters::KEY_SUPPORTED_WHITE_BALANCE,
205                    supported_white_balance);
206    mParameters.set(CameraParameters::KEY_WHITE_BALANCE,
207                    CameraParameters::WHITE_BALANCE_AUTO);
208    getCameraDevice()->initializeWhiteBalanceModes(
209            CameraParameters::WHITE_BALANCE_AUTO, 1.0f, 1.0f);
210    getCameraDevice()->initializeWhiteBalanceModes(
211            CameraParameters::WHITE_BALANCE_INCANDESCENT, 1.38f, 0.60f);
212    getCameraDevice()->initializeWhiteBalanceModes(
213            CameraParameters::WHITE_BALANCE_DAYLIGHT, 1.09f, 0.92f);
214    getCameraDevice()->initializeWhiteBalanceModes(
215            CameraParameters::WHITE_BALANCE_TWILIGHT, 0.92f, 1.22f);
216    getCameraDevice()->setWhiteBalanceMode(CameraParameters::WHITE_BALANCE_AUTO);
217
218    /* Set suported antibanding values */
219    mParameters.set(CameraParameters::KEY_SUPPORTED_ANTIBANDING,
220                    CameraParameters::ANTIBANDING_AUTO);
221    mParameters.set(CameraParameters::KEY_ANTIBANDING,
222                    CameraParameters::ANTIBANDING_AUTO);
223
224    /* Set control effect mode
225     * Bug: 30862244
226     * */
227    mParameters.set(CameraParameters::KEY_SUPPORTED_EFFECTS,
228                    CameraParameters::EFFECT_NONE);
229    mParameters.set(CameraParameters::KEY_EFFECT,
230                    CameraParameters::EFFECT_NONE);
231
232    /* Set focus distances for "near,optimal,far" */
233    mParameters.set(CameraParameters::KEY_FOCUS_DISTANCES,
234                    "Infinity,Infinity,Infinity");
235
236    /* Not supported features
237     */
238    mParameters.set(CameraParameters::KEY_SUPPORTED_FOCUS_MODES,
239                    CameraParameters::FOCUS_MODE_FIXED);
240    mParameters.set(CameraParameters::KEY_FOCUS_MODE,
241                    CameraParameters::FOCUS_MODE_FIXED);
242
243    return NO_ERROR;
244}
245
246void EmulatedCamera::onNextFrameAvailable(nsecs_t timestamp,
247                                          EmulatedCameraDevice* camera_dev)
248{
249    /* Notify the preview window first. */
250    mPreviewWindow.onNextFrameAvailable(timestamp, camera_dev);
251
252    /* Notify callback notifier next. */
253    mCallbackNotifier.onNextFrameAvailable(timestamp, camera_dev);
254}
255
256void EmulatedCamera::onCameraDeviceError(int err)
257{
258    /* Errors are reported through the callback notifier */
259    mCallbackNotifier.onCameraDeviceError(err);
260}
261
262void EmulatedCamera::setTakingPicture(bool takingPicture) {
263    mCallbackNotifier.setTakingPicture(takingPicture);
264}
265/****************************************************************************
266 * Camera API implementation.
267 ***************************************************************************/
268
269status_t EmulatedCamera::connectCamera(hw_device_t** device)
270{
271    ALOGV("%s", __FUNCTION__);
272
273    status_t res = EINVAL;
274    EmulatedCameraDevice* const camera_dev = getCameraDevice();
275    ALOGE_IF(camera_dev == NULL, "%s: No camera device instance.", __FUNCTION__);
276
277    if (camera_dev != NULL) {
278        /* Connect to the camera device. */
279        res = getCameraDevice()->connectDevice();
280        if (res == NO_ERROR) {
281            *device = &common;
282        }
283    }
284
285    return -res;
286}
287
288status_t EmulatedCamera::closeCamera()
289{
290    ALOGV("%s", __FUNCTION__);
291
292    return cleanupCamera();
293}
294
295status_t EmulatedCamera::getCameraInfo(struct camera_info* info)
296{
297    ALOGV("%s", __FUNCTION__);
298
299    const char* valstr = NULL;
300
301    valstr = mParameters.get(EmulatedCamera::FACING_KEY);
302    if (valstr != NULL) {
303        if (strcmp(valstr, EmulatedCamera::FACING_FRONT) == 0) {
304            info->facing = CAMERA_FACING_FRONT;
305        }
306        else if (strcmp(valstr, EmulatedCamera::FACING_BACK) == 0) {
307            info->facing = CAMERA_FACING_BACK;
308        }
309    } else {
310        info->facing = CAMERA_FACING_BACK;
311    }
312
313    valstr = mParameters.get(EmulatedCamera::ORIENTATION_KEY);
314    if (valstr != NULL) {
315        info->orientation = atoi(valstr);
316    } else {
317        info->orientation = 0;
318    }
319
320    return EmulatedBaseCamera::getCameraInfo(info);
321}
322
323void EmulatedCamera::autoFocusComplete() {
324    mCallbackNotifier.autoFocusComplete();
325}
326
327status_t EmulatedCamera::setPreviewWindow(struct preview_stream_ops* window)
328{
329    /* Callback should return a negative errno. */
330    return -mPreviewWindow.setPreviewWindow(window,
331                                             mParameters.getPreviewFrameRate());
332}
333
334void EmulatedCamera::setCallbacks(camera_notify_callback notify_cb,
335                                  camera_data_callback data_cb,
336                                  camera_data_timestamp_callback data_cb_timestamp,
337                                  camera_request_memory get_memory,
338                                  void* user)
339{
340    mCallbackNotifier.setCallbacks(notify_cb, data_cb, data_cb_timestamp,
341                                    get_memory, user);
342}
343
344void EmulatedCamera::enableMsgType(int32_t msg_type)
345{
346    mCallbackNotifier.enableMessage(msg_type);
347}
348
349void EmulatedCamera::disableMsgType(int32_t msg_type)
350{
351    mCallbackNotifier.disableMessage(msg_type);
352}
353
354int EmulatedCamera::isMsgTypeEnabled(int32_t msg_type)
355{
356    return mCallbackNotifier.isMessageEnabled(msg_type);
357}
358
359status_t EmulatedCamera::startPreview()
360{
361    /* Callback should return a negative errno. */
362    return -doStartPreview();
363}
364
365void EmulatedCamera::stopPreview()
366{
367    /* The camera client will not pass on calls to set the preview window to
368     * NULL if the preview is not enabled. If preview is not enabled the camera
369     * client will instead simply destroy the preview window without notifying
370     * the HAL. Later on when preview is enabled again that means the HAL will
371     * attempt to use the old, destroyed window which will cause a crash.
372     * Instead we need to clear the preview window here, the client will set
373     * a preview window when needed. The preview window is cleared here instead
374     * of inside doStopPreview to prevent the window from being cleared when
375     * restarting the preview because of a parameter change. */
376    mPreviewWindow.setPreviewWindow(nullptr, 0);
377
378    doStopPreview();
379}
380
381int EmulatedCamera::isPreviewEnabled()
382{
383    return mPreviewWindow.isPreviewEnabled();
384}
385
386status_t EmulatedCamera::storeMetaDataInBuffers(int enable)
387{
388    /* Callback should return a negative errno. */
389    return -mCallbackNotifier.storeMetaDataInBuffers(enable);
390}
391
392status_t EmulatedCamera::startRecording()
393{
394    /* This callback should return a negative errno, hence all the negations */
395    int frameRate = mParameters.getPreviewFrameRate();
396    status_t res = mCallbackNotifier.enableVideoRecording(frameRate);
397    if (res != NO_ERROR) {
398        ALOGE("%s: CallbackNotifier failed to enable video recording",
399              __FUNCTION__);
400        stopRecording();
401        return -res;
402    }
403    EmulatedCameraDevice* const camera_dev = getCameraDevice();
404    if (camera_dev == nullptr || !camera_dev->isStarted()) {
405        // No need for restarts, the next preview start will use correct params
406        return NO_ERROR;
407    }
408
409    // If the camera is running we might have to restart it to accomodate
410    // whatever pixel format and frame size the caller wants.
411    uint32_t conf_fmt = 0;
412    res = getConfiguredPixelFormat(&conf_fmt);
413    if (res != NO_ERROR) {
414        stopRecording();
415        return -res;
416    }
417    uint32_t cur_fmt = camera_dev->getOriginalPixelFormat();
418    int conf_width = -1, conf_height = -1;
419    res = getConfiguredFrameSize(&conf_width, &conf_height);
420    if (res != NO_ERROR) {
421        stopRecording();
422        return -res;
423    }
424    int cur_width = camera_dev->getFrameWidth();
425    int cur_height = camera_dev->getFrameHeight();
426
427    if (cur_fmt != conf_fmt ||
428            cur_width != conf_width ||
429            cur_height != conf_height) {
430        // We need to perform a restart to use the new format or size and it
431        // has to be an asynchronous restart or this might block if the camera
432        // thread is currently delivering a frame.
433        if (!camera_dev->requestRestart(conf_width, conf_height, conf_fmt,
434                                        false /* takingPicture */,
435                                        false /* oneBurst */)) {
436            ALOGE("%s: Could not restart preview with new pixel format",
437                  __FUNCTION__);
438            stopRecording();
439            return -EINVAL;
440        }
441    }
442    return NO_ERROR;
443}
444
445void EmulatedCamera::stopRecording()
446{
447    mCallbackNotifier.disableVideoRecording();
448}
449
450int EmulatedCamera::isRecordingEnabled()
451{
452    return mCallbackNotifier.isVideoRecordingEnabled();
453}
454
455void EmulatedCamera::releaseRecordingFrame(const void* opaque)
456{
457    mCallbackNotifier.releaseRecordingFrame(opaque);
458}
459
460status_t EmulatedCamera::setAutoFocus()
461{
462    // Make sure to check that a preview is in progress. Otherwise this will
463    // silently fail because no callback will be called until the preview starts
464    // which might be never.
465    if (!isPreviewEnabled()) {
466        return EINVAL;
467    }
468    EmulatedCameraDevice* const camera_dev = getCameraDevice();
469    if (camera_dev && camera_dev->isStarted()) {
470        return camera_dev->setAutoFocus();
471    }
472    return EINVAL;
473}
474
475status_t EmulatedCamera::cancelAutoFocus()
476{
477    // In this case we don't check if a preview is in progress or not. Unlike
478    // setAutoFocus this call will not silently fail without the check. If an
479    // auto-focus request is somehow pending without having preview enabled this
480    // will correctly cancel that pending auto-focus which seems reasonable.
481    EmulatedCameraDevice* const camera_dev = getCameraDevice();
482    if (camera_dev && camera_dev->isStarted()) {
483        return camera_dev->cancelAutoFocus();
484    }
485    return EINVAL;
486}
487
488status_t EmulatedCamera::takePicture()
489{
490    ALOGV("%s", __FUNCTION__);
491
492    status_t res;
493    int width, height;
494    uint32_t org_fmt;
495
496    /* Collect frame info for the picture. */
497    mParameters.getPictureSize(&width, &height);
498    const char* pix_fmt = mParameters.getPictureFormat();
499    if (!GetFourCcFormatFromCameraParam(pix_fmt, &org_fmt)) {
500        // Also check for JPEG here, the function above does not do this since
501        // this is very specific to this use case.
502        if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_JPEG) == 0) {
503            /* We only have JPEG converted for NV21 format. */
504            org_fmt = V4L2_PIX_FMT_NV21;
505        } else {
506            ALOGE("%s: Unsupported pixel format %s", __FUNCTION__, pix_fmt);
507            return EINVAL;
508        }
509    }
510
511    /* Get JPEG quality. */
512    int jpeg_quality = mParameters.getInt(CameraParameters::KEY_JPEG_QUALITY);
513    if (jpeg_quality <= 0) {
514        jpeg_quality = 90;  /* Fall back to default. */
515    }
516
517    /*
518     * Make sure preview is not running, and device is stopped before taking
519     * picture.
520     */
521
522    EmulatedCameraDevice* const camera_dev = getCameraDevice();
523    mCallbackNotifier.setJpegQuality(jpeg_quality);
524    mCallbackNotifier.setCameraParameters(mParameters);
525
526    ALOGD("Starting camera for picture: %.4s(%s)[%dx%d]",
527          reinterpret_cast<const char*>(&org_fmt), pix_fmt, width, height);
528    if (mPreviewWindow.isPreviewEnabled()) {
529        mPreviewWindow.stopPreview();
530        /* If the camera preview is enabled we need to perform an asynchronous
531         * restart. A blocking restart could deadlock this thread as it's
532         * currently holding the camera client lock and the frame delivery could
533         * be stuck on waiting for that lock. If this was synchronous then this
534         * thread would in turn get stuck on waiting for the delivery thread. */
535        if (!camera_dev->requestRestart(width, height, org_fmt,
536                                        true /* takingPicture */,
537                                        true /* oneBurst */)) {
538            return UNKNOWN_ERROR;
539        }
540        return NO_ERROR;
541    } else {
542        /* Start camera device for the picture frame. */
543        res = camera_dev->startDevice(width, height, org_fmt);
544        if (res != NO_ERROR) {
545            return res;
546        }
547
548        /* Deliver one frame only. */
549        mCallbackNotifier.setTakingPicture(true);
550        res = camera_dev->startDeliveringFrames(true);
551        if (res != NO_ERROR) {
552            mCallbackNotifier.setTakingPicture(false);
553        }
554        return res;
555    }
556}
557
558status_t EmulatedCamera::cancelPicture()
559{
560    ALOGV("%s", __FUNCTION__);
561
562    return NO_ERROR;
563}
564
565status_t EmulatedCamera::setParameters(const char* parms)
566{
567    ALOGV("%s", __FUNCTION__);
568    PrintParamDiff(mParameters, parms);
569
570    CameraParameters new_param;
571    String8 str8_param(parms);
572    new_param.unflatten(str8_param);
573    bool restartPreview = false;
574
575    /*
576     * Check for new exposure compensation parameter.
577     */
578    int new_exposure_compensation = new_param.getInt(
579            CameraParameters::KEY_EXPOSURE_COMPENSATION);
580    const int min_exposure_compensation = new_param.getInt(
581            CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION);
582    const int max_exposure_compensation = new_param.getInt(
583            CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION);
584
585    // Checks if the exposure compensation change is supported.
586    if ((min_exposure_compensation != 0) || (max_exposure_compensation != 0)) {
587        if (new_exposure_compensation > max_exposure_compensation) {
588            new_exposure_compensation = max_exposure_compensation;
589        }
590        if (new_exposure_compensation < min_exposure_compensation) {
591            new_exposure_compensation = min_exposure_compensation;
592        }
593
594        const int current_exposure_compensation = mParameters.getInt(
595                CameraParameters::KEY_EXPOSURE_COMPENSATION);
596        if (current_exposure_compensation != new_exposure_compensation) {
597            const float exposure_value = new_exposure_compensation *
598                    new_param.getFloat(
599                            CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP);
600
601            getCameraDevice()->setExposureCompensation(
602                    exposure_value);
603        }
604    }
605
606    const char* new_white_balance = new_param.get(
607            CameraParameters::KEY_WHITE_BALANCE);
608    const char* supported_white_balance = new_param.get(
609            CameraParameters::KEY_SUPPORTED_WHITE_BALANCE);
610
611    if ((supported_white_balance != NULL) && (new_white_balance != NULL) &&
612        (strstr(supported_white_balance, new_white_balance) != NULL)) {
613
614        const char* current_white_balance = mParameters.get(
615                CameraParameters::KEY_WHITE_BALANCE);
616        if ((current_white_balance == NULL) ||
617            (strcmp(current_white_balance, new_white_balance) != 0)) {
618            ALOGV("Setting white balance to %s", new_white_balance);
619            getCameraDevice()->setWhiteBalanceMode(new_white_balance);
620        }
621    }
622    int old_frame_rate = mParameters.getPreviewFrameRate();
623    int new_frame_rate = new_param.getPreviewFrameRate();
624    if (old_frame_rate != new_frame_rate) {
625        getCameraDevice()->setPreviewFrameRate(new_frame_rate);
626    }
627
628    // Validate focus mode
629    const char* focus_mode = new_param.get(CameraParameters::KEY_FOCUS_MODE);
630    if (focus_mode && !IsValueInList(focus_mode, kValidFocusModes)) {
631        return BAD_VALUE;
632    }
633
634    // Validate preview size, if there is no preview size the initial values of
635    // the integers below will be preserved thus intentionally failing the test
636    int new_preview_width = -1, new_preview_height = -1;
637    new_param.getPreviewSize(&new_preview_width, &new_preview_height);
638    if (new_preview_width < 0 || new_preview_height < 0) {
639        return BAD_VALUE;
640    }
641    // If the preview size has changed we have to restart the preview to make
642    // sure we provide frames of the correct size. The receiver assumes the
643    // frame size is correct and will copy all data provided into a buffer whose
644    // size is determined by the preview size without checks, potentially
645    // causing buffer overruns or underruns if there is a size mismatch.
646    int old_preview_width = -1, old_preview_height = -1;
647    mParameters.getPreviewSize(&old_preview_width, &old_preview_height);
648    if (old_preview_width != new_preview_width ||
649            old_preview_height != new_preview_height) {
650        restartPreview = true;
651    }
652
653    // For the same reasons as with the preview size we have to look for changes
654    // in video size and restart the preview if the size has changed.
655    int old_video_width = -1, old_video_height = -1;
656    int new_video_width = -1, new_video_height = -1;
657    mParameters.getVideoSize(&old_video_width, &old_video_height);
658    new_param.getVideoSize(&new_video_width, &new_video_height);
659    if (old_video_width != new_video_width ||
660        old_video_height != new_video_height) {
661        restartPreview = true;
662    }
663    // Restart the preview if the pixel format changes to make sure we serve
664    // the selected encoding to the client.
665    const char* old_format = mParameters.getPreviewFormat();
666    const char* new_format = new_param.getPreviewFormat();
667    if (!StringsEqual(old_format, new_format)) {
668        restartPreview = true;
669    }
670
671    const char* old_hint =
672        mParameters.get(CameraParameters::KEY_RECORDING_HINT);
673    const char* new_hint = new_param.get(CameraParameters::KEY_RECORDING_HINT);
674    if (!StringsEqual(old_hint, new_hint)) {
675        // The recording hint changed, this indicates we transitioned from
676        // recording to non-recording or the other way around. We need to look
677        // at a new pixel format for this and that requires a restart.
678        restartPreview = true;
679    }
680
681    mParameters = new_param;
682
683    // Now that the parameters have been assigned check if the preview needs to
684    // be restarted. If necessary this will then use the new parameters to set
685    // up the preview as requested by the caller.
686    if (restartPreview && isPreviewEnabled()) {
687        status_t status = doStopPreview();
688        if (status != NO_ERROR) {
689            ALOGE("%s: Stopping preview failed: %d", __FUNCTION__, status);
690            return status;
691        }
692        status = doStartPreview();
693        if (status != NO_ERROR) {
694            ALOGE("%s: Starting preview failed: %d", __FUNCTION__, status);
695            return status;
696        }
697    }
698    return NO_ERROR;
699}
700
701/* A dumb variable indicating "no params" / error on the exit from
702 * EmulatedCamera::getParameters(). */
703static char lNoParam = '\0';
704char* EmulatedCamera::getParameters()
705{
706    // Read the image size and set the camera's Field of View.
707    // These values are valid for a Logitech B910 HD Webcam.
708    int width=0, height=0;
709    mParameters.getPictureSize(&width, &height);
710    if (height > 0) {
711        if (((double)width / height) < 1.55) {
712            // Closer to 4:3 (1.33), set the FOV to 61.0 degrees
713            mParameters.set(CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE, "61.0");
714        } else {
715            // Closer to 16:9 (1.77), set the FOV to 70.0 degrees
716            mParameters.set(CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE, "70.0");
717        }
718    }
719
720    String8 params(mParameters.flatten());
721    char* ret_str =
722        reinterpret_cast<char*>(malloc(sizeof(char) * (params.length()+1)));
723    memset(ret_str, 0, params.length()+1);
724    if (ret_str != NULL) {
725        strncpy(ret_str, params.string(), params.length()+1);
726        return ret_str;
727    } else {
728        ALOGE("%s: Unable to allocate string for %s", __FUNCTION__, params.string());
729        /* Apparently, we can't return NULL fron this routine. */
730        return &lNoParam;
731    }
732}
733
734void EmulatedCamera::putParameters(char* params)
735{
736    /* This method simply frees parameters allocated in getParameters(). */
737    if (params != NULL && params != &lNoParam) {
738        free(params);
739    }
740}
741
742status_t EmulatedCamera::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2)
743{
744    ALOGV("%s: cmd = %d, arg1 = %d, arg2 = %d", __FUNCTION__, cmd, arg1, arg2);
745
746    switch (cmd) {
747        case CAMERA_CMD_START_FACE_DETECTION:
748        case CAMERA_CMD_STOP_FACE_DETECTION:
749            // We do not support hardware face detection so we need to indicate
750            // that any attempt to start/stop face detection is invalid
751            return BAD_VALUE;
752    }
753    /* TODO: Future enhancements. */
754    return 0;
755}
756
757void EmulatedCamera::releaseCamera()
758{
759    ALOGV("%s", __FUNCTION__);
760
761    cleanupCamera();
762}
763
764status_t EmulatedCamera::dumpCamera(int fd)
765{
766    ALOGV("%s", __FUNCTION__);
767
768    /* TODO: Future enhancements. */
769    return -EINVAL;
770}
771
772status_t EmulatedCamera::getConfiguredPixelFormat(uint32_t* pixelFormat) const {
773    const char* pix_fmt = nullptr;
774    const char* recordingHint =
775        mParameters.get(CameraParameters::KEY_RECORDING_HINT);
776    bool recordingHintOn = recordingHint && strcmp(recordingHint,
777                                                   CameraParameters::TRUE) == 0;
778    bool recordingEnabled = mCallbackNotifier.isVideoRecordingEnabled();
779    if (recordingHintOn || recordingEnabled) {
780        // We're recording a video, use the video pixel format
781        pix_fmt = mParameters.get(CameraParameters::KEY_VIDEO_FRAME_FORMAT);
782    }
783    if (pix_fmt == nullptr) {
784        pix_fmt = mParameters.getPreviewFormat();
785    }
786    if (pix_fmt == nullptr) {
787        ALOGE("%s: Unable to obtain configured pixel format", __FUNCTION__);
788        return EINVAL;
789    }
790    /* Convert framework's pixel format to the FOURCC one. */
791    if (!GetFourCcFormatFromCameraParam(pix_fmt, pixelFormat)) {
792        ALOGE("%s: Unsupported pixel format %s", __FUNCTION__, pix_fmt);
793        return EINVAL;
794    }
795    return NO_ERROR;
796}
797
798status_t EmulatedCamera::getConfiguredFrameSize(int* outWidth,
799                                                int* outHeight) const {
800    int width = -1, height = -1;
801    if (mParameters.get(CameraParameters::KEY_VIDEO_SIZE) != nullptr) {
802        mParameters.getVideoSize(&width, &height);
803    } else {
804        mParameters.getPreviewSize(&width, &height);
805    }
806    if (width < 0 || height < 0) {
807        ALOGE("%s: No frame size configured for camera", __FUNCTION__);
808        return EINVAL;
809    }
810    // Only modify the out parameters once we know we succeeded
811    *outWidth = width;
812    *outHeight = height;
813    return NO_ERROR;
814}
815
816/****************************************************************************
817 * Preview management.
818 ***************************************************************************/
819
820status_t EmulatedCamera::doStartPreview()
821{
822    ALOGV("%s", __FUNCTION__);
823
824    EmulatedCameraDevice* camera_dev = getCameraDevice();
825    if (camera_dev->isStarted()) {
826        camera_dev->stopDeliveringFrames();
827        camera_dev->stopDevice();
828    }
829
830    status_t res = mPreviewWindow.startPreview();
831    if (res != NO_ERROR) {
832        return res;
833    }
834
835    /* Make sure camera device is connected. */
836    if (!camera_dev->isConnected()) {
837        res = camera_dev->connectDevice();
838        if (res != NO_ERROR) {
839            mPreviewWindow.stopPreview();
840            return res;
841        }
842    }
843
844    /* Lets see what should we use for frame width, and height. */
845    int width, height;
846    res = getConfiguredFrameSize(&width, &height);
847    if (res != NO_ERROR) {
848        mPreviewWindow.stopPreview();
849        return res;
850    }
851
852    uint32_t org_fmt = 0;
853    res = getConfiguredPixelFormat(&org_fmt);
854    if (res != NO_ERROR) {
855        mPreviewWindow.stopPreview();
856        return res;
857    }
858
859    camera_dev->setPreviewFrameRate(mParameters.getPreviewFrameRate());
860    ALOGD("Starting camera: %dx%d -> %.4s",
861         width, height, reinterpret_cast<const char*>(&org_fmt));
862    res = camera_dev->startDevice(width, height, org_fmt);
863    if (res != NO_ERROR) {
864        mPreviewWindow.stopPreview();
865        return res;
866    }
867
868    res = camera_dev->startDeliveringFrames(false);
869    if (res != NO_ERROR) {
870        camera_dev->stopDevice();
871        mPreviewWindow.stopPreview();
872    }
873
874    return res;
875}
876
877status_t EmulatedCamera::doStopPreview()
878{
879    ALOGV("%s", __FUNCTION__);
880
881    status_t res = NO_ERROR;
882    if (mPreviewWindow.isPreviewEnabled()) {
883        /* Stop the camera. */
884        if (getCameraDevice()->isStarted()) {
885            getCameraDevice()->stopDeliveringFrames();
886            res = getCameraDevice()->stopDevice();
887        }
888
889        if (res == NO_ERROR) {
890            /* Disable preview as well. */
891            mPreviewWindow.stopPreview();
892        }
893    }
894
895    return NO_ERROR;
896}
897
898/****************************************************************************
899 * Private API.
900 ***************************************************************************/
901
902status_t EmulatedCamera::cleanupCamera()
903{
904    status_t res = NO_ERROR;
905
906    /* If preview is running - stop it. */
907    res = doStopPreview();
908    if (res != NO_ERROR) {
909        return -res;
910    }
911
912    /* Stop and disconnect the camera device. */
913    EmulatedCameraDevice* const camera_dev = getCameraDevice();
914    if (camera_dev != NULL) {
915        if (camera_dev->isStarted()) {
916            camera_dev->stopDeliveringFrames();
917            res = camera_dev->stopDevice();
918            if (res != NO_ERROR) {
919                return -res;
920            }
921        }
922        if (camera_dev->isConnected()) {
923            res = camera_dev->disconnectDevice();
924            if (res != NO_ERROR) {
925                return -res;
926            }
927        }
928    }
929
930    mCallbackNotifier.cleanupCBNotifier();
931
932    /* Re-init the camera settings in case settings were changed */
933    Initialize();
934
935    return NO_ERROR;
936}
937
938/****************************************************************************
939 * Camera API callbacks as defined by camera_device_ops structure.
940 *
941 * Callbacks here simply dispatch the calls to an appropriate method inside
942 * EmulatedCamera instance, defined by the 'dev' parameter.
943 ***************************************************************************/
944
945int EmulatedCamera::set_preview_window(struct camera_device* dev,
946                                       struct preview_stream_ops* window)
947{
948    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
949    if (ec == NULL) {
950        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
951        return -EINVAL;
952    }
953    return ec->setPreviewWindow(window);
954}
955
956void EmulatedCamera::set_callbacks(
957        struct camera_device* dev,
958        camera_notify_callback notify_cb,
959        camera_data_callback data_cb,
960        camera_data_timestamp_callback data_cb_timestamp,
961        camera_request_memory get_memory,
962        void* user)
963{
964    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
965    if (ec == NULL) {
966        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
967        return;
968    }
969    ec->setCallbacks(notify_cb, data_cb, data_cb_timestamp, get_memory, user);
970}
971
972void EmulatedCamera::enable_msg_type(struct camera_device* dev, int32_t msg_type)
973{
974    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
975    if (ec == NULL) {
976        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
977        return;
978    }
979    ec->enableMsgType(msg_type);
980}
981
982void EmulatedCamera::disable_msg_type(struct camera_device* dev, int32_t msg_type)
983{
984    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
985    if (ec == NULL) {
986        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
987        return;
988    }
989    ec->disableMsgType(msg_type);
990}
991
992int EmulatedCamera::msg_type_enabled(struct camera_device* dev, int32_t msg_type)
993{
994    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
995    if (ec == NULL) {
996        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
997        return -EINVAL;
998    }
999    return ec->isMsgTypeEnabled(msg_type);
1000}
1001
1002int EmulatedCamera::start_preview(struct camera_device* dev)
1003{
1004    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1005    if (ec == NULL) {
1006        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1007        return -EINVAL;
1008    }
1009    return ec->startPreview();
1010}
1011
1012void EmulatedCamera::stop_preview(struct camera_device* dev)
1013{
1014    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1015    if (ec == NULL) {
1016        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1017        return;
1018    }
1019    ec->stopPreview();
1020}
1021
1022int EmulatedCamera::preview_enabled(struct camera_device* dev)
1023{
1024    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1025    if (ec == NULL) {
1026        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1027        return -EINVAL;
1028    }
1029    return ec->isPreviewEnabled();
1030}
1031
1032int EmulatedCamera::store_meta_data_in_buffers(struct camera_device* dev,
1033                                               int enable)
1034{
1035    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1036    if (ec == NULL) {
1037        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1038        return -EINVAL;
1039    }
1040    return ec->storeMetaDataInBuffers(enable);
1041}
1042
1043int EmulatedCamera::start_recording(struct camera_device* dev)
1044{
1045    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1046    if (ec == NULL) {
1047        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1048        return -EINVAL;
1049    }
1050    return ec->startRecording();
1051}
1052
1053void EmulatedCamera::stop_recording(struct camera_device* dev)
1054{
1055    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1056    if (ec == NULL) {
1057        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1058        return;
1059    }
1060    ec->stopRecording();
1061}
1062
1063int EmulatedCamera::recording_enabled(struct camera_device* dev)
1064{
1065    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1066    if (ec == NULL) {
1067        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1068        return -EINVAL;
1069    }
1070    return ec->isRecordingEnabled();
1071}
1072
1073void EmulatedCamera::release_recording_frame(struct camera_device* dev,
1074                                             const void* opaque)
1075{
1076    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1077    if (ec == NULL) {
1078        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1079        return;
1080    }
1081    ec->releaseRecordingFrame(opaque);
1082}
1083
1084int EmulatedCamera::auto_focus(struct camera_device* dev)
1085{
1086    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1087    if (ec == NULL) {
1088        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1089        return -EINVAL;
1090    }
1091    return ec->setAutoFocus();
1092}
1093
1094int EmulatedCamera::cancel_auto_focus(struct camera_device* dev)
1095{
1096    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1097    if (ec == NULL) {
1098        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1099        return -EINVAL;
1100    }
1101    return ec->cancelAutoFocus();
1102}
1103
1104int EmulatedCamera::take_picture(struct camera_device* dev)
1105{
1106    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1107    if (ec == NULL) {
1108        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1109        return -EINVAL;
1110    }
1111    return ec->takePicture();
1112}
1113
1114int EmulatedCamera::cancel_picture(struct camera_device* dev)
1115{
1116    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1117    if (ec == NULL) {
1118        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1119        return -EINVAL;
1120    }
1121    return ec->cancelPicture();
1122}
1123
1124int EmulatedCamera::set_parameters(struct camera_device* dev, const char* parms)
1125{
1126    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1127    if (ec == NULL) {
1128        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1129        return -EINVAL;
1130    }
1131    return ec->setParameters(parms);
1132}
1133
1134char* EmulatedCamera::get_parameters(struct camera_device* dev)
1135{
1136    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1137    if (ec == NULL) {
1138        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1139        return NULL;
1140    }
1141    return ec->getParameters();
1142}
1143
1144void EmulatedCamera::put_parameters(struct camera_device* dev, char* params)
1145{
1146    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1147    if (ec == NULL) {
1148        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1149        return;
1150    }
1151    ec->putParameters(params);
1152}
1153
1154int EmulatedCamera::send_command(struct camera_device* dev,
1155                                 int32_t cmd,
1156                                 int32_t arg1,
1157                                 int32_t arg2)
1158{
1159    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1160    if (ec == NULL) {
1161        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1162        return -EINVAL;
1163    }
1164    return ec->sendCommand(cmd, arg1, arg2);
1165}
1166
1167void EmulatedCamera::release(struct camera_device* dev)
1168{
1169    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1170    if (ec == NULL) {
1171        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1172        return;
1173    }
1174    ec->releaseCamera();
1175}
1176
1177int EmulatedCamera::dump(struct camera_device* dev, int fd)
1178{
1179    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1180    if (ec == NULL) {
1181        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1182        return -EINVAL;
1183    }
1184    return ec->dumpCamera(fd);
1185}
1186
1187int EmulatedCamera::close(struct hw_device_t* device)
1188{
1189    EmulatedCamera* ec =
1190        reinterpret_cast<EmulatedCamera*>(reinterpret_cast<struct camera_device*>(device)->priv);
1191    if (ec == NULL) {
1192        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1193        return -EINVAL;
1194    }
1195    return ec->closeCamera();
1196}
1197
1198/****************************************************************************
1199 * Static initializer for the camera callback API
1200 ****************************************************************************/
1201
1202camera_device_ops_t EmulatedCamera::mDeviceOps = {
1203    EmulatedCamera::set_preview_window,
1204    EmulatedCamera::set_callbacks,
1205    EmulatedCamera::enable_msg_type,
1206    EmulatedCamera::disable_msg_type,
1207    EmulatedCamera::msg_type_enabled,
1208    EmulatedCamera::start_preview,
1209    EmulatedCamera::stop_preview,
1210    EmulatedCamera::preview_enabled,
1211    EmulatedCamera::store_meta_data_in_buffers,
1212    EmulatedCamera::start_recording,
1213    EmulatedCamera::stop_recording,
1214    EmulatedCamera::recording_enabled,
1215    EmulatedCamera::release_recording_frame,
1216    EmulatedCamera::auto_focus,
1217    EmulatedCamera::cancel_auto_focus,
1218    EmulatedCamera::take_picture,
1219    EmulatedCamera::cancel_picture,
1220    EmulatedCamera::set_parameters,
1221    EmulatedCamera::get_parameters,
1222    EmulatedCamera::put_parameters,
1223    EmulatedCamera::send_command,
1224    EmulatedCamera::release,
1225    EmulatedCamera::dump
1226};
1227
1228/****************************************************************************
1229 * Common keys
1230 ***************************************************************************/
1231
1232const char EmulatedCamera::FACING_KEY[]         = "prop-facing";
1233const char EmulatedCamera::ORIENTATION_KEY[]    = "prop-orientation";
1234const char EmulatedCamera::RECORDING_HINT_KEY[] = "recording-hint";
1235
1236/****************************************************************************
1237 * Common string values
1238 ***************************************************************************/
1239
1240const char EmulatedCamera::FACING_BACK[]      = "back";
1241const char EmulatedCamera::FACING_FRONT[]     = "front";
1242
1243/****************************************************************************
1244 * Helper routines
1245 ***************************************************************************/
1246
1247static char* AddValue(const char* param, const char* val)
1248{
1249    const size_t len1 = strlen(param);
1250    const size_t len2 = strlen(val);
1251    char* ret = reinterpret_cast<char*>(malloc(len1 + len2 + 2));
1252    ALOGE_IF(ret == NULL, "%s: Memory failure", __FUNCTION__);
1253    if (ret != NULL) {
1254        memcpy(ret, param, len1);
1255        ret[len1] = ',';
1256        memcpy(ret + len1 + 1, val, len2);
1257        ret[len1 + len2 + 1] = '\0';
1258    }
1259    return ret;
1260}
1261
1262/****************************************************************************
1263 * Parameter debugging helpers
1264 ***************************************************************************/
1265
1266#if DEBUG_PARAM
1267static void PrintParamDiff(const CameraParameters& current,
1268                            const char* new_par)
1269{
1270    char tmp[2048];
1271    const char* wrk = new_par;
1272
1273    /* Divided with ';' */
1274    const char* next = strchr(wrk, ';');
1275    while (next != NULL) {
1276        snprintf(tmp, sizeof(tmp), "%.*s", (int)(intptr_t)(next-wrk), wrk);
1277        /* in the form key=value */
1278        char* val = strchr(tmp, '=');
1279        if (val != NULL) {
1280            *val = '\0'; val++;
1281            const char* in_current = current.get(tmp);
1282            if (in_current != NULL) {
1283                if (strcmp(in_current, val)) {
1284                    ALOGD("=== Value changed: %s: %s -> %s", tmp, in_current, val);
1285                }
1286            } else {
1287                ALOGD("+++ New parameter: %s=%s", tmp, val);
1288            }
1289        } else {
1290            ALOGW("No value separator in %s", tmp);
1291        }
1292        wrk = next + 1;
1293        next = strchr(wrk, ';');
1294    }
1295}
1296#endif  /* DEBUG_PARAM */
1297
1298}; /* namespace android */
1299