vconf: Implementation of module-vconf/vconf-helper 13/96613/2
authorKimJeongYeon <jeongyeon.kim@samsung.com>
Wed, 19 Oct 2016 09:58:12 +0000 (18:58 +0900)
committerJeongho Mok <jho.mok@samsung.com>
Thu, 10 Nov 2016 05:47:16 +0000 (21:47 -0800)
Changes:
* Based on module-gconf/gconf-helper.
* Support hook callback to communicate with stream-manager/device-manager.
* Included to TV product only.

[Version] 5.0.89
[Profile] TV
[Issue Type] Feature Enhancement

Signed-off-by: KimJeongYeon <jeongyeon.kim@samsung.com>
Change-Id: I3c4946f9e774a8d6ce0016c134c7dfa356249966
(cherry picked from commit f79d6c1b1ef40519594eaa99a34e1241bf65d55c)

Makefile.am
configure.ac
packaging/pulseaudio-modules-tizen.spec
src/communicator.h
src/vconf/hook-data.h [new file with mode: 0644]
src/vconf/module-vconf.c [new file with mode: 0644]
src/vconf/vconf-helper.c [new file with mode: 0644]

index 7421ffb..8f30b26 100644 (file)
@@ -18,6 +18,7 @@
 ACLOCAL_AMFLAGS = -I m4
 
 pulsemodlibexecdir= $(libdir)/pulse-5.0/modules
+pulselibexecdir=$(libexecdir)/pulse
 
 AM_CFLAGS = \
        $(PTHREAD_CFLAGS)
@@ -31,6 +32,7 @@ MODULE_LIBADD = $(AM_LIBADD) $(PACORE_LIBS) $(PA_LIBS)
 
 pulsemodlibexec_LTLIBRARIES = \
                libhal-interface.la \
+               libcommunicator.la \
                module-tizenaudio-sink.la \
                module-tizenaudio-source.la \
                module-tizenaudio-policy.la \
@@ -44,6 +46,7 @@ endif
 # These are generated by an M4 script
 SYMDEF_FILES = \
                libhal-interface-symdef.h \
+               libcommunicator-symdef.h \
                module-tizenaudio-sink-symdef.h \
                module-tizenaudio-source-symdef.h \
                module-tizenaudio-policy-symdef.h \
@@ -54,6 +57,11 @@ SYMDEF_FILES += \
                module-tizenaudio-haltc-symdef.h
 endif
 
+if ENABLE_VCONF_HELPER
+SYMDEF_FILES += \
+               module-vconf-symdef.h
+endif
+
 if HAVE_DBUS
 
 endif
@@ -71,6 +79,12 @@ libhal_interface_la_LDFLAGS = $(AM_LDFLAGS) $(PA_LDFLAGS) -avoid-version
 libhal_interface_la_LIBADD = $(AM_LIBADD) $(PACORE_LIBS) $(PA_LIBS)
 libhal_interface_la_CFLAGS = $(AM_CFLAGS) $(PACORE_CFLAGS) $(PA_CFLAGS)
 
+libcommunicator_la_SOURCES = \
+          src/communicator.c   src/communicator.h
+libcommunicator_la_LDFLAGS = $(AM_LDFLAGS) $(PA_LDFLAGS) -avoid-version
+libcommunicator_la_LIBADD = $(AM_LIBADD) $(PACORE_LIBS) $(PA_LIBS)
+libcommunicator_la_CFLAGS = $(AM_CFLAGS) $(PACORE_CFLAGS) $(PA_CFLAGS)
+
 module_tizenaudio_sink_la_SOURCES = src/module-tizenaudio-sink.c
 module_tizenaudio_sink_la_LDFLAGS = $(MODULE_LDFLAGS)
 module_tizenaudio_sink_la_LIBADD = $(MODULE_LIBADD) libhal-interface.la
@@ -88,14 +102,13 @@ module_sound_player_la_CFLAGS = $(MODULE_CFLAGS) $(DBUS_CFLAGS)
 
 module_tizenaudio_policy_la_SOURCES = \
           src/module-tizenaudio-policy.c   \
-          src/communicator.c   src/communicator.h   \
           src/stream-manager.c   src/stream-manager.h   src/stream-manager-priv.h   \
           src/stream-manager-volume.c   src/stream-manager-volume.h   src/stream-manager-volume-priv.h   \
           src/stream-manager-restriction.c   src/stream-manager-restriction-priv.h   \
           src/device-manager.c   src/device-manager.h   src/tizen-device.c   src/tizen-device.h   src/tizen-device-def.c  src/tizen-device-def.h  \
           src/subscribe-observer.c   src/subscribe-observer.h
 module_tizenaudio_policy_la_LDFLAGS = $(MODULE_LDFLAGS) -L$(pulsemodlibexecdir)
-module_tizenaudio_policy_la_LIBADD = $(MODULE_LIBADD) $(DBUS_LIBS) $(VCONF_LIBS) $(INIPARSER_LIBS) $(LIBJSON_LIBS) libhal-interface.la
+module_tizenaudio_policy_la_LIBADD = $(MODULE_LIBADD) $(DBUS_LIBS) $(VCONF_LIBS) $(INIPARSER_LIBS) $(LIBJSON_LIBS) libhal-interface.la libcommunicator.la
 module_tizenaudio_policy_la_CFLAGS = $(MODULE_CFLAGS) $(DBUS_CFLAGS) $(VCONF_CFLAGS) $(INIPARSER_CFLAGS) $(LIBJSON_CFLAGS)
 
 if ENABLE_HALTC
@@ -109,3 +122,19 @@ module_hw_keysound_la_SOURCES = src/module-hw-keysound.c
 module_hw_keysound_la_LDFLAGS = $(MODULE_LDFLAGS)
 module_hw_keysound_la_LIBADD = $(MODULE_LIBADD) $(DBUS_LIBS) $(VCONF_LIBS)
 module_hw_keysound_la_CFLAGS = $(MODULE_CFLAGS) $(DBUS_CFLAGS) $(VCONF_CFLAGS)
+
+if ENABLE_VCONF_HELPER
+pulsemodlibexec_LTLIBRARIES += module-vconf.la
+
+module_vconf_la_SOURCES = src/vconf/module-vconf.c
+module_vconf_la_LDFLAGS = $(MODULE_LDFLAGS)
+module_vconf_la_LIBADD = $(MODULE_LIBADD) libcommunicator.la
+module_vconf_la_CFLAGS = $(MODULE_CFLAGS) -DPA_VCONF_HELPER=\"$(pulselibexecdir)/vconf-helper\"
+
+pulselibexec_PROGRAMS = vconf-helper
+
+vconf_helper_SOURCES = src/vconf/vconf-helper.c
+vconf_helper_LDFLAGS = $(AM_LDFLAGS)
+vconf_helper_LDADD = $(AM_LIBADD) $(GLIB2_LIBS) $(VCONF_LIBS)
+vconf_helper_CFLAGS = $(AM_CFLAGS) $(GLIB2_CFLAGS) $(VCONF_CFLAGS) -fPIC -pie
+endif
index 34b05f8..f578a47 100644 (file)
@@ -337,6 +337,7 @@ AC_CHECK_FUNCS_ONCE([open64])
 PKG_CHECK_MODULES(PA, libpulse)
 AC_SUBST(PA_CFLAGS)
 AC_SUBST(PA_LIBS)
+AC_SUBST(PA_LDFLAGS)
 
 PKG_CHECK_MODULES(PACORE, pulsecore)
 AC_SUBST(PACORE_CFLAGS)
@@ -403,6 +404,21 @@ PA_MACHINE_ID_FALLBACK="${localstatedir}/lib/dbus/machine-id"
 AX_DEFINE_DIR(PA_MACHINE_ID_FALLBACK, PA_MACHINE_ID_FALLBACK,
              [Fallback machine-id file])
 
+#### vconf helper support (optional) ####
+PKG_CHECK_MODULES(GLIB2, glib-2.0)
+AC_SUBST(GLIB2_CFLAGS)
+AC_SUBST(GLIB2_LIBS)
+
+AC_ARG_ENABLE(vconf-helper, AC_HELP_STRING([--enable-vconf-helper], [using vconf-helper]),
+[
+ case "${enableval}" in
+        yes) ENABLE_VCONF_HELPER=yes ;;
+        no)  ENABLE_VCONF_HELPER=no ;;
+        *)   AC_MSG_ERROR(bad value ${enableval} for --enable-vconf-helper) ;;
+ esac
+ ],[ENABLE_VCONF_HELPER=no])
+AM_CONDITIONAL(ENABLE_VCONF_HELPER, test "x$ENABLE_VCONF_HELPER" = "xyes")
+
 ###################################
 #            Output               #
 ###################################
index 9c4f8de..6c7912e 100644 (file)
@@ -1,6 +1,6 @@
 Name:             pulseaudio-modules-tizen
 Summary:          Pulseaudio modules for Tizen
-Version:          5.0.88
+Version:          5.0.89
 Release:          0
 Group:            Multimedia/Audio
 License:          LGPL-2.1+
@@ -13,6 +13,9 @@ BuildRequires:    pkgconfig(dbus-1)
 BuildRequires:    pkgconfig(iniparser)
 BuildRequires:    pkgconfig(json-c)
 BuildRequires:    pkgconfig(vconf)
+%if "%{?TIZEN_PRODUCT_TV}" == "1"
+BuildRequires:    pkgconfig(glib-2.0)
+%endif
 BuildRequires:    mm-hal-interface
 BuildRequires:    pkgconfig(libpulse)
 BuildRequires:    pkgconfig(pulsecore)
@@ -34,6 +37,9 @@ export CFLAGS="%{optflags} -fno-strict-aliasing -DSYSCONFDIR=\\\"%{_sysconfdir}\
 export LD_AS_NEEDED=0
 %reconfigure --prefix=%{_prefix} \
         --disable-static \
+%if "%{?TIZEN_PRODUCT_TV}" == "1"
+        --enable-vconf-helper
+%endif
 #        --enable-haltc
 
 %__make %{?_smp_mflags} V=1
@@ -56,4 +62,9 @@ install -m 0644 %SOURCE1 %{buildroot}%{_tmpfilesdir}/pulseaudio.conf
 %license LICENSE.LGPL-2.1+
 %{_libdir}/pulse-5.0/modules/module-*.so
 %{_libdir}/pulse-5.0/modules/libhal-interface.so
+%{_libdir}/pulse-5.0/modules/libcommunicator.so
 %{_tmpfilesdir}/pulseaudio.conf
+%if "%{?TIZEN_PRODUCT_TV}" == "1"
+%{_libdir}/pulse-5.0/modules/module-vconf.so
+%{_libexecdir}/pulse/vconf-helper
+%endif
index 849c6be..985f959 100644 (file)
@@ -32,6 +32,7 @@ typedef enum pa_communicator_hook {
     PA_COMMUNICATOR_HOOK_DEVICE_STATE_CHANGED,       /* It is fired when a device's state is changed */
     PA_COMMUNICATOR_HOOK_EVENT_FULLY_HANDLED,        /* It is fired when a event is handled by all subscribers */
     PA_COMMUNICATOR_HOOK_UPDATE_INFORMATION,         /* It is fired when information should be updated */
+    PA_COMMUNICATOR_HOOK_UPDATE_VCONF,               /* It is fired when a vconf has updated */
     PA_COMMUNICATOR_HOOK_MAX
 } pa_communicator_hook_t;
 
diff --git a/src/vconf/hook-data.h b/src/vconf/hook-data.h
new file mode 100644 (file)
index 0000000..d0c0bcc
--- /dev/null
@@ -0,0 +1,65 @@
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2016 KimJeongYeon <jeongyeon.kim@samsung.com>
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as published
+  by the Free Software Foundation; either version 2.1 of the License,
+  or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifndef footizenmodulevconffoo
+#define footizenmodulevconffoo
+
+/* Definition for hooking method */
+typedef struct _hook_call_data_for_vconf_changed {
+    char *key;
+    char *value;
+} pa_module_vconf_hook_data_for_vconf_changed;
+
+/* Definitions for vconf prefix items */
+enum {
+    VCONF_PATH_PREFIX_VOLUME = 0,
+    /* TODO: TBD */
+    VCONF_PATH_PREFIX_MAX
+};
+
+const char *vconf_prefix[VCONF_PATH_PREFIX_MAX] = {
+        "file/private/sound/volume/",  /**< VCONF_PATH_PREFIX_VOLUME */
+        /* TODO: TBD */
+};
+
+/* Definitions for vconf items for watching */
+struct vconf_item {
+    char opcode;
+    int prefix;
+    const char *name;
+    int is_notify;
+} vitems[] = {
+        { 'V', VCONF_PATH_PREFIX_VOLUME, "AD",              0 },
+        { 'V', VCONF_PATH_PREFIX_VOLUME, "Master",          0 },
+        { 'V', VCONF_PATH_PREFIX_VOLUME, "MasterHeadphone", 0 },
+        { 'V', VCONF_PATH_PREFIX_VOLUME, "MasterMuteOn",    0 },
+        { 'V', VCONF_PATH_PREFIX_VOLUME, "alarm",           1 },
+        { 'V', VCONF_PATH_PREFIX_VOLUME, "call",            1 },
+        { 'V', VCONF_PATH_PREFIX_VOLUME, "master",          1 },
+        { 'V', VCONF_PATH_PREFIX_VOLUME, "media",           1 },
+        { 'V', VCONF_PATH_PREFIX_VOLUME, "notification",    1 },
+        { 'V', VCONF_PATH_PREFIX_VOLUME, "ringtone",        1 },
+        { 'V', VCONF_PATH_PREFIX_VOLUME, "system",          1 },
+        { 'V', VCONF_PATH_PREFIX_VOLUME, "voice",           1 },
+        { 'V', VCONF_PATH_PREFIX_VOLUME, "voip",            1 },
+    };
+
+#endif
diff --git a/src/vconf/module-vconf.c b/src/vconf/module-vconf.c
new file mode 100644 (file)
index 0000000..0270002
--- /dev/null
@@ -0,0 +1,274 @@
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2016 KimJeongYeon <jeongyeon.kim@samsung.com>
+
+    Based on module-gconf.c
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as published
+  by the Free Software Foundation; either version 2.1 of the License,
+  or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <pulse/xmalloc.h>
+#include <pulsecore/module.h>
+#include <pulsecore/core.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/log.h>
+#include <pulse/mainloop-api.h>
+#include <pulsecore/core-error.h>
+#include <pulsecore/start-child.h>
+
+#include "../communicator.h"
+#include "module-vconf-symdef.h"
+#include "hook-data.h"
+
+PA_MODULE_AUTHOR("KimJeongYeon");
+PA_MODULE_DESCRIPTION("VCONF Adapter");
+PA_MODULE_VERSION(PACKAGE_VERSION);
+PA_MODULE_LOAD_ONCE(true);
+
+#define BUF_MAX    2048
+
+struct userdata {
+    pa_core *core;
+    pa_module *module;
+
+    pid_t pid;
+
+    int fd;
+    int fd_type;
+    pa_io_event *io_event;
+
+    char buf[BUF_MAX];
+    size_t buf_fill;
+
+    pa_communicator *comm;
+};
+
+static int fill_buf(struct userdata *u) {
+    ssize_t r;
+    pa_assert(u);
+
+    if (u->buf_fill >= BUF_MAX) {
+        pa_log_error("read buffer overflow");
+        return -1;
+    }
+
+    if ((r = pa_read(u->fd, u->buf + u->buf_fill, BUF_MAX - u->buf_fill, &u->fd_type)) <= 0)
+        return -1;
+
+    u->buf_fill += (size_t) r;
+    return 0;
+}
+
+static int read_byte(struct userdata *u) {
+    int ret;
+    pa_assert(u);
+
+    if (u->buf_fill < 1)
+        if (fill_buf(u) < 0)
+            return -1;
+
+    ret = u->buf[0];
+    pa_assert(u->buf_fill > 0);
+    u->buf_fill--;
+    memmove(u->buf, u->buf+1, u->buf_fill);
+    return ret;
+}
+
+static char *read_string(struct userdata *u) {
+    pa_assert(u);
+
+    for (;;) {
+        char *e;
+
+        if ((e = memchr(u->buf, 0, u->buf_fill))) {
+            char *ret = pa_xstrdup(u->buf);
+            u->buf_fill -= (size_t) (e - u->buf +1);
+            memmove(u->buf, e+1, u->buf_fill);
+            return ret;
+        }
+
+        if (fill_buf(u) < 0)
+            return NULL;
+    }
+}
+
+static int handle_event(struct userdata *u) {
+    int opcode;
+    int ret = 0;
+
+    do {
+        if ((opcode = read_byte(u)) < 0) {
+            if (errno == EINTR || errno == EAGAIN)
+                break;
+            goto fail;
+        }
+
+        switch (opcode) {
+            case '!':
+                /* The helper tool is now initialized */
+                ret = 1;
+                pa_log_info("The helper tool is now initialized.");
+                break;
+
+            case 'V':
+                /* fall-through */
+
+            default: {
+                /* Default vconf changing events */
+                char *key, *value;
+                pa_module_vconf_hook_data_for_vconf_changed hook_data;
+
+                if (!(key = read_string(u)))
+                    goto fail;
+                if (!(value = read_string(u))) {
+                    pa_xfree(key);
+                    goto fail;
+                }
+
+                pa_log_info("Vconf notified. (key:%s, value:%s)", key, value);
+
+                /* Hook msg from vconf helper */
+                memset(&hook_data, 0, sizeof(pa_module_vconf_hook_data_for_vconf_changed));
+                hook_data.key = key;
+                hook_data.value = value;
+                pa_hook_fire(pa_communicator_hook(u->comm, PA_COMMUNICATOR_HOOK_UPDATE_VCONF), &hook_data);
+
+                pa_xfree(key);
+                pa_xfree(value);
+                break;
+            }
+        }
+    } while (u->buf_fill > 0 && ret == 0);
+
+    return ret;
+
+fail:
+    pa_log_error("Unable to read or parse data from client.");
+    return -1;
+}
+
+static void io_event_cb(
+        pa_mainloop_api*a,
+        pa_io_event* e,
+        int fd,
+        pa_io_event_flags_t events,
+        void *userdata) {
+
+    struct userdata *u = userdata;
+
+    if (handle_event(u) < 0) {
+
+        if (u->io_event) {
+            u->core->mainloop->io_free(u->io_event);
+            u->io_event = NULL;
+        }
+
+        pa_module_unload_request(u->module, true);
+    }
+}
+
+int pa__init(pa_module *m) {
+    struct userdata *u;
+    int r;
+
+    pa_assert(m);
+
+    u = pa_xnew(struct userdata, 1);
+    u->core = m->core;
+    u->module = m;
+    m->userdata = u;
+    u->pid = (pid_t) -1;
+    u->fd = -1;
+    u->fd_type = 0;
+    u->io_event = NULL;
+    u->buf_fill = 0;
+    u->comm = pa_communicator_get(m->core);
+
+    if ((u->fd = pa_start_child_for_read(
+#if defined(__linux__) && !defined(__OPTIMIZE__)
+            pa_run_from_build_tree() ? PA_BUILDDIR "/vconf-helper" :
+#endif
+            PA_VCONF_HELPER, NULL, &u->pid)) < 0)
+        goto fail;
+
+    u->io_event = m->core->mainloop->io_new(
+            m->core->mainloop,
+            u->fd,
+            PA_IO_EVENT_INPUT,
+            io_event_cb,
+            u);
+
+    do {
+        if ((r = handle_event(u)) < 0)
+            goto fail;
+
+        /* Read until the client signalled us that it is ready with
+         * initialization */
+    } while (r != 1);
+
+    return 0;
+
+fail:
+    pa__done(m);
+    return -1;
+}
+
+void pa__done(pa_module *m) {
+    struct userdata *u;
+
+    pa_assert(m);
+
+    if (!(u = m->userdata))
+        return;
+
+    if (u->comm)
+        pa_communicator_unref(u->comm);
+
+    if (u->pid != (pid_t) -1) {
+        kill(u->pid, SIGTERM);
+
+        for (;;) {
+            if (waitpid(u->pid, NULL, 0) >= 0)
+                break;
+
+            if (errno != EINTR) {
+                pa_log_error("waitpid() failed: %s", pa_cstrerror(errno));
+                break;
+            }
+        }
+    }
+
+    if (u->io_event)
+        m->core->mainloop->io_free(u->io_event);
+
+    if (u->fd >= 0)
+        pa_close(u->fd);
+
+    pa_xfree(u);
+}
diff --git a/src/vconf/vconf-helper.c b/src/vconf/vconf-helper.c
new file mode 100644 (file)
index 0000000..f7f8f41
--- /dev/null
@@ -0,0 +1,112 @@
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2016 KimJeongYeon <jeongyeon.kim@samsung.com>
+
+    Based on gconf-helper.c
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as published
+  by the Free Software Foundation; either version 2.1 of the License,
+  or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <vconf.h>
+#include <glib.h>
+
+#include "hook-data.h"
+
+#define VCONF_PATH_MAX    128
+
+static void vconf_callback(keynode_t *key, void *data) {
+    char buf[VCONF_PATH_MAX] = {0,};
+    struct vconf_item *vitem = (struct vconf_item *)data;
+    int idx;
+
+    if (!vitem)
+        return;
+
+    idx = vitem->prefix;
+
+    if (!strncmp(vconf_keynode_get_name(key), vconf_prefix[idx], strlen(vconf_prefix[idx]))) {
+        snprintf(buf, sizeof(buf), "%c%s", vitem->opcode, vconf_keynode_get_name(key));
+        fprintf(stdout, "%s%c", buf, 0);  /* Send opcode + key + '\0'. */
+
+        switch (vconf_keynode_get_type(key)) {
+            case VCONF_TYPE_STRING:
+                snprintf(buf, sizeof(buf), "%s", vconf_keynode_get_str(key));
+                break;
+            case VCONF_TYPE_INT:
+                snprintf(buf, sizeof(buf), "%d", vconf_keynode_get_int(key));
+                break;
+            case VCONF_TYPE_DOUBLE:
+                snprintf(buf, sizeof(buf), "%f",  vconf_keynode_get_dbl(key));
+                break;
+            case VCONF_TYPE_BOOL:
+                snprintf(buf, sizeof(buf), "%d",  vconf_keynode_get_bool(key));
+                break;
+            default:
+                buf[0] = 0;
+                break;
+        }
+        fprintf(stdout, "%s%c", buf, 0);  /* Send value  + '\0'. */
+    }
+
+    fflush(stdout);
+}
+
+int main(int argc, char *argv[]) {
+    GMainLoop *g;
+    char vitem_key[VCONF_PATH_MAX] = {0,};
+    int i, idx;
+
+#if !defined(GLIB_VERSION_2_36)
+    g_type_init();
+#endif
+
+    /* Register vconf changing handler */
+    for (i = 0; i < sizeof(vitems) / sizeof(vitems[0]); i++) {
+        if (vitems[i].is_notify) {
+            idx = vitems[i].prefix;
+            snprintf(vitem_key, sizeof(vitem_key), "%s%s", vconf_prefix[idx], vitems[i].name);
+            vconf_notify_key_changed(vitem_key, vconf_callback, &vitems[i]);
+        }
+    }
+
+    /* Signal the parent that we are now initialized */
+    fprintf(stdout, "!");
+    fflush(stdout);
+
+    g = g_main_loop_new(NULL, FALSE);
+    g_main_loop_run(g);
+    g_main_loop_unref(g);
+
+    /* Unregister vconf changing handler */
+    for (i = 0; i < sizeof(vitems) / sizeof(vitems[0]); i++) {
+        if (vitems[i].is_notify) {
+            idx = vitems[i].prefix;
+            snprintf(vitem_key, sizeof(vitem_key), "%s%s", vconf_prefix[idx], vitems[i].name);
+            vconf_ignore_key_changed(vitem_key, vconf_callback);
+        }
+    }
+
+    return 0;
+}