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 <stdio.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, "(30000,30000)");
180    mParameters.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, "30000,30000");
181    mParameters.setPreviewFrameRate(30);
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    if (!mPreviewWindow.isPreviewEnabled()) {
396        ALOGE("%s: start recording without preview enabled",
397              __FUNCTION__);
398        return INVALID_OPERATION;
399    }
400    int frameRate = mParameters.getPreviewFrameRate();
401    status_t res = mCallbackNotifier.enableVideoRecording(frameRate);
402    if (res != NO_ERROR) {
403        ALOGE("%s: CallbackNotifier failed to enable video recording",
404              __FUNCTION__);
405        stopRecording();
406        return -res;
407    }
408    EmulatedCameraDevice* const camera_dev = getCameraDevice();
409    if (camera_dev == nullptr || !camera_dev->isStarted()) {
410        // No need for restarts, the next preview start will use correct params
411        return NO_ERROR;
412    }
413
414    // If the camera is running we might have to restart it to accomodate
415    // whatever pixel format and frame size the caller wants.
416    uint32_t conf_fmt = 0;
417    res = getConfiguredPixelFormat(&conf_fmt);
418    if (res != NO_ERROR) {
419        stopRecording();
420        return -res;
421    }
422    uint32_t cur_fmt = camera_dev->getOriginalPixelFormat();
423    int conf_width = -1, conf_height = -1;
424    res = getConfiguredFrameSize(&conf_width, &conf_height);
425    if (res != NO_ERROR) {
426        stopRecording();
427        return -res;
428    }
429    int cur_width = camera_dev->getFrameWidth();
430    int cur_height = camera_dev->getFrameHeight();
431
432    if (cur_fmt != conf_fmt ||
433            cur_width != conf_width ||
434            cur_height != conf_height) {
435        // We need to perform a restart to use the new format or size and it
436        // has to be an asynchronous restart or this might block if the camera
437        // thread is currently delivering a frame.
438        if (!camera_dev->requestRestart(conf_width, conf_height, conf_fmt,
439                                        false /* takingPicture */,
440                                        false /* oneBurst */)) {
441            ALOGE("%s: Could not restart preview with new pixel format",
442                  __FUNCTION__);
443            stopRecording();
444            return -EINVAL;
445        }
446    }
447    ALOGD("go all the way to the end");
448    return NO_ERROR;
449}
450
451void EmulatedCamera::stopRecording()
452{
453    mCallbackNotifier.disableVideoRecording();
454}
455
456int EmulatedCamera::isRecordingEnabled()
457{
458    return mCallbackNotifier.isVideoRecordingEnabled();
459}
460
461void EmulatedCamera::releaseRecordingFrame(const void* opaque)
462{
463    mCallbackNotifier.releaseRecordingFrame(opaque);
464}
465
466status_t EmulatedCamera::setAutoFocus()
467{
468    // Make sure to check that a preview is in progress. Otherwise this will
469    // silently fail because no callback will be called until the preview starts
470    // which might be never.
471    if (!isPreviewEnabled()) {
472        return EINVAL;
473    }
474    EmulatedCameraDevice* const camera_dev = getCameraDevice();
475    if (camera_dev && camera_dev->isStarted()) {
476        return camera_dev->setAutoFocus();
477    }
478    return EINVAL;
479}
480
481status_t EmulatedCamera::cancelAutoFocus()
482{
483    // In this case we don't check if a preview is in progress or not. Unlike
484    // setAutoFocus this call will not silently fail without the check. If an
485    // auto-focus request is somehow pending without having preview enabled this
486    // will correctly cancel that pending auto-focus which seems reasonable.
487    EmulatedCameraDevice* const camera_dev = getCameraDevice();
488    if (camera_dev && camera_dev->isStarted()) {
489        return camera_dev->cancelAutoFocus();
490    }
491    return EINVAL;
492}
493
494status_t EmulatedCamera::takePicture()
495{
496    ALOGV("%s", __FUNCTION__);
497
498    status_t res;
499    int width, height;
500    uint32_t org_fmt;
501
502    /* Collect frame info for the picture. */
503    mParameters.getPictureSize(&width, &height);
504    const char* pix_fmt = mParameters.getPictureFormat();
505    if (!GetFourCcFormatFromCameraParam(pix_fmt, &org_fmt)) {
506        // Also check for JPEG here, the function above does not do this since
507        // this is very specific to this use case.
508        if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_JPEG) == 0) {
509            /* We only have JPEG converted for NV21 format. */
510            org_fmt = V4L2_PIX_FMT_NV21;
511        } else {
512            ALOGE("%s: Unsupported pixel format %s", __FUNCTION__, pix_fmt);
513            return EINVAL;
514        }
515    }
516
517    /* Get JPEG quality. */
518    int jpeg_quality = mParameters.getInt(CameraParameters::KEY_JPEG_QUALITY);
519    if (jpeg_quality <= 0) {
520        jpeg_quality = 90;  /* Fall back to default. */
521    }
522
523    /*
524     * Make sure preview is not running, and device is stopped before taking
525     * picture.
526     */
527
528    EmulatedCameraDevice* const camera_dev = getCameraDevice();
529    mCallbackNotifier.setJpegQuality(jpeg_quality);
530    mCallbackNotifier.setCameraParameters(mParameters);
531
532    ALOGD("Starting camera for picture: %.4s(%s)[%dx%d]",
533          reinterpret_cast<const char*>(&org_fmt), pix_fmt, width, height);
534    if (mPreviewWindow.isPreviewEnabled()) {
535        mPreviewWindow.stopPreview();
536        /* If the camera preview is enabled we need to perform an asynchronous
537         * restart. A blocking restart could deadlock this thread as it's
538         * currently holding the camera client lock and the frame delivery could
539         * be stuck on waiting for that lock. If this was synchronous then this
540         * thread would in turn get stuck on waiting for the delivery thread. */
541        if (!camera_dev->requestRestart(width, height, org_fmt,
542                                        true /* takingPicture */,
543                                        true /* oneBurst */)) {
544            return UNKNOWN_ERROR;
545        }
546        return NO_ERROR;
547    } else {
548        ALOGE("%s: preview has not been enabled", __FUNCTION__);
549        return EINVAL;
550    }
551}
552
553status_t EmulatedCamera::cancelPicture()
554{
555    ALOGV("%s", __FUNCTION__);
556    return NO_ERROR;
557}
558
559status_t EmulatedCamera::setParameters(const char* parms)
560{
561    ALOGV("%s", __FUNCTION__);
562    PrintParamDiff(mParameters, parms);
563
564    CameraParameters new_param;
565    String8 str8_param(parms);
566    new_param.unflatten(str8_param);
567    bool restartPreview = false;
568
569    /*
570     * Check for new exposure compensation parameter.
571     */
572    int new_exposure_compensation = new_param.getInt(
573            CameraParameters::KEY_EXPOSURE_COMPENSATION);
574    const int min_exposure_compensation = new_param.getInt(
575            CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION);
576    const int max_exposure_compensation = new_param.getInt(
577            CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION);
578
579    // Checks if the exposure compensation change is supported.
580    if ((min_exposure_compensation != 0) || (max_exposure_compensation != 0)) {
581        if (new_exposure_compensation > max_exposure_compensation) {
582            new_exposure_compensation = max_exposure_compensation;
583        }
584        if (new_exposure_compensation < min_exposure_compensation) {
585            new_exposure_compensation = min_exposure_compensation;
586        }
587
588        const int current_exposure_compensation = mParameters.getInt(
589                CameraParameters::KEY_EXPOSURE_COMPENSATION);
590        if (current_exposure_compensation != new_exposure_compensation) {
591            const float exposure_value = new_exposure_compensation *
592                    new_param.getFloat(
593                            CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP);
594
595            getCameraDevice()->setExposureCompensation(
596                    exposure_value);
597        }
598    }
599
600    const char* new_white_balance = new_param.get(
601            CameraParameters::KEY_WHITE_BALANCE);
602    const char* supported_white_balance = new_param.get(
603            CameraParameters::KEY_SUPPORTED_WHITE_BALANCE);
604
605    if ((supported_white_balance != NULL) && (new_white_balance != NULL) &&
606        (strstr(supported_white_balance, new_white_balance) != NULL)) {
607
608        const char* current_white_balance = mParameters.get(
609                CameraParameters::KEY_WHITE_BALANCE);
610        if ((current_white_balance == NULL) ||
611            (strcmp(current_white_balance, new_white_balance) != 0)) {
612            ALOGV("Setting white balance to %s", new_white_balance);
613            getCameraDevice()->setWhiteBalanceMode(new_white_balance);
614        }
615    }
616    int old_frame_rate = mParameters.getPreviewFrameRate();
617    int new_frame_rate = new_param.getPreviewFrameRate();
618    if (old_frame_rate != new_frame_rate) {
619        getCameraDevice()->setPreviewFrameRate(new_frame_rate);
620    }
621
622    // Validate focus mode
623    const char* focus_mode = new_param.get(CameraParameters::KEY_FOCUS_MODE);
624    if (focus_mode && !IsValueInList(focus_mode, kValidFocusModes)) {
625        return BAD_VALUE;
626    }
627
628    // Validate preview size, if there is no preview size the initial values of
629    // the integers below will be preserved thus intentionally failing the test
630    int new_preview_width = -1, new_preview_height = -1;
631    new_param.getPreviewSize(&new_preview_width, &new_preview_height);
632    if (new_preview_width < 0 || new_preview_height < 0) {
633        return BAD_VALUE;
634    }
635    // If the preview size has changed we have to restart the preview to make
636    // sure we provide frames of the correct size. The receiver assumes the
637    // frame size is correct and will copy all data provided into a buffer whose
638    // size is determined by the preview size without checks, potentially
639    // causing buffer overruns or underruns if there is a size mismatch.
640    int old_preview_width = -1, old_preview_height = -1;
641    mParameters.getPreviewSize(&old_preview_width, &old_preview_height);
642    if (old_preview_width != new_preview_width ||
643            old_preview_height != new_preview_height) {
644        restartPreview = true;
645    }
646
647    // For the same reasons as with the preview size we have to look for changes
648    // in video size and restart the preview if the size has changed.
649    int old_video_width = -1, old_video_height = -1;
650    int new_video_width = -1, new_video_height = -1;
651    mParameters.getVideoSize(&old_video_width, &old_video_height);
652    new_param.getVideoSize(&new_video_width, &new_video_height);
653    if (old_video_width != new_video_width ||
654        old_video_height != new_video_height) {
655        restartPreview = true;
656    }
657    // Restart the preview if the pixel format changes to make sure we serve
658    // the selected encoding to the client.
659    const char* old_format = mParameters.getPreviewFormat();
660    const char* new_format = new_param.getPreviewFormat();
661    if (!StringsEqual(old_format, new_format)) {
662        restartPreview = true;
663    }
664
665    const char* old_hint =
666        mParameters.get(CameraParameters::KEY_RECORDING_HINT);
667    const char* new_hint = new_param.get(CameraParameters::KEY_RECORDING_HINT);
668    if (!StringsEqual(old_hint, new_hint)) {
669        // The recording hint changed, this indicates we transitioned from
670        // recording to non-recording or the other way around. We need to look
671        // at a new pixel format for this and that requires a restart.
672        restartPreview = true;
673    }
674
675    mParameters = new_param;
676
677    // Now that the parameters have been assigned check if the preview needs to
678    // be restarted. If necessary this will then use the new parameters to set
679    // up the preview as requested by the caller.
680    if (restartPreview && isPreviewEnabled()) {
681        status_t status = doStopPreview();
682        if (status != NO_ERROR) {
683            ALOGE("%s: Stopping preview failed: %d", __FUNCTION__, status);
684            return status;
685        }
686        status = doStartPreview();
687        if (status != NO_ERROR) {
688            ALOGE("%s: Starting preview failed: %d", __FUNCTION__, status);
689            return status;
690        }
691    }
692    return NO_ERROR;
693}
694
695/* A dumb variable indicating "no params" / error on the exit from
696 * EmulatedCamera::getParameters(). */
697static char lNoParam = '\0';
698char* EmulatedCamera::getParameters()
699{
700    // Read the image size and set the camera's Field of View.
701    // These values are valid for a Logitech B910 HD Webcam.
702    int width=0, height=0;
703    mParameters.getPictureSize(&width, &height);
704    if (height > 0) {
705        if (((double)width / height) < 1.55) {
706            // Closer to 4:3 (1.33), set the FOV to 61.0 degrees
707            mParameters.set(CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE, "61.0");
708        } else {
709            // Closer to 16:9 (1.77), set the FOV to 70.0 degrees
710            mParameters.set(CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE, "70.0");
711        }
712    }
713
714    String8 params(mParameters.flatten());
715    char* ret_str =
716        reinterpret_cast<char*>(malloc(sizeof(char) * (params.length()+1)));
717    memset(ret_str, 0, params.length()+1);
718    if (ret_str != NULL) {
719        strncpy(ret_str, params.string(), params.length()+1);
720        return ret_str;
721    } else {
722        ALOGE("%s: Unable to allocate string for %s", __FUNCTION__, params.string());
723        /* Apparently, we can't return NULL fron this routine. */
724        return &lNoParam;
725    }
726}
727
728void EmulatedCamera::putParameters(char* params)
729{
730    /* This method simply frees parameters allocated in getParameters(). */
731    if (params != NULL && params != &lNoParam) {
732        free(params);
733    }
734}
735
736status_t EmulatedCamera::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2)
737{
738    ALOGV("%s: cmd = %d, arg1 = %d, arg2 = %d", __FUNCTION__, cmd, arg1, arg2);
739
740    switch (cmd) {
741        case CAMERA_CMD_START_FACE_DETECTION:
742        case CAMERA_CMD_STOP_FACE_DETECTION:
743            // We do not support hardware face detection so we need to indicate
744            // that any attempt to start/stop face detection is invalid
745            return BAD_VALUE;
746    }
747    /* TODO: Future enhancements. */
748    return 0;
749}
750
751void EmulatedCamera::releaseCamera()
752{
753    ALOGV("%s", __FUNCTION__);
754
755    cleanupCamera();
756}
757
758status_t EmulatedCamera::dumpCamera(int fd)
759{
760    ALOGV("%s", __FUNCTION__);
761
762    /* TODO: Future enhancements. */
763    dprintf(fd, "dump camera unimplemented\n");
764    return 0;
765}
766
767status_t EmulatedCamera::getConfiguredPixelFormat(uint32_t* pixelFormat) const {
768    const char* pix_fmt = nullptr;
769    const char* recordingHint =
770        mParameters.get(CameraParameters::KEY_RECORDING_HINT);
771    bool recordingHintOn = recordingHint && strcmp(recordingHint,
772                                                   CameraParameters::TRUE) == 0;
773    bool recordingEnabled = mCallbackNotifier.isVideoRecordingEnabled();
774    if (recordingHintOn || recordingEnabled) {
775        // We're recording a video, use the video pixel format
776        pix_fmt = mParameters.get(CameraParameters::KEY_VIDEO_FRAME_FORMAT);
777    }
778    if (pix_fmt == nullptr) {
779        pix_fmt = mParameters.getPreviewFormat();
780    }
781    if (pix_fmt == nullptr) {
782        ALOGE("%s: Unable to obtain configured pixel format", __FUNCTION__);
783        return EINVAL;
784    }
785    /* Convert framework's pixel format to the FOURCC one. */
786    if (!GetFourCcFormatFromCameraParam(pix_fmt, pixelFormat)) {
787        ALOGE("%s: Unsupported pixel format %s", __FUNCTION__, pix_fmt);
788        return EINVAL;
789    }
790    return NO_ERROR;
791}
792
793status_t EmulatedCamera::getConfiguredFrameSize(int* outWidth,
794                                                int* outHeight) const {
795    int width = -1, height = -1;
796    if (mParameters.get(CameraParameters::KEY_VIDEO_SIZE) != nullptr) {
797        mParameters.getVideoSize(&width, &height);
798    } else {
799        mParameters.getPreviewSize(&width, &height);
800    }
801    if (width < 0 || height < 0) {
802        ALOGE("%s: No frame size configured for camera", __FUNCTION__);
803        return EINVAL;
804    }
805    // Only modify the out parameters once we know we succeeded
806    *outWidth = width;
807    *outHeight = height;
808    return NO_ERROR;
809}
810
811/****************************************************************************
812 * Preview management.
813 ***************************************************************************/
814
815status_t EmulatedCamera::doStartPreview()
816{
817    ALOGV("%s", __FUNCTION__);
818
819    EmulatedCameraDevice* camera_dev = getCameraDevice();
820    if (camera_dev->isStarted()) {
821        camera_dev->stopDeliveringFrames();
822        camera_dev->stopDevice();
823    }
824
825    status_t res = mPreviewWindow.startPreview();
826    if (res != NO_ERROR) {
827        return res;
828    }
829
830    /* Make sure camera device is connected. */
831    if (!camera_dev->isConnected()) {
832        res = camera_dev->connectDevice();
833        if (res != NO_ERROR) {
834            mPreviewWindow.stopPreview();
835            return res;
836        }
837    }
838
839    /* Lets see what should we use for frame width, and height. */
840    int width, height;
841    res = getConfiguredFrameSize(&width, &height);
842    if (res != NO_ERROR) {
843        mPreviewWindow.stopPreview();
844        return res;
845    }
846
847    uint32_t org_fmt = 0;
848    res = getConfiguredPixelFormat(&org_fmt);
849    if (res != NO_ERROR) {
850        mPreviewWindow.stopPreview();
851        return res;
852    }
853
854    camera_dev->setPreviewFrameRate(mParameters.getPreviewFrameRate());
855    ALOGD("Starting camera: %dx%d -> %.4s",
856         width, height, reinterpret_cast<const char*>(&org_fmt));
857    res = camera_dev->startDevice(width, height, org_fmt);
858    if (res != NO_ERROR) {
859        mPreviewWindow.stopPreview();
860        return res;
861    }
862
863    res = camera_dev->startDeliveringFrames(false);
864    if (res != NO_ERROR) {
865        camera_dev->stopDevice();
866        mPreviewWindow.stopPreview();
867    }
868
869    return res;
870}
871
872status_t EmulatedCamera::doStopPreview()
873{
874    ALOGV("%s", __FUNCTION__);
875
876    status_t res = NO_ERROR;
877    if (mPreviewWindow.isPreviewEnabled()) {
878        /* Stop the camera. */
879        if (getCameraDevice()->isStarted()) {
880            getCameraDevice()->stopDeliveringFrames();
881            res = getCameraDevice()->stopDevice();
882        }
883
884        if (res == NO_ERROR) {
885            /* Disable preview as well. */
886            mPreviewWindow.stopPreview();
887        }
888    }
889
890    return NO_ERROR;
891}
892
893/****************************************************************************
894 * Private API.
895 ***************************************************************************/
896
897status_t EmulatedCamera::cleanupCamera()
898{
899    status_t res = NO_ERROR;
900
901    /* If preview is running - stop it. */
902    res = doStopPreview();
903    if (res != NO_ERROR) {
904        return -res;
905    }
906
907    /* Stop and disconnect the camera device. */
908    EmulatedCameraDevice* const camera_dev = getCameraDevice();
909    if (camera_dev != NULL) {
910        if (camera_dev->isStarted()) {
911            camera_dev->stopDeliveringFrames();
912            res = camera_dev->stopDevice();
913            if (res != NO_ERROR) {
914                return -res;
915            }
916        }
917        if (camera_dev->isConnected()) {
918            res = camera_dev->disconnectDevice();
919            if (res != NO_ERROR) {
920                return -res;
921            }
922        }
923    }
924
925    mCallbackNotifier.cleanupCBNotifier();
926
927    /* Re-init the camera settings in case settings were changed */
928    Initialize();
929
930    return NO_ERROR;
931}
932
933/****************************************************************************
934 * Camera API callbacks as defined by camera_device_ops structure.
935 *
936 * Callbacks here simply dispatch the calls to an appropriate method inside
937 * EmulatedCamera instance, defined by the 'dev' parameter.
938 ***************************************************************************/
939
940int EmulatedCamera::set_preview_window(struct camera_device* dev,
941                                       struct preview_stream_ops* window)
942{
943    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
944    if (ec == NULL) {
945        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
946        return -EINVAL;
947    }
948    return ec->setPreviewWindow(window);
949}
950
951void EmulatedCamera::set_callbacks(
952        struct camera_device* dev,
953        camera_notify_callback notify_cb,
954        camera_data_callback data_cb,
955        camera_data_timestamp_callback data_cb_timestamp,
956        camera_request_memory get_memory,
957        void* user)
958{
959    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
960    if (ec == NULL) {
961        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
962        return;
963    }
964    ec->setCallbacks(notify_cb, data_cb, data_cb_timestamp, get_memory, user);
965}
966
967void EmulatedCamera::enable_msg_type(struct camera_device* dev, int32_t msg_type)
968{
969    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
970    if (ec == NULL) {
971        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
972        return;
973    }
974    ec->enableMsgType(msg_type);
975}
976
977void EmulatedCamera::disable_msg_type(struct camera_device* dev, int32_t msg_type)
978{
979    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
980    if (ec == NULL) {
981        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
982        return;
983    }
984    ec->disableMsgType(msg_type);
985}
986
987int EmulatedCamera::msg_type_enabled(struct camera_device* dev, int32_t msg_type)
988{
989    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
990    if (ec == NULL) {
991        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
992        return -EINVAL;
993    }
994    return ec->isMsgTypeEnabled(msg_type);
995}
996
997int EmulatedCamera::start_preview(struct camera_device* dev)
998{
999    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1000    if (ec == NULL) {
1001        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1002        return -EINVAL;
1003    }
1004    return ec->startPreview();
1005}
1006
1007void EmulatedCamera::stop_preview(struct camera_device* dev)
1008{
1009    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1010    if (ec == NULL) {
1011        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1012        return;
1013    }
1014    ec->stopPreview();
1015}
1016
1017int EmulatedCamera::preview_enabled(struct camera_device* dev)
1018{
1019    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1020    if (ec == NULL) {
1021        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1022        return -EINVAL;
1023    }
1024    return ec->isPreviewEnabled();
1025}
1026
1027int EmulatedCamera::store_meta_data_in_buffers(struct camera_device* dev,
1028                                               int enable)
1029{
1030    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1031    if (ec == NULL) {
1032        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1033        return -EINVAL;
1034    }
1035    return ec->storeMetaDataInBuffers(enable);
1036}
1037
1038int EmulatedCamera::start_recording(struct camera_device* dev)
1039{
1040    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1041    if (ec == NULL) {
1042        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1043        return -EINVAL;
1044    }
1045    return ec->startRecording();
1046}
1047
1048void EmulatedCamera::stop_recording(struct camera_device* dev)
1049{
1050    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1051    if (ec == NULL) {
1052        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1053        return;
1054    }
1055    ec->stopRecording();
1056}
1057
1058int EmulatedCamera::recording_enabled(struct camera_device* dev)
1059{
1060    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1061    if (ec == NULL) {
1062        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1063        return -EINVAL;
1064    }
1065    return ec->isRecordingEnabled();
1066}
1067
1068void EmulatedCamera::release_recording_frame(struct camera_device* dev,
1069                                             const void* opaque)
1070{
1071    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1072    if (ec == NULL) {
1073        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1074        return;
1075    }
1076    ec->releaseRecordingFrame(opaque);
1077}
1078
1079int EmulatedCamera::auto_focus(struct camera_device* dev)
1080{
1081    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1082    if (ec == NULL) {
1083        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1084        return -EINVAL;
1085    }
1086    return ec->setAutoFocus();
1087}
1088
1089int EmulatedCamera::cancel_auto_focus(struct camera_device* dev)
1090{
1091    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1092    if (ec == NULL) {
1093        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1094        return -EINVAL;
1095    }
1096    return ec->cancelAutoFocus();
1097}
1098
1099int EmulatedCamera::take_picture(struct camera_device* dev)
1100{
1101    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1102    if (ec == NULL) {
1103        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1104        return -EINVAL;
1105    }
1106    return ec->takePicture();
1107}
1108
1109int EmulatedCamera::cancel_picture(struct camera_device* dev)
1110{
1111    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1112    if (ec == NULL) {
1113        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1114        return -EINVAL;
1115    }
1116    return ec->cancelPicture();
1117}
1118
1119int EmulatedCamera::set_parameters(struct camera_device* dev, const char* parms)
1120{
1121    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1122    if (ec == NULL) {
1123        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1124        return -EINVAL;
1125    }
1126    return ec->setParameters(parms);
1127}
1128
1129char* EmulatedCamera::get_parameters(struct camera_device* dev)
1130{
1131    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1132    if (ec == NULL) {
1133        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1134        return NULL;
1135    }
1136    return ec->getParameters();
1137}
1138
1139void EmulatedCamera::put_parameters(struct camera_device* dev, char* params)
1140{
1141    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1142    if (ec == NULL) {
1143        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1144        return;
1145    }
1146    ec->putParameters(params);
1147}
1148
1149int EmulatedCamera::send_command(struct camera_device* dev,
1150                                 int32_t cmd,
1151                                 int32_t arg1,
1152                                 int32_t arg2)
1153{
1154    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1155    if (ec == NULL) {
1156        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1157        return -EINVAL;
1158    }
1159    return ec->sendCommand(cmd, arg1, arg2);
1160}
1161
1162void EmulatedCamera::release(struct camera_device* dev)
1163{
1164    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1165    if (ec == NULL) {
1166        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1167        return;
1168    }
1169    ec->releaseCamera();
1170}
1171
1172int EmulatedCamera::dump(struct camera_device* dev, int fd)
1173{
1174    EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
1175    if (ec == NULL) {
1176        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1177        return -EINVAL;
1178    }
1179    return ec->dumpCamera(fd);
1180}
1181
1182int EmulatedCamera::close(struct hw_device_t* device)
1183{
1184    EmulatedCamera* ec =
1185        reinterpret_cast<EmulatedCamera*>(reinterpret_cast<struct camera_device*>(device)->priv);
1186    if (ec == NULL) {
1187        ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
1188        return -EINVAL;
1189    }
1190    return ec->closeCamera();
1191}
1192
1193/****************************************************************************
1194 * Static initializer for the camera callback API
1195 ****************************************************************************/
1196
1197camera_device_ops_t EmulatedCamera::mDeviceOps = {
1198    EmulatedCamera::set_preview_window,
1199    EmulatedCamera::set_callbacks,
1200    EmulatedCamera::enable_msg_type,
1201    EmulatedCamera::disable_msg_type,
1202    EmulatedCamera::msg_type_enabled,
1203    EmulatedCamera::start_preview,
1204    EmulatedCamera::stop_preview,
1205    EmulatedCamera::preview_enabled,
1206    EmulatedCamera::store_meta_data_in_buffers,
1207    EmulatedCamera::start_recording,
1208    EmulatedCamera::stop_recording,
1209    EmulatedCamera::recording_enabled,
1210    EmulatedCamera::release_recording_frame,
1211    EmulatedCamera::auto_focus,
1212    EmulatedCamera::cancel_auto_focus,
1213    EmulatedCamera::take_picture,
1214    EmulatedCamera::cancel_picture,
1215    EmulatedCamera::set_parameters,
1216    EmulatedCamera::get_parameters,
1217    EmulatedCamera::put_parameters,
1218    EmulatedCamera::send_command,
1219    EmulatedCamera::release,
1220    EmulatedCamera::dump
1221};
1222
1223/****************************************************************************
1224 * Common keys
1225 ***************************************************************************/
1226
1227const char EmulatedCamera::FACING_KEY[]         = "prop-facing";
1228const char EmulatedCamera::ORIENTATION_KEY[]    = "prop-orientation";
1229const char EmulatedCamera::RECORDING_HINT_KEY[] = "recording-hint";
1230
1231/****************************************************************************
1232 * Common string values
1233 ***************************************************************************/
1234
1235const char EmulatedCamera::FACING_BACK[]      = "back";
1236const char EmulatedCamera::FACING_FRONT[]     = "front";
1237
1238/****************************************************************************
1239 * Helper routines
1240 ***************************************************************************/
1241
1242static char* AddValue(const char* param, const char* val)
1243{
1244    const size_t len1 = strlen(param);
1245    const size_t len2 = strlen(val);
1246    char* ret = reinterpret_cast<char*>(malloc(len1 + len2 + 2));
1247    ALOGE_IF(ret == NULL, "%s: Memory failure", __FUNCTION__);
1248    if (ret != NULL) {
1249        memcpy(ret, param, len1);
1250        ret[len1] = ',';
1251        memcpy(ret + len1 + 1, val, len2);
1252        ret[len1 + len2 + 1] = '\0';
1253    }
1254    return ret;
1255}
1256
1257/****************************************************************************
1258 * Parameter debugging helpers
1259 ***************************************************************************/
1260
1261#if DEBUG_PARAM
1262static void PrintParamDiff(const CameraParameters& current,
1263                            const char* new_par)
1264{
1265    char tmp[2048];
1266    const char* wrk = new_par;
1267
1268    /* Divided with ';' */
1269    const char* next = strchr(wrk, ';');
1270    while (next != NULL) {
1271        snprintf(tmp, sizeof(tmp), "%.*s", (int)(intptr_t)(next-wrk), wrk);
1272        /* in the form key=value */
1273        char* val = strchr(tmp, '=');
1274        if (val != NULL) {
1275            *val = '\0'; val++;
1276            const char* in_current = current.get(tmp);
1277            if (in_current != NULL) {
1278                if (strcmp(in_current, val)) {
1279                    ALOGD("=== Value changed: %s: %s -> %s", tmp, in_current, val);
1280                }
1281            } else {
1282                ALOGD("+++ New parameter: %s=%s", tmp, val);
1283            }
1284        } else {
1285            ALOGW("No value separator in %s", tmp);
1286        }
1287        wrk = next + 1;
1288        next = strchr(wrk, ';');
1289    }
1290}
1291#endif  /* DEBUG_PARAM */
1292
1293}; /* namespace android */
1294