Modification for routing path properly(voice call support) 13/54413/12 accepted/tizen_tv accepted/tizen_wearable accepted/tizen/mobile/20160111.230310 accepted/tizen/mobile/20160111.230423 accepted/tizen/tv/20160111.230345 accepted/tizen/tv/20160111.230435 accepted/tizen/wearable/20160111.230402 accepted/tizen/wearable/20160111.230440 submit/tizen/20160111.114534 submit/tizen/20160111.115046 submit/tizen_common/20160218.142243
authorSangchul Lee <sc11.lee@samsung.com>
Tue, 15 Dec 2015 06:47:17 +0000 (15:47 +0900)
committerSangchul Lee <sc11.lee@samsung.com>
Fri, 8 Jan 2016 07:38:42 +0000 (16:38 +0900)
Change verb name.
Remove unused verb and modifiers.
Add tizen-audio-modem.c for IPC with modem.
Add audio_set_message_cb() API for message forwading to pulseaudio.
Support for voice call.

[Version] 0.1.3
[Profile] Mobile
[Issue Type] Feature Enhancement and Bug Fix

Change-Id: I33bb31bbece9d26a781b342038b45db3cf846585
Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
12 files changed:
Makefile.am
configure.ac
packaging/audio-hal-sc7727.spec
tizen-audio-comm.c [new file with mode: 0644]
tizen-audio-device.c
tizen-audio-internal.h
tizen-audio-modem.c [new file with mode: 0644]
tizen-audio-ucm.c
tizen-audio-util.c
tizen-audio.c
tizen-audio.h
vb_control_parameters.h [new file with mode: 0644]

index 1145f10..87e669b 100644 (file)
@@ -4,14 +4,14 @@ libtizen_audio_la_SOURCES = tizen-audio.c \
                tizen-audio-device.c \
                tizen-audio-volume.c \
                tizen-audio-ucm.c \
+               tizen-audio-modem.c \
+               tizen-audio-comm.c \
                tizen-audio-util.c
 libtizen_audio_la_LDFLAGS = $(AM_LDFLAGS) -disable-static -avoid-version
+libtizen_audio_la_LIBADD = $(AM_LDADD) $(ASOUNDLIB_LIBS) $(VCONF_LIBS) $(DLOG_LIBS) $(INIPARSER_LIBS) $(EXPAT_LIBS)
+libtizen_audio_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) $(VCONF_CFLAGS) $(DLOG_CFLAGS) $(INIPARSER_CFLAGS) $(EXPAT_CFLAGS) -DUSE_DLOG
+
 if USE_TINYALSA
-libtizen_audio_la_LIBADD = $(AM_LDADD) $(ASOUNDLIB_LIBS) $(TINYALSA_LIBS) $(VCONF_LIBS) $(DLOG_LIBS) $(INIPARSER_LIBS)
-libtizen_audio_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) $(TINYALSA_CFLAGS) $(VCONF_CFLAGS) $(DLOG_CFLAGS) $(INIPARSER_CFLAGS) -D__USE_TINYALSA__
-else
-libtizen_audio_la_LIBADD = $(AM_LDADD) $(ASOUNDLIB_LIBS) $(VCONF_LIBS) $(DLOG_LIBS) $(INIPARSER_LIBS)
-libtizen_audio_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) $(VCONF_CFLAGS) $(DLOG_CFLAGS) $(INIPARSER_CFLAGS)
+libtizen_audio_la_LIBADD += $(TINYALSA_LIBS)
+libtizen_audio_la_CFLAGS += $(TINYALSA_CFLAGS) -D__USE_TINYALSA__
 endif
-libtizen_audio_la_CFLAGS += -DUSE_DLOG
-
index 3b0c487..b612ceb 100644 (file)
@@ -47,6 +47,10 @@ PKG_CHECK_MODULES(DLOG, dlog)
 AC_SUBST(DLOG_CFLAGS)
 AC_SUBST(DLOG_LIBS)
 
+PKG_CHECK_MODULES(EXPAT, expat)
+AC_SUBST(EXPAT_CFLAGS)
+AC_SUBST(EXPAT_LIBS)
+
 # Checks for header files.
 
 # Checks for typedefs, structures, and compiler characteristics.
index abc0bd8..73ee9a9 100644 (file)
@@ -1,6 +1,6 @@
 Name:       audio-hal-sc7727
 Summary:    TIZEN Audio HAL for SC7727
-Version:    0.1.2
+Version:    0.1.3
 Release:    0
 Group:      System/Libraries
 License:    Apache-2.0
@@ -11,6 +11,7 @@ BuildRequires: pkgconfig(iniparser)
 BuildRequires: pkgconfig(dlog)
 BuildRequires: pkgconfig(alsa)
 #BuildRequires: pkgconfig(tinyalsa)
+BuildRequires: pkgconfig(expat)
 Provides: libtizen-audio.so
 
 %description
diff --git a/tizen-audio-comm.c b/tizen-audio-comm.c
new file mode 100644 (file)
index 0000000..58b115c
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "tizen-audio-internal.h"
+
+audio_return_t _audio_comm_send_message(audio_hal_t *ah, const char *name, int value)
+{
+    audio_return_t audio_ret = AUDIO_RET_OK;
+
+    AUDIO_LOG_DEBUG("send message : name(%s), value(%d)", name, value);
+    if (ah->comm.msg_cb) {
+        ah->comm.msg_cb(name, value, ah->comm.user_data);
+    }
+
+    return audio_ret;
+}
+
+audio_return_t _audio_comm_init(audio_hal_t *ah)
+{
+    audio_return_t audio_ret = AUDIO_RET_OK;
+
+    AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+    return audio_ret;
+}
+
+audio_return_t _audio_comm_deinit(audio_hal_t *ah)
+{
+    audio_return_t audio_ret = AUDIO_RET_OK;
+
+    AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+    return audio_ret;
+}
index 1190964..e8872ea 100644 (file)
@@ -35,7 +35,6 @@ static device_type_t outDeviceTypes[] = {
     { AUDIO_DEVICE_OUT_RECEIVER, "Earpiece" },
     { AUDIO_DEVICE_OUT_JACK, "Headphones" },
     { AUDIO_DEVICE_OUT_BT_SCO, "Bluetooth" },
-    { AUDIO_DEVICE_OUT_HDMI, "HDMI" },
     { 0, 0 },
 };
 
@@ -47,6 +46,11 @@ static device_type_t inDeviceTypes[] = {
     { 0, 0 },
 };
 
+static int _voice_pcm_open(audio_hal_t *ah);
+static int _voice_pcm_close(audio_hal_t *ah, uint32_t direction);
+static void _reset_pcm_devices(audio_hal_t *ah);
+static void _reset_voice_devices_info(audio_hal_t *ah);
+
 static uint32_t convert_device_string_to_enum(const char* device_str, uint32_t direction)
 {
     uint32_t device = 0;
@@ -59,8 +63,6 @@ static uint32_t convert_device_string_to_enum(const char* device_str, uint32_t d
         device = AUDIO_DEVICE_OUT_JACK;
     } else if ((!strncmp(device_str, "bt", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_OUT)) {
         device = AUDIO_DEVICE_OUT_BT_SCO;
-    } else if (!strncmp(device_str, "hdmi", MAX_NAME_LEN)) {
-        device = AUDIO_DEVICE_OUT_HDMI;
     } else if ((!strncmp(device_str, "builtin-mic", MAX_NAME_LEN))) {
         device = AUDIO_DEVICE_IN_MAIN_MIC;
     /* To Do : SUB_MIC */
@@ -84,6 +86,7 @@ static audio_return_t set_devices(audio_hal_t *ah, const char *verb, device_info
 
     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
     AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
+    AUDIO_RETURN_VAL_IF_FAIL(num_of_devices, AUDIO_ERR_PARAMETER);
 
     if (num_of_devices > MAX_DEVICES) {
         num_of_devices = MAX_DEVICES;
@@ -130,12 +133,10 @@ static audio_return_t set_devices(audio_hal_t *ah, const char *verb, device_info
     }
 
     audio_ret = _audio_ucm_set_devices(ah, verb, active_devices);
-    if (audio_ret) {
+    if (audio_ret)
         AUDIO_LOG_ERROR("Failed to set device: error = %d", audio_ret);
-        return audio_ret;
-    }
-    return audio_ret;
 
+    return audio_ret;
 }
 
 audio_return_t _audio_device_init(audio_hal_t *ah)
@@ -148,6 +149,8 @@ audio_return_t _audio_device_init(audio_hal_t *ah)
     ah->device.pcm_out = NULL;
     ah->device.mode = VERB_NORMAL;
     pthread_mutex_init(&ah->device.pcm_lock, NULL);
+    pthread_mutex_init(&ah->device.device_lock, NULL);
+    pthread_cond_init(&ah->device.device_cond, NULL);
     ah->device.pcm_count = 0;
 
     return AUDIO_RET_OK;
@@ -157,6 +160,9 @@ audio_return_t _audio_device_deinit(audio_hal_t *ah)
 {
     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
 
+    pthread_mutex_destroy(&ah->device.pcm_lock);
+    pthread_mutex_destroy(&ah->device.device_lock);
+    pthread_cond_destroy(&ah->device.device_cond);
     return AUDIO_RET_OK;
 }
 
@@ -165,16 +171,25 @@ static audio_return_t _do_route_ap_playback_capture(audio_hal_t *ah, audio_route
     audio_return_t audio_ret = AUDIO_RET_OK;
     device_info_t *devices = NULL;
     const char *verb = NULL;
+#if 0  /* Disable setting modifiers, because driver does not support it yet */
+    int mod_idx = 0;
+    const char *modifiers[MAX_MODIFIERS] = {NULL,};
+#endif
+
+    if (ah->device.mode != VERB_NORMAL) {
+        if (ah->device.mode == VERB_CALL) {
+            _reset_voice_devices_info(ah);
+            COND_SIGNAL(ah->device.device_cond, "device_cond");
+        }
+        _reset_pcm_devices(ah);
+        ah->device.mode = VERB_NORMAL;
+    }
 
     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
     AUDIO_RETURN_VAL_IF_FAIL(route_info, AUDIO_ERR_PARAMETER);
 
     devices = route_info->device_infos;
 
-    /* To Do: Set modifiers */
-    /* int mod_idx = 0; */
-    /* const char *modifiers[MAX_MODIFIERS] = {NULL,}; */
-
     verb = AUDIO_USE_CASE_VERB_HIFI;
     AUDIO_LOG_INFO("do_route_ap_playback_capture++ ");
 
@@ -185,8 +200,8 @@ static audio_return_t _do_route_ap_playback_capture(audio_hal_t *ah, audio_route
     }
     ah->device.mode = VERB_NORMAL;
 
-    /* To Do: Set modifiers */
-    /*
+#if 0 /* Disable setting modifiers, because driver does not support it yet */
+    /* Set modifiers */
     if (!strncmp("voice_recognition", route_info->role, MAX_NAME_LEN)) {
         modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_VOICESEARCH;
     } else if ((!strncmp("alarm", route_info->role, MAX_NAME_LEN))||(!strncmp("notifiication", route_info->role, MAX_NAME_LEN))) {
@@ -195,9 +210,7 @@ static audio_return_t _do_route_ap_playback_capture(audio_hal_t *ah, audio_route
         else
             modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_MEDIA;
     } else if (!strncmp("ringtone", route_info->role, MAX_NAME_LEN)) {
-        if (ah->device.active_out &= AUDIO_DEVICE_OUT_JACK)
-            modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_DUAL_RINGTONE;
-        else
+        if (ah->device.active_out)
             modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_RINGTONE;
     } else {
         if (ah->device.active_in)
@@ -206,17 +219,19 @@ static audio_return_t _do_route_ap_playback_capture(audio_hal_t *ah, audio_route
             modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_MEDIA;
     }
     audio_ret = _audio_ucm_set_modifiers (ah, verb, modifiers);
-    */
-
+#endif
     return audio_ret;
 }
-audio_return_t _do_route_voicecall(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
+
+static audio_return_t _do_route_voicecall(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
 {
     audio_return_t audio_ret = AUDIO_RET_OK;
-    const char *verb = NULL;
-    verb = AUDIO_USE_CASE_VERB_VOICECALL;
+    const char *verb = AUDIO_USE_CASE_VERB_VOICECALL;
 
     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+    /* if both params are 0, return error for invalid state,
+         * this error would be used to tizen-audio-modem.c */
+    AUDIO_RETURN_VAL_IF_FAIL((devices||num_of_devices), AUDIO_ERR_INVALID_STATE);
     AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
 
     AUDIO_LOG_INFO("do_route_voicecall++");
@@ -226,14 +241,17 @@ audio_return_t _do_route_voicecall(audio_hal_t *ah, device_info_t *devices, int3
         AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
         return audio_ret;
     }
-    /* FIXME. Get network info and configure rate in pcm device */
-    ah->device.mode = VERB_CALL;
-    if (ah->device.active_out && ah->device.active_in)
+
+    if (ah->device.mode != VERB_CALL) {
         _voice_pcm_open(ah);
+        ah->device.mode = VERB_CALL;
+        /* FIXME. Get network info and configure rate in pcm device */
+    }
 
     return audio_ret;
 }
-audio_return_t _do_route_voip(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
+
+static audio_return_t _do_route_voip(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
 {
     audio_return_t audio_ret = AUDIO_RET_OK;
     const char *verb = NULL;
@@ -256,7 +274,7 @@ audio_return_t _do_route_voip(audio_hal_t *ah, device_info_t *devices, int32_t n
     return audio_ret;
 }
 
-audio_return_t _do_route_reset(audio_hal_t *ah, uint32_t direction)
+static audio_return_t _do_route_reset(audio_hal_t *ah, uint32_t direction)
 {
     audio_return_t audio_ret = AUDIO_RET_OK;
 
@@ -266,7 +284,7 @@ audio_return_t _do_route_reset(audio_hal_t *ah, uint32_t direction)
 
     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
 
-    AUDIO_LOG_INFO("do_route_reset++, direction(%p)", direction);
+    AUDIO_LOG_INFO("do_route_reset++, direction(0x%x)", direction);
 
     if (direction == AUDIO_DIRECTION_OUT) {
         ah->device.active_out &= 0x0;
@@ -275,7 +293,12 @@ audio_return_t _do_route_reset(audio_hal_t *ah, uint32_t direction)
     }
     if (ah->device.mode == VERB_CALL) {
         _voice_pcm_close(ah, direction);
+        if (!ah->device.active_in && !ah->device.active_out)
+            ah->device.mode = VERB_NORMAL;
+        _reset_voice_devices_info(ah);
+        COND_SIGNAL(ah->device.device_cond, "device_cond");
     }
+
     /* TO DO: Set Inactive */
     return audio_ret;
 }
@@ -285,6 +308,7 @@ audio_return_t audio_do_route(void *audio_handle, audio_route_info_t *info)
     audio_return_t audio_ret = AUDIO_RET_OK;
     audio_hal_t *ah = (audio_hal_t *)audio_handle;
     device_info_t *devices = NULL;
+    uint32_t prev_size;
 
     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
     AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
@@ -294,9 +318,40 @@ audio_return_t audio_do_route(void *audio_handle, audio_route_info_t *info)
     devices = info->device_infos;
 
     if (!strncmp("call-voice", info->role, MAX_NAME_LEN)) {
-        audio_ret = _do_route_voicecall(ah, devices, info->num_of_devices);
-        if (AUDIO_IS_ERROR(audio_ret)) {
-            AUDIO_LOG_WARN("set voicecall route return 0x%x", audio_ret);
+        if (!ah->modem.is_connected) {
+            if (info->num_of_devices) {
+                if (!ah->device.num_of_call_devices) {
+                    if ((ah->device.init_call_devices = (device_info_t*)calloc(info->num_of_devices, sizeof(device_info_t)))) {
+                        memcpy(ah->device.init_call_devices, devices, info->num_of_devices*sizeof(device_info_t));
+                        ah->device.num_of_call_devices = info->num_of_devices;
+                    } else {
+                        AUDIO_LOG_ERROR("failed to calloc");
+                        audio_ret = AUDIO_ERR_RESOURCE;
+                        goto ERROR;
+                    }
+                } else if (ah->device.num_of_call_devices) {
+                    prev_size = ah->device.num_of_call_devices;
+                    ah->device.num_of_call_devices += info->num_of_devices;
+                    if ((ah->device.init_call_devices = (device_info_t*)realloc(ah->device.init_call_devices, sizeof(device_info_t)*ah->device.num_of_call_devices))) {
+                        memcpy((void*)&(ah->device.init_call_devices[prev_size]), devices, info->num_of_devices*sizeof(device_info_t));
+                    } else {
+                        AUDIO_LOG_ERROR("failed to realloc");
+                        audio_ret = AUDIO_ERR_RESOURCE;
+                        goto ERROR;
+                    }
+                }
+            } else {
+                AUDIO_LOG_ERROR("failed to do route for call-voice, num_of_devices is 0");
+                audio_ret = AUDIO_ERR_PARAMETER;
+                goto ERROR;
+        }
+            AUDIO_LOG_INFO("modem is not ready, skip...");
+        } else {
+            audio_ret = _do_route_voicecall(ah, devices, info->num_of_devices);
+            if (AUDIO_IS_ERROR(audio_ret)) {
+                AUDIO_LOG_WARN("set voicecall route return 0x%x", audio_ret);
+            }
+            COND_SIGNAL(ah->device.device_cond, "device_cond");
         }
     } else if (!strncmp("voip", info->role, MAX_NAME_LEN)) {
         audio_ret = _do_route_voip(ah, devices, info->num_of_devices);
@@ -311,11 +366,12 @@ audio_return_t audio_do_route(void *audio_handle, audio_route_info_t *info)
     } else {
         /* need to prepare for "alarm","notification","emergency","voice-information","voice-recognition","ringtone" */
         audio_ret = _do_route_ap_playback_capture(ah, info);
-
         if (AUDIO_IS_ERROR(audio_ret)) {
             AUDIO_LOG_WARN("set playback route return 0x%x", audio_ret);
         }
     }
+
+ERROR:
     return audio_ret;
 }
 
@@ -374,7 +430,7 @@ static int __voice_pcm_set_params(audio_hal_t *ah, snd_pcm_t *pcm)
         AUDIO_LOG_ERROR("snd_pcm_hw_params_set_access() : failed! - %s\n", snd_strerror(err));
         goto error;
     }
-    err = snd_pcm_hw_params_set_rate(pcm, params, 16000, 0);
+    err = snd_pcm_hw_params_set_rate(pcm, params, 8000, 0);
     if (err < 0) {
         AUDIO_LOG_ERROR("snd_pcm_hw_params_set_rate() : failed! - %s\n", snd_strerror(err));
     }
@@ -407,7 +463,7 @@ error:
     return -1;
 }
 
-int _voice_pcm_open(audio_hal_t *ah)
+static int _voice_pcm_open(audio_hal_t *ah)
 {
     int err, ret = 0;
 
@@ -435,7 +491,7 @@ int _voice_pcm_open(audio_hal_t *ah)
     return ret;
 }
 
-int _voice_pcm_close(audio_hal_t *ah, uint32_t direction)
+static int _voice_pcm_close(audio_hal_t *ah, uint32_t direction)
 {
     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
 
@@ -451,7 +507,39 @@ int _voice_pcm_close(audio_hal_t *ah, uint32_t direction)
         AUDIO_LOG_INFO("voice pcm_in handle close success");
     }
 
-    return 0;
+    return AUDIO_RET_OK;
+}
+
+static void _reset_pcm_devices(audio_hal_t *ah)
+{
+    AUDIO_RETURN_IF_FAIL(ah);
+
+    if (ah->device.pcm_out) {
+        audio_pcm_close((void *)ah, ah->device.pcm_out);
+        ah->device.pcm_out = NULL;
+        AUDIO_LOG_INFO("pcm_out handle close success");
+    }
+    if (ah->device.pcm_in) {
+        audio_pcm_close((void *)ah, ah->device.pcm_in);
+        ah->device.pcm_in = NULL;
+        AUDIO_LOG_INFO("pcm_in handle close success");
+    }
+
+    return;
+}
+
+static void _reset_voice_devices_info(audio_hal_t *ah)
+{
+    AUDIO_RETURN_IF_FAIL(ah);
+
+    AUDIO_LOG_INFO("reset voice device info");
+    if (ah->device.init_call_devices) {
+        free(ah->device.init_call_devices);
+        ah->device.init_call_devices = NULL;
+        ah->device.num_of_call_devices = 0;
+    }
+
+    return;
 }
 
 #ifdef __USE_TINYALSA__
@@ -487,6 +575,11 @@ static struct pcm *__tinyalsa_open_device(audio_pcm_sample_spec_t *ss, size_t pe
 }
 #endif
 
+audio_return_t _audio_do_route_voicecall(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
+{
+    return _do_route_voicecall(ah, devices, num_of_devices);
+}
+
 audio_return_t audio_pcm_open(void *audio_handle, void **pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods)
 {
 #ifdef __USE_TINYALSA__
index 22cd7b0..a0e19e6 100644 (file)
 #ifdef __USE_TINYALSA__
 #include <tinyalsa/asoundlib.h>
 #endif
+#include <time.h>
 #include <pthread.h>
 #include <use-case.h>
 #include "tizen-audio.h"
+#include "vb_control_parameters.h"
 
 /* Debug */
 
     } \
 } while (0)
 
+#define MUTEX_LOCK(x_lock, lock_name) { \
+    AUDIO_LOG_DEBUG("try lock [%s]", lock_name); \
+    pthread_mutex_lock(&(x_lock)); \
+    AUDIO_LOG_DEBUG("after lock [%s]", lock_name); \
+}
+#define MUTEX_UNLOCK(x_lock, lock_name) { \
+    AUDIO_LOG_DEBUG("try unlock [%s]", lock_name); \
+    pthread_mutex_unlock(&(x_lock)); \
+    AUDIO_LOG_DEBUG("after unlock [%s]", lock_name); \
+}
+#define COND_TIMEDWAIT(x_cond, x_lock, x_cond_name, x_timeout_sec) { \
+    AUDIO_LOG_DEBUG("try cond wait [%s]", x_cond_name); \
+    struct timespec ts; \
+    clock_gettime(CLOCK_REALTIME, &ts); \
+    ts.tv_sec += x_timeout_sec; \
+    if (!pthread_cond_timedwait(&(x_cond), &(x_lock), &ts)) \
+        AUDIO_LOG_DEBUG("awaken cond [%s]", x_cond_name); \
+    else \
+        AUDIO_LOG_ERROR("awaken cond [%s] by timeout(%d sec)", x_cond_name, x_timeout_sec); \
+}
+#define COND_SIGNAL(x_cond, x_cond_name) { \
+    AUDIO_LOG_DEBUG("send signal to cond [%s]", x_cond_name); \
+    pthread_cond_signal(&(x_cond)); \
+}
+#define TIMEOUT_SEC 5
+
+/* Signal */
+#define SIGNAL_ROUTING_FOR_VOICE_CALL    "routing_voice_call"
+
 /* Devices : Normal  */
 #define AUDIO_DEVICE_OUT               0x00000000
 #define AUDIO_DEVICE_IN                0x80000000
@@ -86,12 +117,10 @@ enum audio_device_type {
     AUDIO_DEVICE_OUT_RECEIVER         = AUDIO_DEVICE_OUT | 0x00000002,
     AUDIO_DEVICE_OUT_JACK             = AUDIO_DEVICE_OUT | 0x00000004,
     AUDIO_DEVICE_OUT_BT_SCO           = AUDIO_DEVICE_OUT | 0x00000008,
-    AUDIO_DEVICE_OUT_HDMI             = AUDIO_DEVICE_OUT | 0x00000010,
     AUDIO_DEVICE_OUT_ALL              = (AUDIO_DEVICE_OUT_SPEAKER |
                                          AUDIO_DEVICE_OUT_RECEIVER |
                                          AUDIO_DEVICE_OUT_JACK |
-                                         AUDIO_DEVICE_OUT_BT_SCO |
-                                         AUDIO_DEVICE_OUT_HDMI),
+                                         AUDIO_DEVICE_OUT_BT_SCO),
     /* input devices */
     AUDIO_DEVICE_IN_MAIN_MIC          = AUDIO_DEVICE_IN | 0x00000001,
     AUDIO_DEVICE_IN_SUB_MIC           = AUDIO_DEVICE_IN | 0x00000002,
@@ -111,17 +140,14 @@ typedef struct device_type {
 /* Verbs */
 #define AUDIO_USE_CASE_VERB_INACTIVE                "Inactive"
 #define AUDIO_USE_CASE_VERB_HIFI                    "HiFi"
-#define AUDIO_USE_CASE_VERB_VOICECALL               "VoiceCall"
+#define AUDIO_USE_CASE_VERB_VOICECALL               "Voice"
 #define AUDIO_USE_CASE_VERB_LOOPBACK                "Loopback"
-#define AUDIO_USE_CASE_VERB_FMRADIO                 "FM_Radio"
+#define AUDIO_USE_CASE_VERB_VIDEOCALL               "Video"
 
 /* Modifiers */
 #define AUDIO_USE_CASE_MODIFIER_VOICESEARCH              "VoiceSearch"
 #define AUDIO_USE_CASE_MODIFIER_CAMCORDING               "Camcording"
 #define AUDIO_USE_CASE_MODIFIER_RINGTONE                 "Ringtone"
-#define AUDIO_USE_CASE_MODIFIER_DUAL_RINGTONE            "DualRingtone"
-#define AUDIO_USE_CASE_MODIFIER_MEDIA                    "Media"
-#define AUDIO_USE_CASE_MODIFIER_DUAL_MEDIA               "DualMedia"
 
 #define streq !strcmp
 #define strneq strcmp
@@ -193,10 +219,13 @@ typedef struct audio_hal_device {
     snd_pcm_t *pcm_out;
     pthread_mutex_t pcm_lock;
     uint32_t pcm_count;
+    device_info_t *init_call_devices;
+    uint32_t num_of_call_devices;
     audio_route_mode_t mode;
+    pthread_cond_t device_cond;
+    pthread_mutex_t device_lock;
 } audio_hal_device_t;
 
-
 /* Stream */
 #define AUDIO_VOLUME_LEVEL_MAX 16
 
@@ -276,44 +305,70 @@ typedef enum audio_sample_format {
     AUDIO_SAMPLE_INVALID = -1
 } audio_sample_format_t;
 
+typedef struct audio_hal_modem {
+
+    struct {
+        pthread_t voice_thread_handle;
+        pthread_t voip_thread_handle;
+        snd_pcm_t *voice_pcm_handle_p;
+        snd_pcm_t *voice_pcm_handle_c;
+        int exit_vbc_thread;
+        int vbpipe_fd;
+        int vbpipe_voip_fd;
+        unsigned short vbpipe_count;
+    } vbc;
+
+    struct {
+        int fd;
+    } at_cmd;
+
+    audio_modem_t  *cp;
+    cp_type_t cp_type;
+
+    int samplerate;
+    int sim_id;
+    int is_connected;
+} audio_hal_modem_t;
+
+typedef struct audio_hal_comm {
+    message_cb msg_cb;
+    void *user_data;
+} audio_hal_comm_t;
+
 /* Overall */
 typedef struct audio_hal {
     audio_hal_device_t device;
     audio_hal_volume_t volume;
     audio_hal_ucm_t ucm;
     audio_hal_mixer_t mixer;
+    audio_hal_modem_t modem;
+    audio_hal_comm_t comm;
 } audio_hal_t;
 
-typedef struct {
-    unsigned short      is_open; /* if is_open is true, open device; else close device.*/
-    unsigned short      is_headphone;
-    unsigned int        is_downlink_mute;
-    unsigned int        is_uplink_mute;
-} device_ctrl_t;
-
-typedef struct samplerate_ctrl {
-    unsigned int samplerate; /* change samplerate.*/
-} set_samplerate_t;
-
 audio_return_t _audio_volume_init(audio_hal_t *ah);
 audio_return_t _audio_volume_deinit(audio_hal_t *ah);
-
 audio_return_t _audio_device_init(audio_hal_t *ah);
 audio_return_t _audio_device_deinit(audio_hal_t *ah);
 audio_return_t _audio_ucm_init(audio_hal_t *ah);
 audio_return_t _audio_ucm_deinit(audio_hal_t *ah);
+audio_return_t _audio_modem_init(audio_hal_t *ah);
+audio_return_t _audio_modem_deinit(audio_hal_t *ah);
+audio_return_t _audio_comm_init(audio_hal_t *ah);
+audio_return_t _audio_comm_deinit(audio_hal_t *ah);
+audio_return_t _audio_util_init(audio_hal_t *ah);
+audio_return_t _audio_util_deinit(audio_hal_t *ah);
+
+audio_return_t _audio_do_route_voicecall(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices);
 void _audio_ucm_get_device_name(audio_hal_t *ah, const char *use_case, audio_direction_t direction, const char **value);
 #define _audio_ucm_update_use_case _audio_ucm_set_use_case
 audio_return_t _audio_ucm_set_use_case(audio_hal_t *ah, const char *verb, const char *devices[], const char *modifiers[]);
 audio_return_t _audio_ucm_set_devices(audio_hal_t *ah, const char *verb, const char *devices[]);
 audio_return_t _audio_ucm_set_modifiers(audio_hal_t *ah, const char *verb, const char *modifiers[]);
 int _audio_ucm_fill_device_info_list(audio_hal_t *ah, audio_device_info_t *device_info_list, const char *verb);
-int _voice_pcm_open(audio_hal_t *ah);
-int _voice_pcm_close(audio_hal_t *ah, uint32_t direction);
 audio_return_t _audio_ucm_get_verb(audio_hal_t *ah, const char **value);
 audio_return_t _audio_ucm_reset_use_case(audio_hal_t *ah);
-audio_return_t _audio_util_init(audio_hal_t *ah);
-audio_return_t _audio_util_deinit(audio_hal_t *ah);
+int _audio_modem_is_call_connected(audio_hal_t *ah);
+audio_return_t _audio_comm_send_message(audio_hal_t *ah, const char *name, int value);
 audio_return_t _audio_mixer_control_set_param(audio_hal_t *ah, const char* ctl_name, snd_ctl_elem_value_t* value, int size);
 audio_return_t _audio_mixer_control_set_value(audio_hal_t *ah, const char *ctl_name, int val);
 audio_return_t _audio_mixer_control_set_value_string(audio_hal_t *ah, const char* ctl_name, const char* value);
diff --git a/tizen-audio-modem.c b/tizen-audio-modem.c
new file mode 100644 (file)
index 0000000..0154e26
--- /dev/null
@@ -0,0 +1,1034 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <expat.h>
+#include <stdbool.h>
+#include <vconf.h>
+
+#include "tizen-audio-internal.h"
+
+#define vbc_thread_new pthread_create
+#define MIXER_VBC_SWITCH                            "VBC Switch"
+/* pin_switch */
+#define PIN_SWITCH_IIS0_SYS_SEL              "IIS0 pin select"
+#define PIN_SWITCH_IIS0_AP_ID                0
+#define PIN_SWITCH_IIS0_CP0_ID               1
+#define PIN_SWITCH_IIS0_CP1_ID               2
+#define PIN_SWITCH_IIS0_CP2_ID               3
+#define PIN_SWITCH_IIS0_VBC_ID               4
+
+#define PIN_SWITCH_BT_IIS_SYS_SEL            "BT IIS pin select"
+#define PIN_SWITCH_BT_IIS_CP0_IIS0_ID        0
+#define PIN_SWITCH_BT_IIS_CP1_IIS0_ID        4
+#define PIN_SWITCH_BT_IIS_AP_IIS0_ID         8
+
+#define PIN_SWITCH_BT_IIS_CON_SWITCH         "BT IIS con switch"
+
+#define VBC_TD_CHANNELID                            0  /*  cp [3g] */
+#define VBC_ARM_CHANNELID                           2  /*  ap */
+
+#define VBPIPE_DEVICE           "/dev/spipe_w6"
+#define VBPIPE_VOIP_DEVICE      "/dev/spipe_w4"
+#define VBC_CMD_TAG             "VBC"
+
+/* Voice */
+typedef enum {
+    VBC_CMD_NONE = 0,
+    /* current mode and volume gain parameters.*/
+    VBC_CMD_SET_MODE = 1,
+    VBC_CMD_RESP_MODE = 2,
+
+    VBC_CMD_SET_GAIN = 3,
+    VBC_CMD_RESP_GAIN = 4,
+
+    /* whether switch vb control to dsp parameters.*/
+    VBC_CMD_SWITCH_CTRL = 5,
+    VBC_CMD_RESP_SWITCH = 6,
+
+    /* whether mute or not.*/
+    VBC_CMD_SET_MUTE = 7,
+    VBC_CMD_RESP_MUTE = 8,
+
+    /* open/close device parameters.*/
+    VBC_CMD_DEVICE_CTRL = 9,
+    VBC_CMD_RESP_DEVICE = 10,
+
+    VBC_CMD_PCM_OPEN = 11,
+    VBC_CMD_RESP_OPEN  =12,
+
+    VBC_CMD_PCM_CLOSE = 13,
+    VBC_CMD_RESP_CLOSE = 14,
+
+    VBC_CMD_SET_SAMPLERATE = 15,
+    VBC_CMD_RESP_SAMPLERATE = 16,
+
+    VBC_CMD_MAX
+} vbc_command;
+
+const static char* vbc_cmd_str_arry[VBC_CMD_MAX] = {"NONE", "SET_MODE", "RESP_MODE", "SET_GAIN", "RESP_GAIN", "SWITCH_CTL", "RESP_SWITCH",
+"SET_MUTE", "RESP_MUTE", "DEVICE_CTL", "RESP_DEVICE", "PCM_OPEN", "RESP_OPEN", "PCM_CLOSE", "RESP_CLOSE", "SET_SAMPL", "RESP_SAMPL"};
+
+typedef struct {
+    unsigned int  sim_card;   /*sim card number*/
+} open_pcm_t;
+
+typedef struct _vbc_parameters_head {
+    char            tag[4];
+    unsigned int    cmd_type;
+    unsigned int    paras_size;
+} vbc_parameters_head;
+
+typedef struct vbc_control_params {
+    int vbchannel_id;
+    audio_hal_t *ah;
+} vbc_control_params_t;
+
+typedef struct {
+    unsigned short      is_open; /* if is_open is true, open device; else close device.*/
+    unsigned short      is_headphone;
+    unsigned int        is_downlink_mute;
+    unsigned int        is_uplink_mute;
+} device_ctrl_t;
+
+typedef struct samplerate_ctrl {
+    unsigned int samplerate; /* change samplerate.*/
+} set_samplerate_t;
+
+typedef struct {
+    unsigned int  is_switch; /* switch vbc contrl to dsp.*/
+} switch_ctrl_t;
+
+static int __read_nonblock(int fd, void *buf, int bytes)
+{
+    int ret = 0;
+    int bytes_to_read = bytes;
+
+    if ((fd > 0) && (buf != NULL)) {
+        do {
+            ret = read(fd, buf, bytes);
+            if ( ret > 0) {
+                if (ret <= bytes) {
+                    bytes -= ret;
+                }
+            } else if ((!((errno == EAGAIN) || (errno == EINTR))) || (0 == ret)) {
+                break;
+            }
+        } while(bytes);
+    }
+
+    if (bytes == bytes_to_read)
+        return ret ;
+    else
+        return (bytes_to_read - bytes);
+}
+
+static int __write_nonblock(int fd, void *buf, int bytes)
+{
+    int ret = -1;
+    int bytes_to_write = bytes;
+
+    if ((fd > 0) && (buf != NULL)) {
+        do {
+            ret = write(fd, buf, bytes);
+            if ( ret > 0) {
+                if (ret <= bytes) {
+                    bytes -= ret;
+                }
+            } else if ((!((errno == EAGAIN) || (errno == EINTR))) || (0 == ret)) {
+                break;
+            }
+        } while(bytes);
+    }
+
+    if (bytes == bytes_to_write)
+        return ret ;
+    else
+        return (bytes_to_write - bytes);
+
+}
+
+int _audio_modem_is_call_connected(audio_hal_t *ah)
+{
+    int val = -1; /* Mixer values 0 - cp [3g] ,1 - cp [2g] ,2 - ap */
+
+    _audio_mixer_control_get_value(ah, MIXER_VBC_SWITCH, &val);
+    AUDIO_LOG_INFO("modem is connected for call = %d", (val == VBC_TD_CHANNELID));
+
+    return (val == VBC_TD_CHANNELID) ? 1 : 0;
+}
+
+static int __voice_read_samplerate(int fd, set_samplerate_t *paras_ptr)
+{
+    int ret = 0;
+    if (fd > 0 && paras_ptr != NULL) {
+    ret = __read_nonblock(fd, paras_ptr, sizeof(set_samplerate_t));
+        if (ret != sizeof(set_samplerate_t))
+            ret = -1;
+    }
+    AUDIO_LOG_INFO("Return value of read sample rate = %d", ret);
+    return ret;
+
+}
+
+static int __voice_get_samplerate(audio_hal_t *ah, int fd)
+{
+    set_samplerate_t samplerate_paras;
+
+    memset(&samplerate_paras, 0, sizeof(set_samplerate_t));
+    __voice_read_samplerate(fd, &samplerate_paras);
+
+    if (samplerate_paras.samplerate <= 0)
+        ah->modem.samplerate = 8000;
+    else
+        ah->modem.samplerate = samplerate_paras.samplerate;
+
+    return 0;
+}
+
+static int __vbc_write_response(int fd, unsigned int cmd, uint32_t paras_size)
+{
+    int ret = 0;
+    vbc_parameters_head write_head;
+
+    memset(&write_head, 0, sizeof(vbc_parameters_head));
+    memcpy(&write_head.tag[0], VBC_CMD_TAG, 3);
+    write_head.cmd_type = cmd + 1;
+    write_head.paras_size = paras_size;
+
+    ret = __write_nonblock(fd, (void*)&write_head, sizeof(vbc_parameters_head));
+    if (ret < 0)
+        AUDIO_LOG_ERROR("write failed");
+    else
+        AUDIO_LOG_DEBUG("write success for VBC_CMD_[%s]", vbc_cmd_str_arry[cmd]);
+
+    return 0;
+}
+
+#define FM_IIS                                      0x10
+static void i2s_pin_mux_sel(audio_hal_t *ah, int type)
+{
+    audio_return_t ret = AUDIO_RET_OK;
+    audio_modem_t *modem;
+
+    if (!ah) {
+        AUDIO_LOG_ERROR("ah is null");
+        return;
+    }
+
+    AUDIO_LOG_INFO("type is %d",type);
+    modem = ah->modem.cp;
+
+    if (type == FM_IIS) {
+        _audio_mixer_control_set_value(ah,
+                    PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_VBC_ID);
+        return;
+    }
+    if (type == 0) {
+       if(ah->device.active_out & AUDIO_DEVICE_OUT_BT_SCO) {
+            if(modem->i2s_bt.is_ext) {
+                if(modem->i2s_bt.is_switch) {
+                    ret = _audio_mixer_control_set_value(ah,
+                            PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_CP0_ID);
+                }
+            } else {
+                if(modem->i2s_bt.is_switch) {
+                    int value = 0;
+                    _audio_mixer_control_get_value (ah, PIN_SWITCH_IIS0_SYS_SEL, &value);
+                    if(value == PIN_SWITCH_IIS0_CP0_ID) {
+                        ret = _audio_mixer_control_set_value(ah,
+                                PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_AP_ID);
+                    }
+                }
+                if(ah->device.active_out & AUDIO_DEVICE_OUT_BT_SCO) {
+                    if(modem->i2s_bt.is_switch) {
+                        ret = _audio_mixer_control_set_value(ah,
+                                PIN_SWITCH_BT_IIS_SYS_SEL, PIN_SWITCH_BT_IIS_CP0_IIS0_ID);
+                    }
+                }
+            }
+        }
+    } else if (type == 1) {
+        if(ah->device.active_out & AUDIO_DEVICE_OUT_BT_SCO) {
+            if(modem->i2s_bt.is_ext) {
+                if(modem->i2s_bt.is_switch) {
+                    ret = _audio_mixer_control_set_value(ah,
+                            PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_CP1_ID);
+                }
+            } else {
+                if(modem->i2s_bt.is_switch) {
+                    int value = 0;
+                    _audio_mixer_control_get_value (ah, PIN_SWITCH_IIS0_SYS_SEL, &value);
+                    if(value == PIN_SWITCH_IIS0_CP1_ID) {
+                        ret = _audio_mixer_control_set_value(ah,
+                                PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_CP2_ID);
+                    }
+                }
+                if(ah->device.active_out & AUDIO_DEVICE_OUT_BT_SCO) {
+                    if(modem->i2s_bt.is_switch) {
+                        ret = _audio_mixer_control_set_value(ah,
+                                PIN_SWITCH_BT_IIS_SYS_SEL, PIN_SWITCH_BT_IIS_CP1_IIS0_ID);
+                    }
+                }
+            }
+        }
+    } else {
+        AUDIO_LOG_ERROR("invalid type");
+        return;
+    }
+    if (ret)
+        AUDIO_LOG_ERROR("error(0x%x)", ret);
+
+    return;
+}
+
+static void *__vbc_control_voice_thread_run(void *args)
+{
+    audio_return_t audio_ret = AUDIO_RET_OK;
+    vbc_parameters_head read_head;
+    vbc_parameters_head write_head;
+    int exit_thread = 0; /* make exit variable global if required to gracefully exit */
+    int vbpipe_fd;
+    vbc_control_params_t *params = (vbc_control_params_t*)args;
+    if (params == NULL) {
+        return (void*)AUDIO_ERR_PARAMETER;
+    }
+    audio_hal_t *ah = params->ah;
+    fd_set fds_read;
+    struct timeval timeout = {5,0};
+
+    memset(&read_head, 0, sizeof(vbc_parameters_head));
+    memset(&write_head, 0, sizeof(vbc_parameters_head));
+
+    memcpy(&write_head.tag[0], VBC_CMD_TAG, 3);
+    write_head.cmd_type = VBC_CMD_NONE;
+    write_head.paras_size = 0;
+
+    AUDIO_LOG_INFO("[voice] vbc control VOICE thread run");
+
+again:
+    /* open vbpipe device for vb parameter interface between ap and cp */
+    vbpipe_fd = open(VBPIPE_DEVICE, O_RDWR);
+    if (vbpipe_fd < 0) {
+        if (errno == EINTR)
+            goto again;
+        AUDIO_LOG_ERROR("[voice] vbpipe open failed: %s", strerror(errno));
+        return (void*)AUDIO_ERR_IOCTL;
+    }
+    ah->modem.vbc.vbpipe_fd = vbpipe_fd;
+
+    if (fcntl(vbpipe_fd, F_SETFL, O_NONBLOCK) < 0) {
+        AUDIO_LOG_DEBUG("[voice] vbpipe_fd(%d) fcntl error.", vbpipe_fd);
+    }
+
+    AUDIO_LOG_INFO("[voice] %s opened. vbc start loop", VBPIPE_DEVICE);
+
+    /* start loop */
+    while (!exit_thread) {
+        int ret;
+        timeout.tv_sec = 10;
+        timeout.tv_usec = 0;
+
+        /* read command received from cp */
+        FD_ZERO(&fds_read);
+        FD_SET(vbpipe_fd, &fds_read);
+
+        ret = select(vbpipe_fd+1, &fds_read, NULL, NULL, &timeout);
+        if (ret < 0) {
+            ALOGE("voice:select error %d", errno);
+
+            continue;
+        }
+
+        ret = __read_nonblock(vbpipe_fd, &read_head, sizeof(vbc_parameters_head));
+        if (ret < 0) {
+
+            continue;
+        }
+
+        AUDIO_LOG_DEBUG("[voice] Received %d bytes. data: %s, cmd_type: %d", ret, read_head.tag, read_head.cmd_type);
+
+        if (!memcmp(&read_head.tag[0], VBC_CMD_TAG, 3)) {
+            switch (read_head.cmd_type) {
+                case VBC_CMD_PCM_OPEN: {
+                    open_pcm_t open_pcm_params;
+                    uint32_t paras_size = ((ah->modem.cp->i2s_bt.is_switch << 8) | (ah->modem.cp->i2s_bt.index << 0)
+                                        | (ah->modem.cp->i2s_extspk.is_switch << 9) | (ah->modem.cp->i2s_extspk.index << 4));
+
+                    AUDIO_LOG_INFO("[voice] Received VBC_CMD_PCM_OPEN");
+
+                    ah->modem.is_connected = 1;
+                    audio_ret = _audio_do_route_voicecall(ah, ah->device.init_call_devices, ah->device.num_of_call_devices);
+                    if (AUDIO_IS_ERROR(audio_ret)) {
+                        AUDIO_LOG_WARN("set voicecall route return 0x%x", audio_ret);
+                        if (audio_ret == AUDIO_ERR_INVALID_STATE) {
+                            /* send signal and wait for the ucm setting,
+                             * it might an incoming call scenario */
+                            _audio_comm_send_message(ah, SIGNAL_ROUTING_FOR_VOICE_CALL, 1);
+                            COND_TIMEDWAIT(ah->device.device_cond, ah->device.device_lock, "device_cond", TIMEOUT_SEC);
+                            MUTEX_UNLOCK(ah->device.device_lock, "device_lock");
+                        }
+                    }
+
+                    memset(&open_pcm_params, 0, sizeof(open_pcm_t));
+                    ret = __read_nonblock(vbpipe_fd, &open_pcm_params, sizeof(open_pcm_t));
+                    if (ret < 0)
+                        AUDIO_LOG_ERROR("read failed");
+                    else
+                        ah->modem.sim_id = open_pcm_params.sim_card;
+
+                    if (ah->device.active_out & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_BT_SCO)) {
+                        if (ah->modem.cp_type == CP_TG)
+                            i2s_pin_mux_sel(ah, 1);
+                        else if(ah->modem.cp_type == CP_W)
+                            i2s_pin_mux_sel(ah, 0);
+                    }
+
+                    AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_PCM_OPEN");
+                    __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_OPEN, paras_size);
+                    break;
+                }
+
+                case VBC_CMD_PCM_CLOSE: {
+                    AUDIO_LOG_INFO("[voice] Received VBC_CMD_PCM_CLOSE");
+
+                    ah->modem.samplerate = 0;
+                    ah->modem.is_connected = 0;
+
+                    /* send signal and wait for the reset ucm */
+                    _audio_comm_send_message(ah, SIGNAL_ROUTING_FOR_VOICE_CALL, 0);
+                    COND_TIMEDWAIT(ah->device.device_cond, ah->device.device_lock, "device_cond", TIMEOUT_SEC);
+                    MUTEX_UNLOCK(ah->device.device_lock, "device_lock");
+
+                    _audio_mixer_control_set_value(ah, MIXER_VBC_SWITCH, VBC_ARM_CHANNELID);
+
+                    AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_PCM_CLOSE");
+                    __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_CLOSE, 0);
+                    break;
+                }
+
+                case VBC_CMD_RESP_CLOSE: {
+                    AUDIO_LOG_INFO("[voice] Received VBC_CMD_RESP_CLOSE & send response");
+                    ret = __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_CLOSE, 0);
+                    break;
+                }
+
+                case VBC_CMD_SET_MODE: {
+                    char dummy[52];
+                    memset(dummy, 0, sizeof(dummy));
+                    AUDIO_LOG_INFO("[voice] Received VBC_CMD_SET_MODE");
+
+                    if (ah->device.active_out & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_BT_SCO)) {
+                        if (ah->modem.cp_type == CP_TG)
+                            i2s_pin_mux_sel(ah, 1);
+                        else if(ah->modem.cp_type == CP_W)
+                            i2s_pin_mux_sel(ah, 0);
+                    }
+                    /* To do: set mode params : __vbc_set_mode_params(ah, vbpipe_fd); */
+
+                    __read_nonblock(vbpipe_fd, dummy, sizeof(dummy));
+                    AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_SET_MODE");
+                    __vbc_write_response(vbpipe_fd, VBC_CMD_SET_MODE, 0);
+                    break;
+                }
+                case VBC_CMD_SET_GAIN: {
+                    AUDIO_LOG_INFO("[voice] Received VBC_CMD_SET_GAIN");
+
+                    /* To do: set gain params : __vbc_set_gain_params(ah, vbpipe_fd); */
+
+                    AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_SET_GAIN");
+                    __vbc_write_response(vbpipe_fd, VBC_CMD_SET_GAIN, 0);
+                    break;
+                }
+                case VBC_CMD_SWITCH_CTRL: {
+                    switch_ctrl_t switch_ctrl_params;
+
+                    AUDIO_LOG_INFO("[voice] Received VBC_CMD_SWITCH_CTRL");
+
+                    memset(&switch_ctrl_params,0,sizeof(switch_ctrl_t));
+                    ret = __read_nonblock(vbpipe_fd, &switch_ctrl_params, sizeof(switch_ctrl_t));
+                    if (ret < 0)
+                        AUDIO_LOG_ERROR("read failed");
+                    else
+                        AUDIO_LOG_INFO("is_switch:%d", switch_ctrl_params.is_switch);
+
+                    _audio_mixer_control_set_value(ah, MIXER_VBC_SWITCH, VBC_TD_CHANNELID);
+
+                    AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_SET_GAIN");
+                    __vbc_write_response(vbpipe_fd, VBC_CMD_SWITCH_CTRL, 0);
+                   break;
+                }
+                case VBC_CMD_SET_MUTE: {
+                    AUDIO_LOG_INFO("[voice] Received VBC_CMD_SET_MUTE");
+                    break;
+                }
+                case VBC_CMD_DEVICE_CTRL: {
+                    char dummy[64];
+                    memset(dummy, 0, sizeof(dummy));
+                    AUDIO_LOG_INFO("[voice] Received VBC_CMD_DEVICE_CTRL");
+
+                    /* To do: set device ctrl params :__vbc_set_device_ctrl_params(ah, vbpipe_fd); */
+                    __read_nonblock(vbpipe_fd, dummy, sizeof(dummy));
+
+                    AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_DEVICE_CTRL");
+                    __vbc_write_response(vbpipe_fd, VBC_CMD_DEVICE_CTRL, 0);
+
+                    break;
+                }
+                case VBC_CMD_SET_SAMPLERATE: {
+                    AUDIO_LOG_INFO("[voice] Received VBC_CMD_SET_SAMPLERATE");
+
+//                    _voice_pcm_close(ah, 0);
+//
+//                    __voice_get_samplerate(ah, vbpipe_fd);
+//
+//                    ret = _voice_pcm_open(ah);
+//                    if (ret < 0) {
+//                        _voice_pcm_close(ah, 1);
+//                        break;
+//                    }
+
+                    AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_SET_SAMPLERATE");
+                    __vbc_write_response(vbpipe_fd, VBC_CMD_SET_SAMPLERATE, 0);
+                    break;
+                }
+                default:
+                    AUDIO_LOG_WARN("[voice] Unknown command received : %d", read_head.cmd_type);
+                    break;
+            }
+        }
+    }
+    if (params)
+        free(params);
+
+    close(vbpipe_fd);
+
+    AUDIO_LOG_INFO("Exit vbc VOICE thread");
+
+    return (void*)0;
+}
+
+static void *__vbc_control_voip_thread_run(void *args)
+{
+    open_pcm_t open_pcm_params;
+    vbc_parameters_head read_head;
+    vbc_parameters_head write_head;
+    int exit_thread = 0; /* make exit variable global if required to gracefully exit */
+    int vbpipe_fd;
+    vbc_control_params_t *params = (vbc_control_params_t*)args;
+    if (params == NULL) {
+        return (void*)AUDIO_ERR_PARAMETER;
+    }
+    audio_hal_t *ah = params->ah;
+    fd_set fds_read;
+
+    struct timeval timeout = {5,0};
+
+    memset(&read_head, 0, sizeof(vbc_parameters_head));
+    memset(&write_head, 0, sizeof(vbc_parameters_head));
+
+    memcpy(&write_head.tag[0], VBC_CMD_TAG, 3);
+    write_head.cmd_type = VBC_CMD_NONE;
+    write_head.paras_size = 0;
+
+    AUDIO_LOG_INFO("[voip] vbc control VOIP thread run");
+
+again:
+    /* open vbpipe device for vb parameter interface between ap and cp */
+    vbpipe_fd = open(VBPIPE_VOIP_DEVICE, O_RDWR);
+    if (vbpipe_fd < 0) {
+        if (errno == EINTR)
+            goto again;
+        AUDIO_LOG_ERROR("[voip] vbpipe open failed: %s", strerror(errno));
+        return (void*)0;
+    }
+    ah->modem.vbc.vbpipe_voip_fd = vbpipe_fd;
+
+    if (fcntl(vbpipe_fd, F_SETFL, O_NONBLOCK) < 0) {
+        AUDIO_LOG_DEBUG("[voip] vbpipe_fd(%d) fcntl error.", vbpipe_fd);
+    }
+
+    AUDIO_LOG_INFO("[voip] %s opened. vbc start loop", VBPIPE_VOIP_DEVICE);
+
+    /* start loop */
+    while (!exit_thread) {
+        int ret;
+        timeout.tv_sec = 5;;
+        timeout.tv_usec = 0;
+
+        /* read command received from cp */
+
+        FD_ZERO(&fds_read);
+        FD_SET(vbpipe_fd, &fds_read);
+
+        ret = select(vbpipe_fd+1, &fds_read, NULL, NULL, &timeout);
+        if (ret < 0) {
+            ALOGE("[voip] select error %d", errno);
+            continue;
+        }
+
+        ret = __read_nonblock(vbpipe_fd, &read_head, sizeof(vbc_parameters_head));
+        if (ret < 0) {
+            continue;
+        }
+
+        AUDIO_LOG_DEBUG("[voip] Received %d bytes. data: %s, cmd_type: %d", ret, read_head.tag, read_head.cmd_type);
+
+        if (!memcmp(&read_head.tag[0], VBC_CMD_TAG, 3)) {
+            switch (read_head.cmd_type) {
+                case VBC_CMD_PCM_OPEN: {
+                    uint32_t paras_size = ((ah->modem.cp->i2s_bt.is_switch << 8) | (ah->modem.cp->i2s_bt.index << 0)
+                                        | (ah->modem.cp->i2s_extspk.is_switch << 9) | (ah->modem.cp->i2s_extspk.index << 4));
+
+                    AUDIO_LOG_INFO("[voip] Received VBC_CMD_PCM_OPEN");
+
+                    memset(&open_pcm_params, 0, sizeof(open_pcm_t));
+                    ret = __read_nonblock(vbpipe_fd, &open_pcm_params, sizeof(open_pcm_t));
+                    if (ret < 0)
+                        AUDIO_LOG_ERROR("read failed");
+
+                    AUDIO_LOG_DEBUG("[voip] Send response for VBC_CMD_PCM_OPEN");
+                    __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_OPEN, paras_size);
+                    break;
+                }
+                case VBC_CMD_PCM_CLOSE: {
+                    AUDIO_LOG_INFO("[voip] Received VBC_CMD_PCM_CLOSE & send response");
+
+                    __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_CLOSE, 0);
+
+                    break;
+                }
+                case VBC_CMD_RESP_CLOSE: {
+                    AUDIO_LOG_INFO("[voip] Received VBC_CMD_RESP_CLOSE & send response");
+
+                    ret = __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_CLOSE, 0);
+                    break;
+                }
+                case VBC_CMD_SET_MODE: {
+                    AUDIO_LOG_INFO("[voip] Received VBC_CMD_SET_MODE");
+
+                    if (ah->device.active_out & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_BT_SCO)) {
+                        if (ah->modem.cp_type == CP_TG)
+                            i2s_pin_mux_sel(ah, 1);
+                        else if(ah->modem.cp_type == CP_W)
+                            i2s_pin_mux_sel(ah, 0);
+                    }
+                    /* To do: set mode params : __vbc_set_mode_params(ah, vbpipe_fd); */
+                    AUDIO_LOG_DEBUG("[voip] Send response for VBC_CMD_SET_MODE");
+                    __vbc_write_response(vbpipe_fd, VBC_CMD_SET_MODE, 0);
+                    break;
+                }
+                case VBC_CMD_SET_GAIN: {
+                    AUDIO_LOG_INFO("[voip] Received VBC_CMD_SET_GAIN");
+
+                    /* To do: set gain params : __vbc_set_gain_params(ah, vbpipe_fd); */
+                    AUDIO_LOG_DEBUG("[voip] Send response for VBC_CMD_SET_GAIN");
+                    __vbc_write_response(vbpipe_fd, VBC_CMD_SET_GAIN, 0);
+                    break;
+                }
+                case VBC_CMD_SWITCH_CTRL: {
+                    switch_ctrl_t switch_ctrl_params;
+
+                    AUDIO_LOG_INFO("[voip] Received VBC_CMD_SWITCH_CTRL");
+
+                    memset(&switch_ctrl_params, 0, sizeof(switch_ctrl_t));
+                    ret = __read_nonblock(vbpipe_fd, &switch_ctrl_params, sizeof(switch_ctrl_t));
+                    if (ret < 0)
+                        AUDIO_LOG_ERROR("read failed");
+                    else
+                        AUDIO_LOG_INFO("is_switch:%d", switch_ctrl_params.is_switch);
+
+                    _audio_mixer_control_set_value(ah, MIXER_VBC_SWITCH, VBC_TD_CHANNELID);
+
+                    AUDIO_LOG_DEBUG("[voip] Send response for VBC_CMD_SWITCH_CTRL");
+                    __vbc_write_response(vbpipe_fd, VBC_CMD_SWITCH_CTRL, 0);
+                    break;
+                }
+                case VBC_CMD_SET_MUTE: {
+                    AUDIO_LOG_INFO("[voip] Received VBC_CMD_SET_MUTE & send response");
+                    __vbc_write_response(vbpipe_fd, VBC_CMD_SET_MUTE, 0);
+                    break;
+                }
+                case VBC_CMD_DEVICE_CTRL: {
+                    AUDIO_LOG_INFO("[voip] Received VBC_CMD_DEVICE_CTRL");
+                    __vbc_write_response(vbpipe_fd, VBC_CMD_DEVICE_CTRL, 0);
+                    break;
+                }
+                case VBC_CMD_SET_SAMPLERATE: {
+                    AUDIO_LOG_INFO("[voip] Received VBC_CMD_SET_SAMPLERATE");
+
+//                    _voice_pcm_close(ah, 0);
+//                    __voice_get_samplerate(ah, vbpipe_fd);
+//
+//                    ret = _voice_pcm_open(ah);
+//                    if (ret < 0) {
+//                        _voice_pcm_close(ah, 1);
+//                        break;
+//                    }
+                    AUDIO_LOG_DEBUG("[voip] Send response for VBC_CMD_SET_SAMPLERATE");
+                    __vbc_write_response(vbpipe_fd, VBC_CMD_SET_SAMPLERATE, 0);
+                    break;
+                }
+                default:
+                    AUDIO_LOG_WARN("Unknown command received : %d", read_head.cmd_type);
+                    break;
+            }
+        }
+    }
+    close(vbpipe_fd);
+    if (params)
+        free(params);
+
+    AUDIO_LOG_INFO("Exit vbc VOIP thread");
+
+    return (void*)0;
+}
+
+static audio_return_t __vbc_control_open(audio_hal_t *ah)
+{
+    vbc_control_params_t *params = (vbc_control_params_t*)malloc(sizeof(vbc_control_params_t));
+    audio_return_t ret = AUDIO_RET_OK;
+    audio_return_t ret2 = AUDIO_RET_OK;
+
+    if (params == NULL) {
+         AUDIO_LOG_ERROR("vbc control param allocation failed");
+         return AUDIO_ERR_RESOURCE;
+    }
+
+    params->ah = ah;
+    AUDIO_LOG_INFO("vbc control thread create");
+    ret = vbc_thread_new(&ah->modem.vbc.voice_thread_handle, NULL, __vbc_control_voice_thread_run, (void*)params);
+    if (ret < 0) {
+        AUDIO_LOG_ERROR("vbc control thread create failed");
+        ret = AUDIO_ERR_RESOURCE;
+        return ret;
+    }
+
+    ret2 = vbc_thread_new(&ah->modem.vbc.voip_thread_handle, NULL, __vbc_control_voip_thread_run, (void*)params);
+    if (ret2 < 0) {
+        AUDIO_LOG_ERROR("vbc control VOIP thread create failed");
+        ret2 = AUDIO_ERR_RESOURCE;
+        return ret2;
+    }
+
+    return AUDIO_RET_OK;
+}
+
+static audio_return_t __vbc_control_close(audio_hal_t *ah)
+{
+    /* TODO. Make sure we always receive CLOSE command from modem and then close pcm device */
+    ah->modem.vbc.exit_vbc_thread = 1;
+    close(ah->modem.vbc.vbpipe_fd);
+
+    pthread_cancel(ah->modem.vbc.voice_thread_handle);
+    pthread_cancel(ah->modem.vbc.voip_thread_handle);
+
+    return AUDIO_RET_OK;
+}
+
+static vbc_ctrl_pipe_para_t *__audio_modem_create(audio_modem_t  *modem, const char *num)
+{
+    if (!atoi((char *)num)) {
+        AUDIO_LOG_ERROR("Unnormal modem num!");
+        return NULL;
+    }
+
+    modem->num = atoi((char *)num);
+    /* check if we need to allocate  space for modem profile */
+    if(!modem->vbc_ctrl_pipe_info) {
+        modem->vbc_ctrl_pipe_info = malloc(modem->num * sizeof(vbc_ctrl_pipe_para_t));
+
+        if (modem->vbc_ctrl_pipe_info == NULL) {
+            AUDIO_LOG_ERROR("Unable to allocate modem profiles");
+            return NULL;
+        } else {
+            /* initialise the new profile */
+            memset((void*)modem->vbc_ctrl_pipe_info, 0x00, modem->num * sizeof(vbc_ctrl_pipe_para_t));
+        }
+    }
+
+    AUDIO_LOG_DEBUG("peter: modem num is %d",modem->num);
+    /* return the profile just added */
+    return modem->vbc_ctrl_pipe_info;
+}
+
+
+static void __audio_modem_start_tag(void *data, const XML_Char *tag_name,
+        const XML_Char **attr)
+{
+    struct modem_config_parse_state *state = data;
+    audio_modem_t *modem = state->modem_info;
+
+    /* Look at tags */
+    if (strcmp(tag_name, "audio") == 0) {
+        if (strcmp(attr[0], "device") == 0) {
+            AUDIO_LOG_INFO("The device name is %s", attr[1]);
+        } else {
+            AUDIO_LOG_ERROR("Unnamed audio!");
+        }
+    } else if (strcmp(tag_name, "modem") == 0) {
+        /* Obtain the modem num */
+        if (strcmp(attr[0], "num") == 0) {
+            AUDIO_LOG_DEBUG("The modem num is '%s'", attr[1]);
+            state->vbc_ctrl_pipe_info = __audio_modem_create(modem, attr[1]);
+        } else {
+            AUDIO_LOG_ERROR("no modem num!");
+        }
+    } else if (strcmp(tag_name, "cp") == 0) {
+        if (state->vbc_ctrl_pipe_info) {
+            /* Obtain the modem name  \pipe\vbc   filed */
+            if (strcmp(attr[0], "name") != 0) {
+                AUDIO_LOG_ERROR("Unnamed modem!");
+                goto attr_err;
+            }
+            if (strcmp(attr[2], "pipe") != 0) {
+                AUDIO_LOG_ERROR("'%s' No pipe filed!", attr[0]);
+                goto attr_err;
+            }
+            if (strcmp(attr[4], "vbchannel") != 0) {
+                AUDIO_LOG_ERROR("'%s' No vbc filed!", attr[0]);
+                goto attr_err;
+            }
+            AUDIO_LOG_DEBUG("cp name is '%s', pipe is '%s',vbc is '%s'", attr[1], attr[3],attr[5]);
+            if(strcmp(attr[1], "w") == 0)
+            {
+                state->vbc_ctrl_pipe_info->cp_type = CP_W;
+            }
+            else if(strcmp(attr[1], "t") == 0)
+            {
+                state->vbc_ctrl_pipe_info->cp_type = CP_TG;
+            }
+            memcpy((void*)state->vbc_ctrl_pipe_info->s_vbc_ctrl_pipe_name,(void*)attr[3],strlen((char *)attr[3]));
+            state->vbc_ctrl_pipe_info->channel_id = atoi((char *)attr[5]);
+            state->vbc_ctrl_pipe_info++;
+
+        } else {
+            AUDIO_LOG_ERROR("error profile!");
+        }
+    } else if (strcmp(tag_name, "i2s_for_btcall") == 0) {
+        if (strcmp(attr[0], "index") == 0) {
+            AUDIO_LOG_DEBUG("The iis_for_btcall index is '%s'", attr[1]);
+            modem->i2s_bt.index = atoi((char *)attr[1]);
+        } else {
+            AUDIO_LOG_ERROR("no iis_ctl index for bt call!");
+        }
+
+        if (strcmp(attr[2], "switch") == 0) {
+            AUDIO_LOG_DEBUG("The iis_for_btcall switch is '%s'", attr[3]);
+            if(strcmp(attr[3],"1") == 0)
+                modem->i2s_bt.is_switch = true;
+            else if(strcmp(attr[3],"0") == 0)
+                modem->i2s_bt.is_switch = false;
+        } else {
+            AUDIO_LOG_ERROR("no iis_ctl switch for bt call!");
+        }
+        if (strcmp(attr[4], "dst") == 0) {
+            AUDIO_LOG_DEBUG("The iis_for_btcall dst  is '%s'", attr[5]);
+            if (strcmp(attr[5], "internal") == 0)
+                modem->i2s_bt.is_ext = 0;
+            else if (strcmp(attr[5], "external") == 0)
+                modem->i2s_bt.is_ext = 1;
+        } else {
+            AUDIO_LOG_ERROR("no dst path for bt call!");
+        }
+    } else if (strcmp(tag_name, "i2s_for_extspeaker") == 0) {
+        if (strcmp(attr[0], "index") == 0) {
+            AUDIO_LOG_DEBUG("The i2s_for_extspeaker index is '%s'", attr[1]);
+            modem->i2s_extspk.index = atoi((char *)attr[1]);
+        } else {
+            AUDIO_LOG_ERROR("no iis_ctl index for extspk call!");
+        }
+        if (strcmp(attr[2], "switch") == 0) {
+            AUDIO_LOG_DEBUG("The iis_for_btcall switch is '%s'", attr[3]);
+            if(strcmp(attr[3],"1") == 0)
+                modem->i2s_extspk.is_switch = true;
+            else if(strcmp(attr[3],"0") == 0)
+                modem->i2s_extspk.is_switch = false;
+        } else {
+            AUDIO_LOG_ERROR("no iis_ctl switch for extspk call!");
+        }
+        if (strcmp(attr[4], "dst") == 0) {
+            if (strcmp(attr[5], "external") == 0)
+                modem->i2s_extspk.is_ext = 1;
+            else if(strcmp(attr[5], "internal") == 0)
+                modem->i2s_extspk.is_ext = 0;
+
+            AUDIO_LOG_DEBUG("The i2s_for_extspeaker dst  is '%d'", modem->i2s_extspk.is_ext);
+
+        } else {
+            AUDIO_LOG_ERROR("no dst path for bt call!");
+        }
+    } else if (strcmp(tag_name, "debug") == 0) {  //parse debug info
+        if (strcmp(attr[0], "enable") == 0) {
+            if (strcmp(attr[1], "0") == 0) {
+                modem->debug_info.enable = 0;
+            } else {
+                modem->debug_info.enable = 1;
+            }
+        } else {
+            AUDIO_LOG_ERROR("no adaptable type for debug!");
+            goto attr_err;
+        }
+    } else if (strcmp(tag_name, "debuginfo") == 0) { //parse debug info
+        if (strcmp(attr[0], "sleepdeltatimegate") == 0) {
+            AUDIO_LOG_DEBUG("The sleepdeltatimegate is  '%s'", attr[1]);
+            modem->debug_info.sleeptime_gate=atoi((char *)attr[1]);
+        } else if (strcmp(attr[0], "pcmwritetimegate") == 0) {
+            AUDIO_LOG_DEBUG("The pcmwritetimegate is  '%s'", attr[1]);
+            modem->debug_info.pcmwritetime_gate=atoi((char *)attr[1]);
+        } else if (strcmp(attr[0], "lastthiswritetimegate") == 0) {
+            AUDIO_LOG_DEBUG("The lastthiswritetimegate is  '%s'", attr[1]);
+            modem->debug_info.lastthis_outwritetime_gate=atoi((char *)attr[1]);
+        } else {
+            AUDIO_LOG_ERROR("no adaptable info for debuginfo!");
+            goto attr_err;
+        }
+   }
+
+attr_err:
+    return;
+}
+static void __audio_modem_end_tag(void *data, const XML_Char *tag_name)
+{
+    return;
+}
+
+struct config_parse_state {
+    audio_modem_t *modem_info;
+ /* To do : pga control setting*/
+ /* struct audio_pga *pga; */
+ /* struct pga_profile *profile; */
+ /* struct pga_attribute_item *attribute_item; */
+};
+static audio_modem_t * __audio_modem_parse (void)
+{
+    struct config_parse_state state;
+    XML_Parser parser;
+    FILE *file;
+    int bytes_read;
+    void *buf;
+    audio_modem_t *modem = NULL;
+
+    modem = calloc(1, sizeof(audio_modem_t));
+
+    if(modem == NULL) {
+        goto err_alloc;
+    }
+    memset(modem, 0, sizeof(audio_modem_t));
+    modem->num = 0;
+    modem->vbc_ctrl_pipe_info = NULL;
+
+    file = fopen(AUDIO_XML_PATH, "r");
+    if (!file) {
+        AUDIO_LOG_ERROR("Failed to open %s", AUDIO_XML_PATH);
+        goto err_fopen;
+    }
+
+    parser = XML_ParserCreate(NULL);
+    if (!parser) {
+        AUDIO_LOG_ERROR("Failed to create XML parser");
+        goto err_parser_create;
+    }
+
+    memset(&state, 0, sizeof(state));
+    state.modem_info = modem;
+    XML_SetUserData(parser, &state);
+    XML_SetElementHandler(parser, __audio_modem_start_tag, __audio_modem_end_tag);
+
+    for (;;) {
+        buf = XML_GetBuffer(parser, BUF_SIZE);
+        if (buf == NULL)
+            goto err_parse;
+
+        bytes_read = fread(buf, 1, BUF_SIZE, file);
+        if (bytes_read < 0)
+            goto err_parse;
+
+        if (XML_ParseBuffer(parser, bytes_read, bytes_read == 0) == XML_STATUS_ERROR) {
+            AUDIO_LOG_ERROR("Error in codec PGA xml (%s)", AUDIO_XML_PATH);
+            goto err_parse;
+        }
+
+        if (bytes_read == 0)
+            break;
+    }
+    XML_ParserFree(parser);
+    fclose(file);
+    return modem;
+
+err_parse:
+    XML_ParserFree(parser);
+err_parser_create:
+    fclose(file);
+err_fopen:
+    free(modem);
+err_alloc:
+    modem = NULL;
+    return NULL;
+}
+
+audio_return_t _audio_modem_init(audio_hal_t *ah)
+{
+    audio_return_t audio_ret = AUDIO_RET_OK;
+
+    AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+    ah->modem.vbc.vbpipe_count = 0;
+
+    /* Initialize vbc interface */
+    audio_ret = __vbc_control_open(ah);
+    if (AUDIO_IS_ERROR(audio_ret)) {
+        AUDIO_LOG_ERROR("__vbc_control_open failed");
+        goto exit;
+    }
+    ah->modem.vbc.voice_pcm_handle_p = NULL;
+    ah->modem.vbc.voice_pcm_handle_c = NULL;
+    ah->modem.samplerate = 0;
+    ah->modem.cp = __audio_modem_parse();
+    if (ah->modem.cp == NULL) {
+        AUDIO_LOG_ERROR("modem parse failed");
+        goto exit;
+    }
+    ah->modem.cp_type = ah->modem.cp->vbc_ctrl_pipe_info->cp_type;
+
+    /* This ctrl need to be set "0" always - SPRD */
+    _audio_mixer_control_set_value(ah, PIN_SWITCH_BT_IIS_CON_SWITCH, 0);
+
+exit:
+    return audio_ret;
+}
+
+audio_return_t _audio_modem_deinit(audio_hal_t *ah)
+{
+    AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+    /* Close vbc interface */
+    __vbc_control_close(ah);
+
+    return AUDIO_RET_OK;
+}
+
index 7161539..e1dba8f 100644 (file)
@@ -128,9 +128,11 @@ int _audio_ucm_fill_device_info_list(audio_hal_t *ah, audio_device_info_t *devic
         if (strncmp(verb, AUDIO_USE_CASE_VERB_VOICECALL, strlen(AUDIO_USE_CASE_VERB_VOICECALL)) &&
             strncmp(verb, AUDIO_USE_CASE_VERB_LOOPBACK, strlen(AUDIO_USE_CASE_VERB_LOOPBACK))) {
             __add_ucm_device_info(ah, verb, AUDIO_DIRECTION_IN, device_info_list, &device_info_count);
+#if 0 /* disable temporarily */
             if (strncmp(verb, AUDIO_USE_CASE_VERB_FMRADIO, strlen(AUDIO_USE_CASE_VERB_FMRADIO))) {
                 __add_ucm_device_info(ah, verb, AUDIO_DIRECTION_OUT, device_info_list, &device_info_count);
             }
+#endif
         }
 
         if (curr_verb)
@@ -515,7 +517,7 @@ audio_return_t _audio_ucm_set_devices(audio_hal_t *ah, const char *verb, const c
     } else {
         is_verb_changed = 1;
 
-        AUDIO_LOG_DEBUG("Setting new verb: %s", verb);
+        AUDIO_LOG_INFO("Setting new verb: %s", verb);
         /* set new verb */
         if (snd_use_case_set(ah->ucm.uc_mgr, "_verb", verb) < 0) {
             AUDIO_LOG_ERROR("Setting verb %s failed", verb);
@@ -524,7 +526,7 @@ audio_return_t _audio_ucm_set_devices(audio_hal_t *ah, const char *verb, const c
         }
         /* enable devices */
         for (i = 0; i < dev_count; i++) {
-            AUDIO_LOG_DEBUG("Enable device : %s", devices[i]);
+            AUDIO_LOG_INFO("Enable device : %s", devices[i]);
             if (snd_use_case_set(ah->ucm.uc_mgr, "_enadev", devices[i]) < 0)
                 AUDIO_LOG_ERROR("Enable %s device failed", devices[i]);
         }
index 4e06923..20b79eb 100644 (file)
@@ -73,16 +73,6 @@ audio_return_t _audio_mixer_control_set_param(audio_hal_t *ah, const char* ctl_n
     return AUDIO_RET_OK;
 }
 
-audio_return_t audio_mixer_control_get_value(audio_hal_t *ah, const char *ctl_name, int *val)
-{
-    audio_return_t audio_ret = AUDIO_RET_OK;
-
-    AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
-
-    audio_ret = _audio_mixer_control_get_value(ah, ctl_name, val);
-    return audio_ret;
-}
-
 audio_return_t _audio_mixer_control_get_value(audio_hal_t *ah, const char *ctl_name, int *val)
 {
     snd_ctl_t *handle;
@@ -170,8 +160,6 @@ audio_return_t _audio_mixer_control_set_value(audio_hal_t *ah, const char *ctl_n
     snd_ctl_elem_id_t *id;
     snd_ctl_elem_info_t *info;
     snd_ctl_elem_type_t type;
-
-    char *card_name = NULL;
     int ret = 0, count = 0, i = 0;
 
     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
@@ -181,7 +169,7 @@ audio_return_t _audio_mixer_control_set_value(audio_hal_t *ah, const char *ctl_n
 
     ret = snd_ctl_open(&handle, ALSA_DEFAULT_CARD, 0);
     if (ret < 0) {
-        AUDIO_LOG_ERROR("snd_ctl_open error, card: %s: %s", card_name, snd_strerror(ret));
+        AUDIO_LOG_ERROR("snd_ctl_open error, card: %s: %s", ALSA_DEFAULT_CARD, snd_strerror(ret));
         pthread_mutex_unlock(&(ah->mixer.mutex));
         return AUDIO_ERR_IOCTL;
     }
index 882a9b4..a37a7ab 100644 (file)
@@ -29,6 +29,23 @@ static const char* AUDIO_LATENCY_MID  = "mid";
 static const char* AUDIO_LATENCY_HIGH = "high";
 static const char* AUDIO_LATENCY_VOIP = "voip";
 
+audio_return_t audio_set_message_cb(void *audio_handle, message_cb callback, void *user_data)
+{
+    audio_hal_t *ah;
+    audio_return_t ret = AUDIO_RET_OK;
+
+    AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+    AUDIO_RETURN_VAL_IF_FAIL(callback, AUDIO_ERR_PARAMETER);
+
+    ah = (audio_hal_t *)audio_handle;
+    ah->comm.msg_cb = callback;
+    ah->comm.user_data = user_data;
+
+    AUDIO_LOG_DEBUG("message callback is set, callback(%p), user_data(%p)", ah->comm.msg_cb, ah->comm.user_data);
+
+    return ret;
+}
+
 audio_return_t audio_init(void **audio_handle)
 {
     audio_hal_t *ah;
@@ -56,6 +73,14 @@ audio_return_t audio_init(void **audio_handle)
         AUDIO_LOG_ERROR("mixer init failed");
         goto error_exit;
     }
+    if (AUDIO_IS_ERROR((ret = _audio_modem_init(ah)))) {
+        AUDIO_LOG_ERROR("modem init failed");
+        goto error_exit;
+    }
+    if (AUDIO_IS_ERROR((ret = _audio_comm_init(ah)))) {
+        AUDIO_LOG_ERROR("comm init failed");
+        goto error_exit;
+    }
 
     *audio_handle = (void *)ah;
     return AUDIO_RET_OK;
@@ -77,6 +102,8 @@ audio_return_t audio_deinit(void *audio_handle)
     _audio_volume_deinit(ah);
     _audio_ucm_deinit(ah);
     _audio_util_deinit(ah);
+    _audio_modem_deinit(ah);
+    _audio_comm_deinit(ah);
     free(ah);
     ah = NULL;
 
index 8dd3b44..794cdd7 100644 (file)
@@ -30,7 +30,10 @@ typedef enum audio_return {
     AUDIO_ERR_RESOURCE                  = (int32_t)0x80001001,
     AUDIO_ERR_PARAMETER                 = (int32_t)0x80001002,
     AUDIO_ERR_IOCTL                     = (int32_t)0x80001003,
-    AUDIO_ERR_NOT_IMPLEMENTED           = (int32_t)0x80001004,
+    AUDIO_ERR_INVALID_STATE             = (int32_t)0x80001004,
+    AUDIO_ERR_INTERNAL                  = (int32_t)0x80001005,
+
+    AUDIO_ERR_NOT_IMPLEMENTED           = (int32_t)0x80001100,
 } audio_return_t ;
 
 typedef enum audio_direction {
@@ -68,19 +71,24 @@ typedef struct audio_stream_info {
     uint32_t idx;
 } audio_stream_info_t ;
 
+typedef void (*message_cb)(const char *name, int value, void *user_data);
+
 /* Overall */
 typedef struct audio_interface {
     audio_return_t (*init)(void **audio_handle);
     audio_return_t (*deinit)(void *audio_handle);
+    /* Volume */
     audio_return_t (*get_volume_level_max)(void *audio_handle, audio_volume_info_t *info, uint32_t *level);
     audio_return_t (*get_volume_level)(void *audio_handle, audio_volume_info_t *info, uint32_t *level);
     audio_return_t (*set_volume_level)(void *audio_handle, audio_volume_info_t *info, uint32_t level);
     audio_return_t (*get_volume_value)(void *audio_handle, audio_volume_info_t *info, uint32_t level, double *value);
     audio_return_t (*get_volume_mute)(void *audio_handle, audio_volume_info_t *info, uint32_t *mute);
     audio_return_t (*set_volume_mute)(void *audio_handle, audio_volume_info_t *info, uint32_t mute);
+    /* Routing */
     audio_return_t (*do_route)(void *audio_handle, audio_route_info_t *info);
     audio_return_t (*update_route_option)(void *audio_handle, audio_route_option_t *option);
     audio_return_t (*update_stream_connection_info) (void *audio_handle, audio_stream_info_t *info, uint32_t is_connected);
+    /* Buffer Attribute */
     audio_return_t (*get_buffer_attr)(void *audio_handle, uint32_t direction, const char *latency, uint32_t samplerate, int format, uint32_t channels,
                                       uint32_t *maxlength, uint32_t *tlength, uint32_t *prebuf, uint32_t* minreq, uint32_t *fragsize);
     /* Interface of PCM device */
@@ -95,6 +103,8 @@ typedef struct audio_interface {
     audio_return_t (*pcm_recover)(void *audio_handle, void *pcm_handle, int revents);
     audio_return_t (*pcm_get_params)(void *audio_handle, void *pcm_handle, uint32_t direction, void **sample_spec, uint32_t *period_size, uint32_t *periods);
     audio_return_t (*pcm_set_params)(void *audio_handle, void *pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods);
+    /* Message callback */
+    audio_return_t (*set_message_cb)(void *audio_handle, message_cb callback, void *user_data);
 } audio_interface_t;
 
 audio_return_t audio_init(void **audio_handle);
@@ -121,4 +131,5 @@ audio_return_t audio_pcm_get_fd(void *audio_handle, void *pcm_handle, int *fd);
 audio_return_t audio_pcm_recover(void *audio_handle, void *pcm_handle, int revents);
 audio_return_t audio_pcm_get_params(void *audio_handle, void *pcm_handle, uint32_t direction, void **sample_spec, uint32_t *period_size, uint32_t *periods);
 audio_return_t audio_pcm_set_params(void *audio_handle, void *pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods);
+audio_return_t audio_set_message_cb(void *audio_handle, message_cb callback, void *user_data);
 #endif
diff --git a/vb_control_parameters.h b/vb_control_parameters.h
new file mode 100644 (file)
index 0000000..0b64e66
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VBC_CONTROL_PARAMETERS_H
+#define VBC_CONTROL_PARAMETERS_H
+
+#include "pthread.h"
+
+
+#define BUF_SIZE 1024
+
+#define VBC_PIPE_NAME_MAX_LEN 16
+#define VOIP_PIPE_NAME_MAX     VBC_PIPE_NAME_MAX_LEN
+#define NAME_LEN_MAX 16
+
+#define AUDIO_XML_PATH "/usr/etc/audio_hw.xml"
+
+#define MODEM_T_ENABLE_PROPERTY     "persist.modem.t.enable"
+#define MODEM_W_ENABLE_PROPERTY     "persist.modem.w.enable"
+
+
+typedef enum {
+    CP_W,
+    CP_TG,
+    CP_MAX
+}cp_type_t;
+
+/*support multiple call for multiple modem(cp0/cp1/...):
+different modem is corresponding to different pipe and all pipes use the only vbc.
+support multiple pipe:
+1. change VBC_PIPE_COUNT
+2. change the definition of s_vbc_ctrl_pipe_info.
+3. change channel_id for different cp .On sharp, 0 for cp0,  1 for cp1,2 for ap
+*/
+
+typedef struct
+{
+    char s_vbc_ctrl_pipe_name[VBC_PIPE_NAME_MAX_LEN];
+    int channel_id;
+    cp_type_t cp_type;
+}vbc_ctrl_pipe_para_t;
+
+
+struct voip_res
+{
+    cp_type_t cp_type;
+    int8_t  pipe_name[VOIP_PIPE_NAME_MAX];
+    int  channel_id;
+    int enable;
+    int is_done;
+    void *adev;
+    pthread_t thread_id;
+};
+
+typedef struct
+{
+    int8_t index;
+    int is_switch;
+    int8_t is_ext;
+}i2s_ctl_t;
+
+
+
+typedef struct debuginfo
+{
+    int enable;
+    int sleeptime_gate;
+    int pcmwritetime_gate;
+    int lastthis_outwritetime_gate;
+}debuginfo;
+
+typedef struct{
+    int num;
+    vbc_ctrl_pipe_para_t *vbc_ctrl_pipe_info;
+    i2s_ctl_t i2s_bt;
+    i2s_ctl_t i2s_extspk;
+    struct voip_res  voip_res;
+    debuginfo debug_info;
+}audio_modem_t;
+
+/*audio mode structure,we can expand  for more fields if necessary*/
+typedef struct
+{
+       int index;
+    char mode_name[NAME_LEN_MAX];
+
+}audio_mode_item_t;
+
+/*we mostly have four mode,(headset,headfree,handset,handsfree),
+    differet product may configure different mode number,htc have 25 modes.*/
+typedef struct{
+       int num;
+       audio_mode_item_t *audio_mode_item_info;
+}aud_mode_t;
+struct modem_config_parse_state{
+       audio_modem_t *modem_info;
+       vbc_ctrl_pipe_para_t *vbc_ctrl_pipe_info;
+       aud_mode_t  *audio_mode_info;
+       audio_mode_item_t *audio_mode_item_info;
+};
+
+#endif
+