exynos: sthal: Update to latest source

* From https://gitlab.com/Linaro/96boards/e850-96/platform/hardware/samsung_slsi/-/tree/3f80ca082ee2471ffa4c22f70b131dd6af456de3/modules/libaudio/sthal
* With modification to allow specifying soundtrigger config path explicitly.

Change-Id: I958095549d0e347dc83b8932df6abefbf1683dff
Signed-off-by: Francescodario Cuzzocrea <bosconovic@gmail.com>
diff --git a/libaudio/sthal/Android.mk b/libaudio/sthal/Android.mk
index ba50ba4..3c7125a 100644
--- a/libaudio/sthal/Android.mk
+++ b/libaudio/sthal/Android.mk
@@ -17,6 +17,7 @@
 #
 # Primary SoundTrigger HAL module
 #
+ifeq ($(BOARD_USE_COMMON_AUDIOHAL), true)
 ifeq ($(BOARD_USE_SOUNDTRIGGER_HAL),true)
 LOCAL_PATH := $(call my-dir)
 
@@ -40,21 +41,16 @@
 LOCAL_CFLAGS += -DMMAP_INTERFACE_ENABLED
 endif
 
-LOCAL_MODULE := sound_trigger.primary.$(TARGET_SOC)
-
-ifeq ($(BOARD_USES_VENDORIMAGE), true)
-LOCAL_PROPRIETARY_MODULE := true
+ifeq ($(BOARD_USE_SOUNDTRIGGER_HAL_2_3),true)
+LOCAL_CFLAGS += -DSTHAL_2_3
 endif
+
+LOCAL_MODULE := sound_trigger.primary.$(TARGET_SOC)
+LOCAL_PROPRIETARY_MODULE := true
 LOCAL_MODULE_RELATIVE_PATH := hw
 LOCAL_MODULE_TAGS := optional
 
 include $(BUILD_SHARED_LIBRARY)
-
-else
-
-ifeq ($(BOARD_USE_SOUNDTRIGGER_HAL), STHAL_TEST)
-LOCAL_PATH := $(call my-dir)
 include $(call all-makefiles-under,$(LOCAL_PATH))
 endif
-
 endif
diff --git a/libaudio/sthal/sound_trigger_hw.c b/libaudio/sthal/sound_trigger_hw.c
index fe0a613..834117f 100644
--- a/libaudio/sthal/sound_trigger_hw.c
+++ b/libaudio/sthal/sound_trigger_hw.c
@@ -53,8 +53,8 @@
 #include"vts.h"
 #endif
 
-/* Note: odmword_uuid should be updated */
-static sound_trigger_uuid_t odmword_uuid = { 0x1817de20, 0xfa3b, 0x11e5, 0xbef2, { 0x00, 0x03, 0xa6, 0xd6, 0xc6, 0x1c } };
+/* temporary hack for okg */
+static sound_trigger_uuid_t bixby_uuid = { 0x1817de20, 0xfa3b, 0x11e5, 0xbef2, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
 static sound_trigger_uuid_t hotword_uuid = { 0x7038ddc8, 0x30f2, 0x11e6, 0xb0ac, { 0x40, 0xa8, 0xf0, 0x3d, 0x3f, 0x15 } };
 
 
@@ -72,7 +72,11 @@
 
 // Since there's only ever one sound_trigger_device, keep it as a global so that other people can
 // dlopen this lib to get at the streaming audio.
-static struct sound_trigger_device g_stdev = { .lock = PTHREAD_MUTEX_INITIALIZER };
+static struct sound_trigger_device g_stdev = {
+    .lock = PTHREAD_MUTEX_INITIALIZER,
+    .trigger_lock = PTHREAD_MUTEX_INITIALIZER,
+    .recording_lock = PTHREAD_MUTEX_INITIALIZER
+};
 
 // Utility function for configuration MIC mixer controls
 int set_mixer_ctrls(
@@ -145,7 +149,7 @@
     memcpy(stdev->mapped_addr, data, len);
 
     ALOGV("%s: %s Model loaded size[%d]", __func__,
-                (model_index == HOTWORD_INDEX ? "Google" : "ODMVoice"), len);
+                (model_index == HOTWORD_INDEX ? "Google" : "SVoice"), len);
 
     if (len > VTSDRV_MISC_MODEL_BIN_MAXSZ) {
         ALOGW("%s: buffer overflow Model size[%d] > Mapped bufsize[%d]",
@@ -156,7 +160,7 @@
     if (model_index == HOTWORD_INDEX)
         ioctl_cmd = VTSDRV_MISC_IOCTL_WRITE_GOOGLE;
     else
-        ioctl_cmd = VTSDRV_MISC_IOCTL_WRITE_ODMVOICE;
+        ioctl_cmd = VTSDRV_MISC_IOCTL_WRITE_SVOICE;
 
     /* Update model binary inforation to VTS misc driver */
     if (ioctl(stdev->vtsdev_fd, ioctl_cmd, &len) < 0) {
@@ -208,9 +212,8 @@
 
 // Utility function for allocating a hotword recognition event. Caller receives ownership of
 // allocated struct.
-static struct sound_trigger_recognition_event *sound_trigger_hotword_event_alloc(
-        struct sound_trigger_device *stdev)
-{
+static struct sound_trigger_recognition_event *sound_trigger_event_alloc(
+        struct sound_trigger_device *stdev, int index) {
     struct sound_trigger_phrase_recognition_event *event =
             (struct sound_trigger_phrase_recognition_event *)calloc(
                     1, sizeof(struct sound_trigger_phrase_recognition_event));
@@ -220,16 +223,16 @@
 
     event->common.status = RECOGNITION_STATUS_SUCCESS;
     event->common.type = SOUND_MODEL_TYPE_KEYPHRASE;
-    event->common.model = stdev->model_handles[HOTWORD_INDEX];
+    event->common.model = stdev->model_handles[index];
 
-    if (stdev->configs[HOTWORD_INDEX]) {
+    if (stdev->configs[index]) {
         unsigned int i;
 
-        event->num_phrases = stdev->configs[HOTWORD_INDEX]->num_phrases;
+        event->num_phrases = stdev->configs[index]->num_phrases;
         if (event->num_phrases > SOUND_TRIGGER_MAX_PHRASES)
             event->num_phrases = SOUND_TRIGGER_MAX_PHRASES;
         for (i=0; i < event->num_phrases; i++)
-            memcpy(&event->phrase_extras[i], &stdev->configs[HOTWORD_INDEX]->phrases[i],
+            memcpy(&event->phrase_extras[i], &stdev->configs[index]->phrases[i],
                    sizeof(struct sound_trigger_phrase_recognition_extra));
     }
 
@@ -251,12 +254,8 @@
     return &event->common;
 }
 
-// Utility function for allocating a hotsound recognition event. Caller receives ownership of
-// allocated struct.
-static struct sound_trigger_recognition_event *sound_trigger_odmvoice_event_alloc(
-        struct sound_trigger_device* stdev)
-{
-#if 0 //Generic recognition event
+static struct sound_trigger_recognition_event *sound_trigger_generic_event_alloc(
+        struct sound_trigger_device *stdev, int index) {
     struct sound_trigger_generic_recognition_event *event =
             (struct sound_trigger_generic_recognition_event *)calloc(
                     1, sizeof(struct sound_trigger_generic_recognition_event));
@@ -266,45 +265,8 @@
 
     event->common.status = RECOGNITION_STATUS_SUCCESS;
     event->common.type = SOUND_MODEL_TYPE_GENERIC;
-    event->common.model = stdev->model_handles[ODMVOICE_INDEX];
-    // Signify that all the data is coming through streaming, not through the
-    // buffer.
-    event->common.capture_available = true;
+    event->common.model = stdev->model_handles[index];
 
-    event->common.audio_config = AUDIO_CONFIG_INITIALIZER;
-    event->common.audio_config.sample_rate = 16000;
-    event->common.audio_config.channel_mask = AUDIO_CHANNEL_IN_MONO;
-    event->common.audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
-#else //as ODMVoice model
-    struct sound_trigger_phrase_recognition_event *event =
-            (struct sound_trigger_phrase_recognition_event *)calloc(
-                    1, sizeof(struct sound_trigger_phrase_recognition_event));
-    if (!event) {
-        return NULL;
-    }
-
-    event->common.status = RECOGNITION_STATUS_SUCCESS;
-    event->common.type = SOUND_MODEL_TYPE_KEYPHRASE;
-    event->common.model = stdev->model_handles[ODMVOICE_INDEX];
-
-    if (stdev->configs[ODMVOICE_INDEX]) {
-        unsigned int i;
-
-        event->num_phrases = stdev->configs[ODMVOICE_INDEX]->num_phrases;
-        if (event->num_phrases > SOUND_TRIGGER_MAX_PHRASES)
-            event->num_phrases = SOUND_TRIGGER_MAX_PHRASES;
-        for (i=0; i < event->num_phrases; i++)
-            memcpy(&event->phrase_extras[i], &stdev->configs[ODMVOICE_INDEX]->phrases[i],
-                   sizeof(struct sound_trigger_phrase_recognition_extra));
-    }
-
-    event->num_phrases = 1;
-    event->phrase_extras[0].confidence_level = 100;
-    event->phrase_extras[0].num_levels = 1;
-    event->phrase_extras[0].levels[0].level = 100;
-    event->phrase_extras[0].levels[0].user_id = 0;
-    // Signify that all the data is coming through streaming, not through the
-    // buffer.
     event->common.capture_available = true;
     event->common.trigger_in_data = false;
 
@@ -312,25 +274,47 @@
     event->common.audio_config.sample_rate = 16000;
     event->common.audio_config.channel_mask = AUDIO_CHANNEL_IN_MONO;
     event->common.audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
-#endif
+
     return &event->common;
 }
+#ifdef STHAL_2_3
+const struct sound_trigger_properties_header* stdev_get_properties_extended(
+        const struct sound_trigger_hw_device *dev) {
+    struct sound_trigger_device *stdev = (struct sound_trigger_device *)dev;
 
+    ALOGI("%s: enter", __func__);
+
+    if (stdev == NULL)
+        return NULL;
+
+    return (struct sound_trigger_properties_header *)&hw_properties_1_3;
+}
+#endif
 static int stdev_get_properties(
         const struct sound_trigger_hw_device *dev,
         struct sound_trigger_properties *properties)
 {
     struct sound_trigger_device *stdev = (struct sound_trigger_device *)dev;
+    int google_version = 0;
 
     ALOGI("%s", __func__);
     if (stdev == NULL || properties == NULL) {
         return -EINVAL;
     }
+
+    pthread_mutex_lock(&stdev->lock);
+    if (ioctl(stdev->vtsdev_fd, VTSDRV_MISC_IOCTL_READ_GOOGLE_VERSION, &google_version) < 0) {
+        ALOGE("%s: VTSDRV_MISC_IOCTL_READ_GOOGLE_VERSION failed", __func__);
+        //return -EINVAL;
+    }
+    pthread_mutex_unlock(&stdev->lock);
+    ALOGI("%s Google Version : %d", __func__, google_version);
     memcpy(properties, &hw_properties, sizeof(struct sound_trigger_properties));
+    properties->version = google_version;
     return 0;
 }
 
-//Parses Extra config structure data, for ODMVoice specification information
+//Parses Extra config structure data, for SVoice specification information
 static void ParseExtraConfigData(
         struct sound_trigger_device *stdev,
         const char *keyValuePairs)
@@ -345,29 +329,22 @@
         return;
     }
 
-	/* Note: if any Extra config data is defined by ODM,
-	 * parsing strings should updated as ODM specific requirements
-	 * Information that can be set in extra data,
-	 * 1. Backlog_size: How many ms of previous data to be captured from the trigger word
-	 * 2. Voice trigger mode: ODM specific, other default trigger mode will be used
-	*/
-
     // get backlog_size
-    ret = str_parms_get_int(parms, "backlog_size", &value);
+    ret = str_parms_get_int(parms, "voice_trig", &value);
     if (ret >= 0) {
-        ALOGV("backlog_size = (%d)", value);
+        ALOGV("voice_trigger = (%d)", value);
         stdev->backlog_size = value;
-        str_parms_del(parms, "backlog_size");
+        str_parms_del(parms, "voice_trig");
     }
 
-    /* ODM specific voice trigger mode if any
-     * currently 3 modes as reserved1, reserved2 & default one ODM Voice trigger mode
-    */
-    ret = str_parms_get_int(parms, "voice_trigger_mode", &value);
+    // wakeup_mode : 1 => bixby (LPSD + voice trigger)
+    // wakeup_mode : 2 => LPSD(babycry/doorbell)
+    // wakeup_mode : 3 => bixby (only voice trigger)
+    ret = str_parms_get_int(parms, "wakeup_mode", &value);
     if (ret >= 0) {
-        ALOGV("voice_trigger_mode = (%d)", value);
-        stdev->odmvoicemodel_mode = value;
-        str_parms_del(parms, "voice_trigger_mode");
+        ALOGV("wakeup_mode = (%d)", value);
+        stdev->svoicemodel_mode = value;
+        str_parms_del(parms, "wakeup_mode");
     }
     str_parms_destroy(parms);
 }
@@ -380,6 +357,7 @@
 {
     char **active_mic_ctrls = NULL;
     int *ctrl_values = NULL;
+    int ctrl_count = MAIN_MIC_CONTROL_COUNT;
 
     if (enable_mic != 0) {
         /* Check whether MIC controls are configured or not, if not configure first */
@@ -391,9 +369,10 @@
             if (stdev->active_mic == VTS_HEADSET_MIC) {
                 active_mic_ctrls = headset_mic_ctlname;
                 ctrl_values = headset_mic_ctlvalue;
+                ctrl_count = HEADSET_MIC_CONTROL_COUNT;
             }
 
-            if (set_mixer_ctrls(stdev, active_mic_ctrls, ctrl_values, MAIN_MIC_CONTROL_COUNT, false)) {
+            if (set_mixer_ctrls(stdev, active_mic_ctrls, ctrl_values, ctrl_count, false)) {
                 ALOGW("%s: Enabling MIC control configuration Failed", __func__);
             }
             stdev->is_mic_configured = 1;
@@ -402,12 +381,14 @@
     } else {
         active_mic_ctrls = main_mic_ctlname;
 
-        if (stdev->active_mic == VTS_HEADSET_MIC)
+        if (stdev->active_mic == VTS_HEADSET_MIC) {
             active_mic_ctrls = headset_mic_ctlname;
+            ctrl_count = HEADSET_MIC_CONTROL_COUNT;
+        }
 
         /* Reset MIC controls for disabling VTS */
         if (stdev->is_mic_configured) {
-            if (set_mixer_ctrls(stdev, active_mic_ctrls, NULL, MAIN_MIC_CONTROL_COUNT, true)) {
+            if (set_mixer_ctrls(stdev, active_mic_ctrls, NULL, ctrl_count, true)) {
                 ALOGW("%s: Enabling MIC control configuration Failed", __func__);
             }
             stdev->is_mic_configured = 0;
@@ -417,7 +398,32 @@
 
     return;
 }
+#ifdef STHAL_2_3
+static int stdev_set_parameter(const struct sound_trigger_hw_device *dev __unused,
+                                   sound_model_handle_t handle __unused,
+                                   sound_trigger_model_parameter_t param __unused,
+                                   int32_t value __unused) {
+    ALOGI("%s: enter", __func__);
 
+    return 0;
+}
+
+static int stdev_get_parameter(const struct sound_trigger_hw_device *dev __unused,
+        sound_model_handle_t handle __unused, sound_trigger_model_parameter_t param __unused,
+        int32_t *value __unused) {
+    ALOGI("%s: enter", __func__);
+
+    return 0;
+}
+
+static int stdev_query_parameter(const struct sound_trigger_hw_device *dev __unused,
+        sound_model_handle_t handle __unused, sound_trigger_model_parameter_t param __unused,
+        sound_trigger_model_parameter_range_t *param_range __unused) {
+    ALOGI("%s: enter", __func__);
+
+    return 0;
+}
+#endif
 // If enabled_algorithms = 0, then the VTS will be turned off. Otherwise, treated as a bit mask for
 // which algorithms should be enabled on the VTS. Must be called with the stdev->lock held.
 static void stdev_vts_set_power(
@@ -443,7 +449,7 @@
         if (enabled_algorithms & (0x1 << HOTWORD_INDEX)) {
             ALOGV("%s: Google Model recognization start", __func__);
             if (set_mixer_ctrls(stdev, model_recognize_start_ctlname,
-                hotword_recognize_start_ctlvalue, MODEL_CONTROL_COUNT, false)) {
+                hotword_recognize_start_ctlvalue, MODEL_START_CONTROL_COUNT, false)) {
                 ALOGE("%s: Google Model recognization start Failed", __func__);
                 goto exit;
             }
@@ -454,52 +460,52 @@
             ALOGD("%s: Google Model recognization started & Notified to AudioHAL", __func__);
         }
 
-        if (enabled_algorithms & (0x1 << ODMVOICE_INDEX)) {
+        if (enabled_algorithms & (0x1 << SVOICE_INDEX)) {
             int *ctrl_values = NULL;
 
-            if (stdev->odmvoicemodel_mode == ODMVOICE_RESERVED1_MODE)
-                ctrl_values = odmvoice_reserved1recognize_start_ctlvalue;
-            else if (stdev->odmvoicemodel_mode == ODMVOICE_RESERVED2_MODE)
-                ctrl_values = odmvoice_reserved2recognize_start_ctlvalue;
-            else if (stdev->odmvoicemodel_mode == ODMVOICE_TRIGGER_MODE)
-                ctrl_values = odmvoice_triggerrecognize_start_ctlvalue;
+            if (stdev->svoicemodel_mode == SVOICE_BIXBY_MODE)
+                ctrl_values = svoice_bixbyrecognize_start_ctlvalue;
+            else if (stdev->svoicemodel_mode == SVOICE_LPSD_MODE)
+                ctrl_values = svoice_lpsdrecognize_start_ctlvalue;
+            else if (stdev->svoicemodel_mode == SVOICE_BIXBY_ALWAYS_MODE)
+                ctrl_values = svoice_bixbyalwaysrecognize_start_ctlvalue;
             else {
-                ALOGE("%s: Unknown ODMVoice recognition mode to start, set default ODMVoice Trigger mode", __func__);
-                ctrl_values = odmvoice_triggerrecognize_start_ctlvalue;
+                ALOGE("%s: Unknown Svoice recognition mode to start, set default bixby mode", __func__);
+                ctrl_values = svoice_bixbyrecognize_start_ctlvalue;
             }
 
-            ALOGV("%s: ODMVoice Model [%s] recognization start", __func__,
-                ((stdev->odmvoicemodel_mode == ODMVOICE_RESERVED2_MODE) ?
-                "ODM Reserved2 mode" : ((stdev->odmvoicemodel_mode == ODMVOICE_RESERVED1_MODE) ?
-                "ODM Reserved1 mode" : "ODMVoice trigger mode")));
+            ALOGV("%s: Svoice Model [%s] recognization start", __func__,
+                ((stdev->svoicemodel_mode == SVOICE_LPSD_MODE) ?
+                "BabyCry" : ((stdev->svoicemodel_mode == SVOICE_BIXBY_MODE) ?
+                "Bixby" : "Bixby Always")));
             if (set_mixer_ctrls(stdev, model_recognize_start_ctlname,
-                        ctrl_values, MODEL_CONTROL_COUNT, false)) {
-                ALOGE("%s: ODMVoice Model recognization start Failed", __func__);
+                        ctrl_values, MODEL_START_CONTROL_COUNT, false)) {
+                ALOGE("%s: Svoice Model recognization start Failed", __func__);
                 goto exit;
             }
 
             /* handle backlog control size */
-            if ((stdev->odmvoicemodel_mode == ODMVOICE_RESERVED1_MODE ||
-                stdev->odmvoicemodel_mode == ODMVOICE_TRIGGER_MODE) &&
+            if ((stdev->svoicemodel_mode == SVOICE_BIXBY_MODE ||
+                stdev->svoicemodel_mode == SVOICE_BIXBY_ALWAYS_MODE) &&
                 stdev->backlog_size) {
                 if (set_mixer_ctrls(stdev, model_backlog_size_ctlname,
                             &stdev->backlog_size, MODEL_BACKLOG_CONTROL_COUNT, false)) {
-                    ALOGE("%s: ODMVoice Model backlog size configuration Failed", __func__);
+                    ALOGE("%s: Svoice Model backlog size configuration Failed", __func__);
                     goto exit;
                 }
-                ALOGD("%s: ODMVoice Model Backlog size [%d] configured", __func__, stdev->backlog_size);
+                ALOGD("%s: Svoice Model Backlog size [%d] configured", __func__, stdev->backlog_size);
             }
-            stdev->recognize_started |= (0x1 << ODMVOICE_INDEX);
-            ALOGD("%s: ODMVoice Model [%s] recognization started", __func__,
-                ((stdev->odmvoicemodel_mode == ODMVOICE_RESERVED2_MODE) ?
-                "ODM Reserved2 mode" : ((stdev->odmvoicemodel_mode == ODMVOICE_RESERVED1_MODE) ?
-                "ODM Reserved1 mode" : "ODMVoice trigger mode")));
+            stdev->recognize_started |= (0x1 << SVOICE_INDEX);
+            ALOGD("%s: Svoice Model [%s] recognization started", __func__,
+                ((stdev->svoicemodel_mode == SVOICE_LPSD_MODE) ?
+                "BabyCry" : ((stdev->svoicemodel_mode == SVOICE_BIXBY_MODE) ?
+                "Bixby" : "Bixby Always")));
         }
     } else {
         /* Stop recognition of previous started models */
         if (stdev->recognize_started & (0x1 << HOTWORD_INDEX)) {
             if (set_mixer_ctrls(stdev, model_recognize_stop_ctlname,
-                hotword_recognize_stop_ctlvalue, MODEL_CONTROL_COUNT, false)) {
+                hotword_recognize_stop_ctlvalue, MODEL_STOP_CONTROL_COUNT, false)) {
                 ALOGE("%s: Google Model recognization stop Failed", __func__);
                 goto exit;
             }
@@ -510,30 +516,30 @@
             ALOGD("%s: Google Model recognization stopped & Notified to AudioHAL", __func__);
         }
 
-        if (stdev->recognize_started & (0x1 << ODMVOICE_INDEX)) {
+        if (stdev->recognize_started & (0x1 << SVOICE_INDEX)) {
             int *ctrl_values = NULL;
 
-            if (stdev->odmvoicemodel_mode == ODMVOICE_RESERVED1_MODE)
-                ctrl_values = odmvoice_reserved1recognize_stop_ctlvalue;
-            else if (stdev->odmvoicemodel_mode == ODMVOICE_RESERVED2_MODE)
-                ctrl_values = odmvoice_reserved2recognize_stop_ctlvalue;
-            else if (stdev->odmvoicemodel_mode == ODMVOICE_TRIGGER_MODE)
-                ctrl_values = odmvoice_triggerrecognize_stop_ctlvalue;
+            if (stdev->svoicemodel_mode == SVOICE_BIXBY_MODE)
+                ctrl_values = svoice_bixbyrecognize_stop_ctlvalue;
+            else if (stdev->svoicemodel_mode == SVOICE_LPSD_MODE)
+                ctrl_values = svoice_lpsdrecognize_stop_ctlvalue;
+            else if (stdev->svoicemodel_mode == SVOICE_BIXBY_ALWAYS_MODE)
+                ctrl_values = svoice_bixbyalwaysrecognize_stop_ctlvalue;
             else {
-                ALOGE("%s: Unknown ODMVoice recognition mode to stop, use default ODMVoice Trigger mode", __func__);
-                ctrl_values = odmvoice_triggerrecognize_stop_ctlvalue;
+                ALOGE("%s: Unknown Svoice recognition mode to stop, set default bixby mode", __func__);
+                ctrl_values = svoice_bixbyrecognize_stop_ctlvalue;
             }
 
             if (set_mixer_ctrls(stdev, model_recognize_stop_ctlname,
-                ctrl_values, MODEL_CONTROL_COUNT, false)) {
-                ALOGE("%s: ODMVoice Model recognization stop Failed", __func__);
+                ctrl_values, MODEL_STOP_CONTROL_COUNT, false)) {
+                ALOGE("%s: Svoice Model recognization stop Failed", __func__);
                 goto exit;
             }
-            stdev->recognize_started &= ~(0x1 << ODMVOICE_INDEX);
-            ALOGD("%s: ODMVoice Model [%s] recognization stopped", __func__,
-                ((stdev->odmvoicemodel_mode == ODMVOICE_RESERVED2_MODE) ?
-                "ODM Reserved2 mode" : ((stdev->odmvoicemodel_mode == ODMVOICE_RESERVED1_MODE) ?
-                "ODM Reserved1 mode" : "ODMVoice trigger mode")));
+            stdev->recognize_started &= ~(0x1 << SVOICE_INDEX);
+            ALOGD("%s: Svoice Model [%s] recognization stopped", __func__,
+                ((stdev->svoicemodel_mode == SVOICE_LPSD_MODE) ?
+                "BabyCry" : ((stdev->svoicemodel_mode == SVOICE_BIXBY_MODE) ?
+                "Bixby" : "Bixby Always")));
         }
 
         if (!stdev->recognize_started && !stdev->is_recording) {
@@ -684,8 +690,8 @@
 #else
         ret = sysfs_write(VTS_HOTWORD_MODEL, buffer, buffer_len);
 #endif
-    } else if (model_index == ODMVOICE_INDEX) {
-        /* load ODMVoice model binary */
+    } else if (model_index == SVOICE_INDEX) {
+        /* load SVoice model binary */
 #ifdef MMAP_INTERFACE_ENABLED
         ret = load_modelbinary(stdev, model_index, buffer, buffer_len);
 #else
@@ -728,6 +734,7 @@
     struct pollfd fds[2];
     int err = 0;
     int i, n;
+    int recoveryCnt = 0;
 
     ALOGI("%s", __func__);
     prctl(PR_SET_NAME, (unsigned long)"sound trigger callback", 0, 0, 0);
@@ -760,18 +767,26 @@
             }
             for (i = 0; i < n;) {
                 if (strstr(msg + i, "VOICE_WAKEUP_WORD_ID=1") ||
-                    strstr(msg + i, "VOICE_WAKEUP_WORD_ID=2") ||
-                    strstr(msg + i, "VOICE_WAKEUP_WORD_ID=3")) {
+                    strstr(msg + i, "VOICE_WAKEUP_WORD_ID=LPSD") ||
+                    strstr(msg + i, "VOICE_WAKEUP_WORD_ID=2")) {
                     struct sound_trigger_recognition_event *event = NULL;
                     int trigger_index = 0;
 
                     if (strstr(msg + i, "VOICE_WAKEUP_WORD_ID=1")||
-                        strstr(msg + i, "VOICE_WAKEUP_WORD_ID=3")) {
-                            event = sound_trigger_odmvoice_event_alloc(stdev);
-                            trigger_index = ODMVOICE_INDEX;
-                            ALOGI("%s ODMVOICE Event Triggerred %d", __func__, trigger_index);
+                        strstr(msg + i, "VOICE_WAKEUP_WORD_ID=LPSD")) {
+                        if (stdev->is_generic & (0x1 << SVOICE_INDEX))
+                            event = sound_trigger_generic_event_alloc(stdev, SVOICE_INDEX);
+                        else
+                            event = sound_trigger_event_alloc(stdev, SVOICE_INDEX);
+
+                            trigger_index = SVOICE_INDEX;
+                            ALOGI("%s SVOICE Event Triggerred %d", __func__, trigger_index);
                     } else {
-                            event = sound_trigger_hotword_event_alloc(stdev);
+                        if (stdev->is_generic & (0x1 << HOTWORD_INDEX))
+                            event = sound_trigger_generic_event_alloc(stdev, HOTWORD_INDEX);
+                        else
+                            event = sound_trigger_event_alloc(stdev, HOTWORD_INDEX);
+
                             trigger_index = HOTWORD_INDEX;
                             ALOGI("%s HOTWORD Event Triggered --%d", __func__, trigger_index);
                     }
@@ -793,13 +808,13 @@
                             stdev->configs[trigger_index] &&
                             stdev->configs[trigger_index]->capture_requested) {
                             ALOGI("%s Streaming Enabled for %s", __func__, (trigger_index ?
-                                        "ODMVOICE" : "HOTWORD"));
+                                        "SVOICE" : "HOTWORD"));
                             stdev->is_streaming = (0x1 << trigger_index);
                             goto exit;
                         } else {
                             /* Error handling if models stop-recognition failed */
                             if ((stdev->model_stopfailedhandles[HOTWORD_INDEX] != HANDLE_NONE) ||
-                                (stdev->model_stopfailedhandles[ODMVOICE_INDEX] != HANDLE_NONE) ||
+                                (stdev->model_stopfailedhandles[SVOICE_INDEX] != HANDLE_NONE) ||
                                 stdev->model_execstate[trigger_index] == MODEL_STATE_STOPABORT) {
                                 handle_stop_recognition_l(stdev);
                                 stdev->model_execstate[trigger_index] = MODEL_STATE_NONE;
@@ -828,7 +843,24 @@
             ALOGI("%s: Termination message", __func__);
             break;
         } else {
-            ALOGI("%s: Message to ignore", __func__);
+            ALOGI("%s: uevent %d %d / err : %d", __func__, fds[0].revents, fds[1].revents, err);
+            if ((fds[0].revents & POLLERR) ||
+                (fds[0].revents & POLLHUP)) {
+                recoveryCnt++;
+                if (recoveryCnt > 1) {
+                    ALOGE("%s: Socket Recovery Fail", __func__);
+                    goto exit;
+                }
+                ALOGI("%s: Socket Error : Recovery", __func__);
+                close(fds[0].fd);
+                stdev->uevent_socket = uevent_open_socket(64*1024, true);
+                if (stdev->uevent_socket == -1) {
+                    ALOGE("%s: Failed to open uevent socket", __func__);
+                    goto exit;
+                }
+                fds[0].events = POLLIN;
+                fds[0].fd = stdev->uevent_socket;
+            }
         }
         stdev->recog_cbstate = RECOG_CB_NONE;
         pthread_mutex_unlock(&stdev->lock);
@@ -876,11 +908,13 @@
 
     /* TODO: Figure out what the model type is by looking at the UUID? */
     if (sound_model->type == SOUND_MODEL_TYPE_KEYPHRASE) {
-        if (!memcmp(&sound_model->vendor_uuid, &odmword_uuid, sizeof(sound_trigger_uuid_t))) {
-            model_index = ODMVOICE_INDEX;
-            ALOGV("%s ODMVOICE_INDEX Sound Model", __func__);
+        if (!memcmp(&sound_model->vendor_uuid, &bixby_uuid, sizeof(sound_trigger_uuid_t))) {
+            model_index = SVOICE_INDEX;
+            stdev->is_generic &= ~(0x1 << SVOICE_INDEX);
+            ALOGV("%s SVOICE_INDEX Sound Model", __func__);
         } else if (!memcmp(&sound_model->vendor_uuid, &hotword_uuid, sizeof(sound_trigger_uuid_t))) {
             model_index = HOTWORD_INDEX;
+            stdev->is_generic &= ~(0x1 << HOTWORD_INDEX);
             ALOGV("%s HOTWORD_INDEX Sound Model", __func__);
         } else {
             ALOGE("%s Invalid UUID: {0x%x, 0x%x, 0x%x, 0x%x \n {0x%x 0x%x 0x%x 0x%x 0x%x 0x%x}}", __func__,
@@ -893,9 +927,14 @@
             goto exit;
         }
     } else if (sound_model->type == SOUND_MODEL_TYPE_GENERIC) {
-        if (!memcmp(&sound_model->vendor_uuid, &odmword_uuid, sizeof(sound_trigger_uuid_t))) {
-            model_index = ODMVOICE_INDEX;
-            ALOGV("%s ODMVOICE_INDEX Sound Model", __func__);
+        if (!memcmp(&sound_model->vendor_uuid, &bixby_uuid, sizeof(sound_trigger_uuid_t))) {
+            model_index = SVOICE_INDEX;
+            stdev->is_generic |= (0x1 << SVOICE_INDEX);
+            ALOGV("%s SVOICE_INDEX Sound Model", __func__);
+        } else if (!memcmp(&sound_model->vendor_uuid, &hotword_uuid, sizeof(sound_trigger_uuid_t))) {
+            model_index = HOTWORD_INDEX;
+            stdev->is_generic |= (0x1 << HOTWORD_INDEX);
+            ALOGV("%s HOTWORD_INDEX Sound Model", __func__);
         } else {
             ALOGE("%s Generic Invalid UUID: {0x%x, 0x%x, 0x%x, 0x%x \n {0x%x 0x%x 0x%x 0x%x 0x%x 0x%x}}",
                 __func__, sound_model->vendor_uuid.timeLow, sound_model->vendor_uuid.timeMid,
@@ -964,7 +1003,91 @@
     pthread_mutex_unlock(&stdev->lock);
     return ret;
 }
+#ifdef STHAL_2_3
+static int stdev_start_recognition_extended(
+        const struct sound_trigger_hw_device *dev,
+        sound_model_handle_t handle,
+        const struct sound_trigger_recognition_config_header *config,
+        recognition_callback_t callback,
+        void *cookie)
+{
+    struct sound_trigger_device *stdev = (struct sound_trigger_device *)dev;
+    struct sound_trigger_recognition_config_extended_1_3 *configs = (struct sound_trigger_recognition_config_extended_1_3 *)config;
+    int ret = 0;
 
+    ALOGI("%s Handle %d", __func__, handle);
+
+    pthread_mutex_lock(&stdev->lock);
+    pthread_mutex_lock(&stdev->trigger_lock);
+    if (handle < 0 || handle >= MAX_SOUND_MODELS || stdev->model_handles[handle] != handle) {
+         ALOGE("%s: Handle doesn't match", __func__);
+        ret = -ENOSYS;
+        goto exit;
+    }
+    if (stdev->recognition_callbacks[handle] != NULL) {
+         ALOGW("%s:model recognition is already started Checking for error state", __func__);
+         /* Error handling if models stop-recognition failed */
+         if ((stdev->model_stopfailedhandles[HOTWORD_INDEX] != HANDLE_NONE) ||
+             (stdev->model_stopfailedhandles[SVOICE_INDEX] != HANDLE_NONE)) {
+             handle_stop_recognition_l(stdev);
+             ALOGI("%s stop-recognition error state handled", __func__);
+         }
+    }
+
+    if (stdev->voicecall_state == VOICECALL_STARTED) {
+        ALOGI("%s VoiceCall in progress", __func__);
+        ret = -EBUSY;
+        goto exit;
+    }
+
+    // Copy the config for this handle.
+    if (config) {
+        if (stdev->configs[handle]) {
+            free(stdev->configs[handle]);
+        }
+        stdev->configs[handle] = malloc(sizeof(configs->base));
+        if (!stdev->configs[handle]) {
+            ret = -ENOMEM;
+            goto exit;
+        }
+        memcpy(stdev->configs[handle], &configs->base, sizeof(configs->base));
+
+        /* Check whether config has extra inforamtion */
+        if (configs->base.data_size > 0) {
+            char *params = (char*)configs + sizeof(*configs);
+            // reset & update user data
+            stdev->backlog_size = 0;
+            stdev->svoicemodel_mode = SVOICE_UNKNOWN_MODE;
+            if (params)
+                ParseExtraConfigData(stdev, params);
+        }
+    }
+
+    ret = stdev_start_callback_thread(stdev);
+    if (ret) {
+        goto exit;
+    }
+
+    stdev->recognition_callbacks[handle] = callback;
+    stdev->recognition_cookies[handle] = cookie;
+
+    // Reconfigure the VTS to run any algorithm that have a callback.
+    if (!stdev->is_streaming ||
+            (stdev->is_streaming & (0x1 << handle))) {
+        ALOGI("Starting VTS Recognition\n");
+        stdev_vts_set_power(stdev, 0);
+        stdev_vts_set_power(stdev, stdev_active_callback_bitmask(stdev));
+    }
+
+    stdev->model_stopfailedhandles[handle] = HANDLE_NONE;
+    stdev->model_execstate[handle] = MODEL_STATE_RUNNING;
+    ALOGI("%s Handle Exit %d", __func__, handle);
+exit:
+    pthread_mutex_unlock(&stdev->trigger_lock);
+    pthread_mutex_unlock(&stdev->lock);
+    return ret;
+}
+#endif
 static int stdev_start_recognition(
         const struct sound_trigger_hw_device *dev,
         sound_model_handle_t handle,
@@ -976,7 +1099,9 @@
     int ret = 0;
 
     ALOGI("%s Handle %d", __func__, handle);
+
     pthread_mutex_lock(&stdev->lock);
+    pthread_mutex_lock(&stdev->trigger_lock);
     if (handle < 0 || handle >= MAX_SOUND_MODELS || stdev->model_handles[handle] != handle) {
          ALOGE("%s: Handle doesn't match", __func__);
         ret = -ENOSYS;
@@ -986,7 +1111,7 @@
          ALOGW("%s:model recognition is already started Checking for error state", __func__);
          /* Error handling if models stop-recognition failed */
          if ((stdev->model_stopfailedhandles[HOTWORD_INDEX] != HANDLE_NONE) ||
-             (stdev->model_stopfailedhandles[ODMVOICE_INDEX] != HANDLE_NONE)) {
+             (stdev->model_stopfailedhandles[SVOICE_INDEX] != HANDLE_NONE)) {
              handle_stop_recognition_l(stdev);
              ALOGI("%s stop-recognition error state handled", __func__);
          }
@@ -1015,7 +1140,7 @@
             char *params = (char*)config + sizeof(*config);
             // reset & update user data
             stdev->backlog_size = 0;
-            stdev->odmvoicemodel_mode = ODMVOICE_UNKNOWN_MODE;
+            stdev->svoicemodel_mode = SVOICE_UNKNOWN_MODE;
             if (params)
                 ParseExtraConfigData(stdev, params);
         }
@@ -1041,6 +1166,7 @@
     stdev->model_execstate[handle] = MODEL_STATE_RUNNING;
     ALOGI("%s Handle Exit %d", __func__, handle);
 exit:
+    pthread_mutex_unlock(&stdev->trigger_lock);
     pthread_mutex_unlock(&stdev->lock);
     return ret;
 }
@@ -1090,8 +1216,12 @@
     } else
         ALOGV("%s Handle %d Trylock acquired successfully", __func__, handle);
 
+    pthread_mutex_lock(&stdev->trigger_lock);
+    ALOGV("%s Handle %d Trigger-Trylock successfully", __func__, handle);
+
     ret = stdev_stop_recognition_l(stdev, handle);
 
+    pthread_mutex_unlock(&stdev->trigger_lock);
     pthread_mutex_unlock(&stdev->lock);
     ALOGI("%s Handle Exit %d", __func__, handle);
     return ret;
@@ -1194,6 +1324,7 @@
     ALOGV("%s", __func__);
 
     pthread_mutex_lock(&stdev->lock);
+    pthread_mutex_lock(&stdev->trigger_lock);
 
     if (!stdev->sthal_opened) {
         ALOGE("%s: stdev has not been opened", __func__);
@@ -1233,6 +1364,7 @@
     stdev->is_seamless_recording = true;
     ret = 1;
 exit:
+    pthread_mutex_unlock(&stdev->trigger_lock);
     pthread_mutex_unlock(&stdev->lock);
     return ret;
 }
@@ -1254,8 +1386,7 @@
         return -EINVAL;
     }
 
-    pthread_mutex_lock(&stdev->lock);
-
+    pthread_mutex_lock(&stdev->trigger_lock);
     if (!stdev->sthal_opened) {
         ALOGE("%s: stdev has not been opened", __func__);
         ret = -EFAULT;
@@ -1283,7 +1414,7 @@
     }
 
 exit:
-    pthread_mutex_unlock(&stdev->lock);
+    pthread_mutex_unlock(&stdev->trigger_lock);
     return ret;
 }
 
@@ -1302,6 +1433,7 @@
     }
 
     pthread_mutex_lock(&stdev->lock);
+    pthread_mutex_lock(&stdev->trigger_lock);
 
     if (!stdev->sthal_opened) {
         ALOGE("%s: stdev has not been opened", __func__);
@@ -1340,6 +1472,7 @@
         stdev_vts_set_power(stdev, active_bitmask);
     }
 exit:
+    pthread_mutex_unlock(&stdev->trigger_lock);
     pthread_mutex_unlock(&stdev->lock);
     return ret;
 }
@@ -1355,6 +1488,7 @@
     ALOGV("%s", __func__);
 
     pthread_mutex_lock(&stdev->lock);
+    pthread_mutex_lock(&stdev->recording_lock);
 
     if (!stdev->sthal_opened) {
         ALOGE("%s: stdev has not been opened", __func__);
@@ -1404,6 +1538,7 @@
     stdev->is_recording = true;
     ret = 1;
 exit:
+    pthread_mutex_unlock(&stdev->recording_lock);
     pthread_mutex_unlock(&stdev->lock);
     return ret;
 }
@@ -1414,12 +1549,11 @@
         size_t  buffer_len)
 {
     struct sound_trigger_device *stdev = &g_stdev;
-//    int i;
+    // int i;
     size_t ret = 0;
 
     //ALOGV("%s", __func__);
-
-    pthread_mutex_lock(&stdev->lock);
+    pthread_mutex_lock(&stdev->recording_lock);
 
     if (!stdev->sthal_opened) {
         ALOGE("%s: stdev has not been opened", __func__);
@@ -1448,7 +1582,7 @@
     }
 
 exit:
-    pthread_mutex_unlock(&stdev->lock);
+    pthread_mutex_unlock(&stdev->recording_lock);
     return ret;
 }
 
@@ -1462,6 +1596,7 @@
     ALOGV("%s", __func__);
 
     pthread_mutex_lock(&stdev->lock);
+    pthread_mutex_lock(&stdev->recording_lock);
 
     if (!stdev->sthal_opened) {
         ALOGE("%s: stdev has not been opened", __func__);
@@ -1477,7 +1612,7 @@
 
     /* Error handling if models stop-recognition failed */
     if ((stdev->model_stopfailedhandles[HOTWORD_INDEX] != HANDLE_NONE) ||
-        (stdev->model_stopfailedhandles[ODMVOICE_INDEX] != HANDLE_NONE)) {
+        (stdev->model_stopfailedhandles[SVOICE_INDEX] != HANDLE_NONE)) {
         handle_stop_recognition_l(stdev);
         ALOGI("%s stop-recognition error state handled", __func__);
     }
@@ -1500,6 +1635,7 @@
 
     stdev->is_recording = false;
 exit:
+    pthread_mutex_unlock(&stdev->recording_lock);
     pthread_mutex_unlock(&stdev->lock);
     return ret;
 }
@@ -1529,8 +1665,10 @@
             ALOGI("%s: Close VTS Record PCM to reconfigure active Mic", __func__);
             // Close record PCM before changing MIC
             if (stdev->recording_pcm) {
+                pthread_mutex_lock(&stdev->recording_lock);
                 pcm_close(stdev->recording_pcm);
                 stdev->recording_pcm = NULL;
+                pthread_mutex_unlock(&stdev->recording_lock);
             }
             stdev->is_recording = false;
         }
@@ -1540,8 +1678,10 @@
             ALOGI("%s: Close VTS Seamless PCM to reconfigure active Mic", __func__);
             // Close seamless PCM before changing MIC
             if (stdev->streaming_pcm) {
+                pthread_mutex_lock(&stdev->trigger_lock);
                 pcm_close(stdev->streaming_pcm);
                 stdev->streaming_pcm = NULL;
+                pthread_mutex_unlock(&stdev->trigger_lock);
             }
             stdev->is_seamless_recording = false;
         }
@@ -1595,8 +1735,10 @@
                 if (stdev->streaming_pcm && !pcm_is_ready(stdev->streaming_pcm)) {
                     ALOGE("%s: failed to open streaming PCM", __func__);
                     if (stdev->recording_pcm) {
+                        pthread_mutex_lock(&stdev->recording_lock);
                         pcm_close(stdev->recording_pcm);
                         stdev->recording_pcm = NULL;
+                        pthread_mutex_unlock(&stdev->recording_lock);
                     }
                     ret = -EFAULT;
                     goto exit;
@@ -1639,8 +1781,10 @@
                 ALOGI("%s: Close VTS Record PCM to reconfigure active Mic", __func__);
                 // Close record PCM before changing MIC
                 if (stdev->recording_pcm) {
+                    pthread_mutex_lock(&stdev->recording_lock);
                     pcm_close(stdev->recording_pcm);
                     stdev->recording_pcm = NULL;
+                    pthread_mutex_unlock(&stdev->recording_lock);
                 }
                 stdev->is_recording = false;
             }
@@ -1650,8 +1794,10 @@
                 ALOGI("%s: Close VTS Seamless PCM to reconfigure active Mic", __func__);
                 // Close seamless PCM before changing MIC
                 if (stdev->streaming_pcm) {
+                    pthread_mutex_lock(&stdev->trigger_lock);
                     pcm_close(stdev->streaming_pcm);
                     stdev->streaming_pcm = NULL;
+                    pthread_mutex_unlock(&stdev->trigger_lock);
                 }
                 stdev->is_seamless_recording = false;
                 stdev->is_streaming = false;
@@ -1661,7 +1807,7 @@
             active_bitmask = stdev_active_callback_bitmask(stdev);
             stdev_vts_set_power(stdev, 0);
             stdev->recognition_callbacks[HOTWORD_INDEX] = NULL;
-            stdev->recognition_callbacks[ODMVOICE_INDEX] = NULL;
+            stdev->recognition_callbacks[SVOICE_INDEX] = NULL;
         }
         /* update voicecall status */
         stdev->voicecall_state = VOICECALL_STARTED;
@@ -1765,12 +1911,20 @@
 
     stdev->device.common.tag = HARDWARE_DEVICE_TAG;
     stdev->device.common.version = SOUND_TRIGGER_DEVICE_API_VERSION_1_0;
+#ifdef STHAL_2_3
+    stdev->device.common.version = SOUND_TRIGGER_DEVICE_API_VERSION_1_3;
+    stdev->device.get_properties_extended = stdev_get_properties_extended;
+    stdev->device.start_recognition_extended = stdev_start_recognition_extended;
+    stdev->device.set_parameter = stdev_set_parameter;
+    stdev->device.get_parameter = stdev_get_parameter;
+    stdev->device.query_parameter = stdev_query_parameter;
+#endif
+    stdev->device.get_properties = stdev_get_properties;
+    stdev->device.start_recognition = stdev_start_recognition;
     stdev->device.common.module = (struct hw_module_t *)module;
     stdev->device.common.close = stdev_close;
-    stdev->device.get_properties = stdev_get_properties;
     stdev->device.load_sound_model = stdev_load_sound_model;
     stdev->device.unload_sound_model = stdev_unload_sound_model;
-    stdev->device.start_recognition = stdev_start_recognition;
     stdev->device.stop_recognition = stdev_stop_recognition;
     stdev->send_socket = stdev->term_socket = stdev->uevent_socket = -1;
     stdev->streaming_pcm = NULL;
@@ -1806,7 +1960,7 @@
             if (!stdev->notify_sthal_status) {
                 ALOGE("%s: Error in grabbing function from %s", __func__, AUDIO_PRIMARY_HAL_LIBRARY_PATH);
                 stdev->notify_sthal_status = 0;
-                goto notify_exit;
+//                goto notify_exit;
             }
         }
     }
@@ -1819,7 +1973,7 @@
     pthread_mutex_unlock(&stdev->lock);
     return 0;
 
-notify_exit:
+// notify_exit:
     if(stdev->audio_primary_lib)
         dlclose(stdev->audio_primary_lib);
 hal_exit:
diff --git a/libaudio/sthal/sound_trigger_hw.h b/libaudio/sthal/sound_trigger_hw.h
index ce22870..3806e81 100644
--- a/libaudio/sthal/sound_trigger_hw.h
+++ b/libaudio/sthal/sound_trigger_hw.h
@@ -30,15 +30,16 @@
 /* Model index */
 #define MAX_SOUND_MODELS    2
 #define HOTWORD_INDEX       0
-#define ODMVOICE_INDEX      1
+#define SVOICE_INDEX        1
 #define HANDLE_NONE         -1
 
-#define MODEL_CONTROL_COUNT     3
+#define MODEL_START_CONTROL_COUNT       3
+#define MODEL_STOP_CONTROL_COUNT        2
 #define MODEL_BACKLOG_CONTROL_COUNT     1
 
 static const struct sound_trigger_properties hw_properties = {
     "Samsung SLSI", // implementor
-    "Exynos Primary SoundTrigger HAL, OK Google and ODMVoice", // description
+    "Exynos Primary SoundTrigger HAL, OK Google and SVoice", // description
     1, // version
     { 0x1817de20, 0xfa3b, 0x11e5, 0xbef2, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
     2, // max_sound_models
@@ -52,6 +53,25 @@
     0 // power_consumption_mw
 };
 
+static struct sound_trigger_properties_extended_1_3 hw_properties_1_3 = {
+    {SOUND_TRIGGER_DEVICE_API_VERSION_1_3, 320}, // API version, rough total size
+    {"Samsung SLSI", // implementor
+    "Exynos Primary SoundTrigger HAL", // description
+    1, // version
+    { 0x1817de20, 0xfa3b, 0x11e5, 0xbef2, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
+    2, // max_sound_models
+    1, // max_key_phrases
+    1, // max_users
+    RECOGNITION_MODE_VOICE_TRIGGER, // recognition_modes
+    true, // capture_transition
+    0, // max_buffer_ms
+    false, // concurrent_capture
+    false, // trigger_in_event
+    0}, // power_consumption_mw
+    "374236809, 4ac4bfe8-a4c9-3f5c-8f02-6db7c7123cb6", // supportedModelArch
+    0 // audioCapabilities
+};
+
 typedef enum {
        VTS_MAIN_MIC         = 0,    //Main mic
        VTS_HEADSET_MIC      = 1,    //Headset mic
@@ -63,22 +83,22 @@
 }VTS_RECOGNIZE_STATE;
 
 typedef enum {
-       ODMVOICE_UNKNOWN_MODE			= 0,    //None
-       ODMVOICE_RESERVED1_MODE			= 1,    //Reserved1 mode
-       ODMVOICE_RESERVED2_MODE			= 2,    //Reserved2 mode
-       ODMVOICE_TRIGGER_MODE			= 3,    //ODM voice trigger mode
-}ODMVOICE_MODEL_MODE;
+       SVOICE_UNKNOWN_MODE          = 0,    //None
+       SVOICE_BIXBY_MODE            = 1,    //Bixby (LPSD + voice trigger)
+       SVOICE_LPSD_MODE             = 2,    //LPSD (babycry/doorbell)
+       SVOICE_BIXBY_ALWAYS_MODE     = 3,    //Bixby (LPSD + voice trigger)
+}SVOICE_MODEL_MODE;
 
 typedef enum {
        VTS_MODE_OFF                     = 0,    //default is off
-       VTS_MODE_RESERVED1_ON            = 1,    // ODM specific trigger mode1
-       VTS_MODE_RESERVED2_ON            = 2,    //ODM specific trigger mode2
-       VTS_MODE_ODMVOICE_TRIGGER_ON     = 3,    //ODM key phrase Detection (Trigger)
-       VTS_MODE_GOOGLE_TRIGGER_ON       = 4,    //Google key phrase Detection (Trigger)
-       VTS_MODE_SENSORY_TRIGGER_ON      = 5,    //sensory key phrase Detection (Trigger)
-       VTS_MODE_RESERVED1_OFF           = 6,    //OFF: ODM specific trigger mode1
-       VTS_MODE_RESERVED2_OFF           = 7,    //OFF: ODM specific trigger mode2
-       VTS_MODE_ODMVOICE_TRIGGER_OFF    = 8,    //OFF: ODM key phrase Detection (Trigger)
+       VTS_MODE_VOICE_TRIGGER_ON        = 1,    //Both LPSD & Trigger are enabled (Voice trigger mode)
+       VTS_MODE_SOUND_DETECT_ON         = 2,    //Low Power sound Detect only(Babycrying mode)
+       VTS_MODE_VT_ALWAYS_ON            = 3,    //VTS key phrase Detection only(Trigger)
+       VTS_MODE_GOOGLE_TRIGGER_ON       = 4,    //Google key phrase Detection only(Trigger)
+       VTS_MODE_SENSORY_TRIGGER_ON      = 5,    //sensory key phrase Detection only(Trigger)
+       VTS_MODE_VOICE_TRIGGER_OFF       = 6,    //OFF: Both LPSD & Trigger are enabled (Voice trigger mode)
+       VTS_MODE_SOUND_DETECT_OFF        = 7,    //OFF: Low Power sound Detect only(Babycrying mode)
+       VTS_MODE_VT_ALWAYS_OFF           = 8,    //OFF: VTS key phrase Detection only(Trigger)
        VTS_MODE_GOOGLE_TRIGGER_OFF      = 9,    //OFF: Google key phrase Detection
        VTS_MODE_SENSORY_TRIGGER_OFF     = 10,    //OFF: sensory key phrase Detection
        VTS_MODE_COUNT,
@@ -123,46 +143,44 @@
     "VTS VoiceTrigger Value",
 };
 
+// Delete Trigger Value setting in the stop control
+// : unnecessary and can cause abnormal operation of the firmware
 char *model_recognize_stop_ctlname[] = {
     "VTS Active Keyphrase",
-    "VTS VoiceTrigger Value",
     "VTS VoiceRecognization Mode",
 };
 
-int odmvoice_reserved1recognize_start_ctlvalue[] = {
+int svoice_bixbyrecognize_start_ctlvalue[] = {
     0,  //"VTS Active Keyphrase",
-    VTS_MODE_RESERVED1_ON,  //"VTS Execution Mode",
+    VTS_MODE_VOICE_TRIGGER_ON,  //"VTS Execution Mode",
     1800, //back log size from trigger point
 };
 
-int odmvoice_reserved1recognize_stop_ctlvalue[] = {
+int svoice_bixbyrecognize_stop_ctlvalue[] = {
     0, //"VTS Active Keyphrase",
-    0, //back log size from trigger point
-    VTS_MODE_RESERVED1_OFF, //"VTS Execution Mode",
+    VTS_MODE_VOICE_TRIGGER_OFF, //"VTS Execution Mode",
 };
 
-int odmvoice_reserved2recognize_start_ctlvalue[] = {
+int svoice_lpsdrecognize_start_ctlvalue[] = {
     0,  //"VTS Active Keyphrase",
-    VTS_MODE_RESERVED2_ON,  //"VTS Execution Mode",
+    VTS_MODE_SOUND_DETECT_ON,  //"VTS Execution Mode",
     0, //back log size from trigger point
 };
 
-int odmvoice_reserved2recognize_stop_ctlvalue[] = {
+int svoice_lpsdrecognize_stop_ctlvalue[] = {
     0, //"VTS Active Keyphrase",
-    0, //back log size from trigger point
-    VTS_MODE_RESERVED2_OFF, //"VTS Execution Mode",
+    VTS_MODE_SOUND_DETECT_OFF, //"VTS Execution Mode",
 };
 
-int odmvoice_triggerrecognize_start_ctlvalue[] = {
+int svoice_bixbyalwaysrecognize_start_ctlvalue[] = {
     0,  //"VTS Active Keyphrase",
-    VTS_MODE_ODMVOICE_TRIGGER_ON,  //"VTS Execution Mode",
+    VTS_MODE_VT_ALWAYS_ON,  //"VTS Execution Mode",
     1800, //back log size from trigger point
 };
 
-int odmvoice_triggerrecognize_stop_ctlvalue[] = {
+int svoice_bixbyalwaysrecognize_stop_ctlvalue[] = {
     0, //"VTS Active Keyphrase",
-    0, //back log size from trigger point
-    VTS_MODE_ODMVOICE_TRIGGER_ON, //"VTS Execution Mode",
+    VTS_MODE_VT_ALWAYS_OFF, //"VTS Execution Mode",
 };
 
 int hotword_recognize_start_ctlvalue[] = {
@@ -173,7 +191,6 @@
 
 int hotword_recognize_stop_ctlvalue[] = {
     1, //"VTS Active Keyphrase",
-    0, //back log size from trigger point
     VTS_MODE_GOOGLE_TRIGGER_OFF, //"VTS Execution Mode",
 };
 
@@ -195,6 +212,8 @@
     void *sound_model_cookies[MAX_SOUND_MODELS];
     pthread_t callback_thread;
     pthread_mutex_t lock;
+    pthread_mutex_t trigger_lock;
+    pthread_mutex_t recording_lock;
     int send_socket;
     int term_socket;
     int uevent_socket;
@@ -221,12 +240,13 @@
     struct pcm *recording_pcm;
 
     int backlog_size;
-    int odmvoicemodel_mode;
+    int svoicemodel_mode;
 
     int voicecall_state;
     int recog_cbstate;
     int model_execstate[MAX_SOUND_MODELS];
     sound_model_handle_t model_stopfailedhandles[MAX_SOUND_MODELS];
+    int is_generic;
 };
 
 #endif  // __EXYNOS_SOUNDTRIGGERHAL_H__
diff --git a/libaudio/sthal/test/Android.mk b/libaudio/sthal/test/Android.mk
index 052b1fc..d74fe54 100644
--- a/libaudio/sthal/test/Android.mk
+++ b/libaudio/sthal/test/Android.mk
@@ -15,7 +15,6 @@
 #
 # VTS Unit Test Console application
 #
-ifeq ($(BOARD_USE_SOUNDTRIGGER_HAL), STHAL_TEST)
 LOCAL_PATH := $(call my-dir)
 
 include $(CLEAR_VARS)
@@ -27,10 +26,8 @@
 
 LOCAL_C_INCLUDES += \
     external/tinyalsa/include \
-    $(TOP)/hardware/samsung_slsi-linaro/exynos/libaudio/sthal
-
-LOCAL_C_INCLUDES += \
-    $(TOP)/device/samsung/$(TARGET_BOOTLOADER_BOARD_NAME)/conf
+    $(TOP)/hardware/samsung_slsi/modules/libaudio/sthal \
+    $(TOP)/device/samsung/$(PRODUCT_DEVICE)/conf
 
 LOCAL_SHARED_LIBRARIES := \
     liblog \
@@ -43,7 +40,4 @@
 LOCAL_CFLAGS += -DMMAP_INTERFACE_ENABLED
 endif
 
-LOCAL_MODULE_TAGS := optional
-
 include $(BUILD_EXECUTABLE)
-endif
diff --git a/libaudio/sthal/test/vts_hw_test.c b/libaudio/sthal/test/vts_hw_test.c
index e14c0fe..fd2f717 100644
--- a/libaudio/sthal/test/vts_hw_test.c
+++ b/libaudio/sthal/test/vts_hw_test.c
@@ -43,8 +43,10 @@
 
 #include"sound_trigger_hw.h"
 #ifdef MMAP_INTERFACE_ENABLED
-#include"vts.h"
+#include "vts.h"
+#include "soundtrigger_conf.h"
 #endif
+#include "soundtrigger_play_conf.h"
 
 #define UEVENT_MSG_LEN          64*1024
 
@@ -59,39 +61,67 @@
 } VTS_RECORD_STATE;
 
 typedef enum {
-    VTS_RESERVED2_STOPPED_STATE,
-    VTS_RESERVED2_STARTED_STATE,
-} VTS_ODMRSVD2_STATE;
+    VTS_LPSD_STOPPED_STATE,
+    VTS_LPSD_STARTED_STATE,
+} VTS_LPSD_STATE;
+
+typedef enum {
+    VTS_PLAY_STOPPED_STATE,
+    VTS_PLAY_STARTED_STATE,
+} VTS_PLAY_STATE;
+
+typedef enum {
+    PLAY_BACK_STOPPED_STATE,
+    PLAY_BACK_STARTED_STATE,
+} PLAY_BACK_STATE;
 
 typedef enum {
     VTS_TRIGGERED_CAPTURE,
     VTS_NORMAL_CAPTURE,
 } VTS_CAP_MODE;
 
+typedef enum {
+    BIXBY_MODEL = 1,
+    GOOGLE_MODEL
+} VTS_MODEL_TYPE;
+
 /* Sound model binaries */
 #define SOUND_MODEL_OKGOOGLE_BINARY         "/data/voice_dva_okgoogle.bin"
-#define SOUND_MODEL_ODMVOICE_BINARY           "/data/voice_dva_odmvoice.bin"
+#define SOUND_MODEL_SVOICE_BINARY           "/data/voice_dva_svoice.bin"
 
 #define VTS_TRIGGER_CAPTURE_OUTPUT  "/sdcard/vts-trigger-cap.wav"
 #define VTS_NORMAL_CAPTURE_OUTPUT  "/sdcard/vts-normal-cap.wav"
 
 #define VTS_STREAMING_BUFFER_SIZE  4800 //(4 * 1024)
-#define NUM_OF_SAMPLES_TO_CAPTURE 100
+#define PLAY_BACK_BUFFER_SIZE VTS_STREAMING_BUFFER_SIZE*2
+#define NUM_OF_SAMPLES_TO_CAPTURE 10
+#define LOOPBACK_BUFFER_SIZE VTS_STREAMING_BUFFER_SIZE*NUM_OF_SAMPLES_TO_CAPTURE
+
+char * loopback_stream;
 
 struct vts_hw_device {
     VTS_HW_STATE vts_state;
     VTS_RECORD_STATE vts_rec_state;
-    VTS_ODMRSVD2_STATE vts_odmrsvd2_state;
+    VTS_LPSD_STATE vts_lpsd_state;
+    PLAY_BACK_STATE play_back_state;
+    VTS_MODEL_TYPE vts_model_type;
     pthread_mutex_t lock;
     int send_sock;
     int term_sock;
     bool thread_exit;
     bool rec_thread_exit;
-    bool odmrsvd2_thread_exit;
+    bool play_thread_exit;
+    bool lpsd_thread_exit;
     pthread_t callback_thread;
     pthread_t rec_thread;
-    pthread_t odmrsvd2_thread;
-    bool model_loaded;
+    pthread_t play_thread;
+    pthread_t lpsd_thread;
+    bool start_loopback_play;
+    int model_loaded;
+
+    VTS_PLAY_STATE vts_play_state;
+    bool vts_play_thread_exit;
+    pthread_t vts_play_thread;
 };
 
 #define ID_RIFF 0x46464952
@@ -125,9 +155,23 @@
 void *mapped_addr = NULL;
 #endif
 
+enum state {
+    MENU_START_BIXBY_RECOGNITION = 1,
+    MENU_START_GOOGLE_RECOGNITION,
+    MENU_STOP_RECOGNITION,
+    MENU_START_RECORD,
+    MENU_STOP_RECORD,
+    MENU_START_PLAY,
+    MENU_STOP_PLAY,
+    MENU_START_PLAYBACK,
+    MENU_STOP_PLAYBACK,
+    MENU_EXIT
+};
+
 void vts_recognition_stop(struct vts_hw_device *vts_dev);
-void vts_odmrsvd2_stop(struct vts_hw_device *vts_dev);
+void vts_lpsd_stop(struct vts_hw_device *vts_dev);
 void vts_record_stop(struct vts_hw_device *vts_dev);
+void playback_stop(struct vts_hw_device *vts_dev);
 
 static int dmic_usagecnt = 0;
 
@@ -141,9 +185,10 @@
 {
     int i = (reverse ? (ctrl_count - 1): 0);
     int ret = 0;
+    int temp[2] = {1,1};
     struct mixer_ctl *mixerctl = NULL;
 
-    printf("%s, path: %s", __func__, path_name[0]);
+    printf("%s, path: %s \n", __func__, path_name[0]);
 
     if (mixer_handle) {
         //for (i=0; i < ctrl_count; i++) {
@@ -181,12 +226,67 @@
         printf("%s: Failed to open mixer\n", __func__);
         return -EINVAL;
     }
-
     return ret;
 }
 
+int set_mixer_ctrls_array(
+        struct mixer *mixer_handle,
+        char *path_name[],
+        int *path_ctlvalue[],
+        int ctrl_count,
+        bool reverse,
+        int value_cnt[])
+{
+    int i = (reverse ? (ctrl_count - 1): 0);
+    int j = 0;
+    int ret = 0;
+    int buf[3];
+    struct mixer_ctl *mixerctl = NULL;
+
+    printf("%s, path: %s\n", __func__, path_name[0]);
+
+    if (mixer_handle) {
+        while(ctrl_count) {
+            //printf("%s, ctrl_count: %d Loop index: %d", __func__, ctrl_count, i);
+            /* Get required control from mixer */
+            mixerctl = mixer_get_ctl_by_name(mixer_handle, path_name[i]);
+            if (mixerctl) {
+                printf("value count : %d \n", value_cnt[i]);
+                for(j = 0; j<value_cnt[i]; j++){
+                    buf[j] = path_ctlvalue[i][j];
+                }
+                /* Enable the control */
+                ret = mixer_ctl_set_array(mixerctl, buf, value_cnt[i]);
+                if (ret) {
+                    printf("%s: %s Failed to configure\n", __func__, path_name[i]);
+                    ret = -EINVAL;
+                    break;
+                } else {
+                    for(j = 0; j<value_cnt[i]; j++){
+                        printf("%s: %s %d configured value: %d\n", __func__, path_name[i],j,buf[j]);
+                    }
+                }
+             } else {
+                printf("%s: %s control doesn't exist\n", __func__, path_name[i]);
+                ret = -EINVAL;
+                break;
+            }
+            ctrl_count--;
+            if (reverse)
+                i--;
+            else
+                i++;
+        }
+    } else {
+        printf("%s: Failed to open mixer\n", __func__);
+        return -EINVAL;
+    }
+    return ret;
+}
+
+
 #ifdef MMAP_INTERFACE_ENABLED
-static void load_modelbinary(char *data, int len)
+static void load_modelbinary(char *data, int len, int model)
 {
     printf("%s: Size: %d\n", __func__, len);
 
@@ -199,11 +299,16 @@
         printf("%s: MMAP buffer overflow Model Binary size greater then mapped size !!!\n", __func__);
     }
 
-    /* Update model binary inforation to VTS misc driver */
-    if (ioctl(vtsdev_fd, VTSDRV_MISC_IOCTL_WRITE_ODMVOICE, &len) < 0) {
-        printf("%s: Failed to update model binary size\n", __func__);
+    if(model == BIXBY_MODEL) {
+        /* Update model binary inforation to VTS misc driver */
+        if (ioctl(vtsdev_fd, VTSDRV_MISC_IOCTL_WRITE_SVOICE, &len) < 0) {
+            printf("%s: Failed to update model binary size\n", __func__);
+        }
+    } else {
+        if (ioctl(vtsdev_fd, VTSDRV_MISC_IOCTL_WRITE_GOOGLE, &len) < 0) {
+            printf("%s: Failed to update model binary size\n", __func__);
+        }
     }
-
     return;
 }
 #endif
@@ -235,6 +340,66 @@
     return;
 }
 
+int set_playback_dmic_ctrls(int flag)
+{
+    int ret = EXIT_SUCCESS;
+    char **active_spkc_ctrls = NULL;
+    int *ctrl_spk_values = NULL;
+    char **not_active_spkc_ctrls = NULL;
+    int *not_ctrl_spk_values = NULL;
+
+    char **active_spkc_array_ctrls = NULL;
+    int **ctrl_spk_array_values = NULL;
+    char **not_active_array_spkc_ctrls = NULL;
+    int **not_ctrl_spk_array_values = NULL;
+    int *ctrl_spk_array_cnt = NULL;
+    if (vtsMixerHandle) {
+        if (!flag) {
+            if (dmic_usagecnt) {
+                dmic_usagecnt--;
+                printf("Dmic Disabled usage count %d \n", dmic_usagecnt);
+            } else {
+                printf("Dmic usage count is Zero \n");
+                return ret;
+            }
+            not_active_array_spkc_ctrls = headset_spk_ctlname_arry;
+            not_ctrl_spk_array_values = headset_spk_not_ctlvalue_arry;
+            ctrl_spk_array_cnt = headset_spk_ctlvalue_cnt_arry;
+            if (set_mixer_ctrls_array(vtsMixerHandle, not_active_array_spkc_ctrls, not_ctrl_spk_array_values, MAIN_SPKC_CONTROL_ARRAY_COUNT, !flag, ctrl_spk_array_cnt)) {
+                printf("%s: %s SPK Array dis control configuration Failed", __func__, flag ? "Enabling" : "Disabling");
+                mixer_close(vtsMixerHandle);
+                vtsMixerHandle = NULL;
+                return -EINVAL;
+            }
+            printf("%s: %s SPK Array dis Controls ", __func__, flag ? "Enable" : "Disable");
+        } else {
+            if (!dmic_usagecnt) {
+                active_spkc_ctrls = headset_spk_ctlname;
+                ctrl_spk_values = headset_spk_ctlvalue;
+                if (set_mixer_ctrls(vtsMixerHandle, active_spkc_ctrls, ctrl_spk_values, MAIN_SPKC_CONTROL_COUNT, !flag)) {
+                    printf("%s: %s SPK control configuration Failed", __func__, flag ? "Enabling" : "Disabling");
+                    mixer_close(vtsMixerHandle);
+                    vtsMixerHandle = NULL;
+                    return -EINVAL;
+                 }
+                 printf("%s: %s SPK Controls ", __func__, flag ? "Enable" : "Disable");
+
+                 active_spkc_array_ctrls = headset_spk_ctlname_arry;
+                 ctrl_spk_array_values = headset_spk_ctlvalue_arry;
+                 ctrl_spk_array_cnt = headset_spk_ctlvalue_cnt_arry;
+                 if (set_mixer_ctrls_array(vtsMixerHandle, active_spkc_array_ctrls, ctrl_spk_array_values, MAIN_SPKC_CONTROL_ARRAY_COUNT, !flag, ctrl_spk_array_cnt)) {
+                     printf("%s: %s SPK Array control configuration Failed", __func__, flag ? "Enabling" : "Disabling");
+                     mixer_close(vtsMixerHandle);
+                     vtsMixerHandle = NULL;
+                     return -EINVAL;
+                 }
+                printf("%s: %s SPK Array Controls ", __func__, flag ? "Enable" : "Disable");
+            }
+        }
+    }
+    return ret;
+}
+
 int set_dmic_ctrls(int flag)
 {
     int i;
@@ -283,27 +448,29 @@
 {
     if (vts_dev->vts_state == VTS_RECOGNITION_STARTED_STATE) {
         vts_recognition_stop(vts_dev);
-    } else if (vts_dev->vts_odmrsvd2_state == VTS_RESERVED2_STARTED_STATE) {
-        vts_odmrsvd2_stop(vts_dev);
+    } else if (vts_dev->vts_lpsd_state == VTS_LPSD_STARTED_STATE) {
+        vts_lpsd_stop(vts_dev);
     } else if (vts_dev->vts_rec_state == VTS_RECORD_STARTED_STATE) {
         vts_record_stop(vts_dev);
+    } else if (vts_dev->play_back_state == PLAY_BACK_STARTED_STATE) {
+        playback_stop(vts_dev);
+    } else {
+        printf("Is is not in any state\n");
     }
-
     printf("%s: Exit \n", __func__);
     return;
 }
 
 static void vts_close_term_sock(struct vts_hw_device *vts_dev)
 {
-    if (vts_dev->send_sock >=0) {
+    if (vts_dev->send_sock >= 0) {
         close(vts_dev->send_sock);
         vts_dev->send_sock = -1;
     }
-    if (vts_dev->term_sock >=0) {
+    if (vts_dev->term_sock >= 0) {
         close(vts_dev->term_sock);
         vts_dev->term_sock = -1;
     }
-
     return;
 }
 
@@ -311,7 +478,7 @@
 static int fetch_streaming_buffer(struct vts_hw_device *vts_dev, int cap_mode)
 {
     int ret = 0;
-    unsigned int flags, frames;
+    unsigned int flags, flags_out, frames;
     int i = 0;
     struct pcm *vcap_pcm = NULL;
     FILE *out_vcap_fp = NULL;
@@ -340,6 +507,9 @@
         vcap_pcm = pcm_open(VTS_SOUND_CARD, pcmnode, flags, &pcmconfig);
         if (vcap_pcm && !pcm_is_ready(vcap_pcm)) {
             printf("%s - FAILED to open VTS PCM Node : %d\n", __func__, pcmnode);
+            /* Release VTS capture node */
+            pcm_close(vcap_pcm);
+            vcap_pcm = NULL;
             goto out;
         }
 
@@ -374,7 +544,8 @@
             /* leave enough room for header */
             fseek(out_vcap_fp, sizeof(struct wav_header), SEEK_SET);
 
-            for (i=0; i < NUM_OF_SAMPLES_TO_CAPTURE; i++) {
+            i = 0;
+            while(1) {
                 ret = pcm_read(vcap_pcm, (void*)streaming_buf, (unsigned int)VTS_STREAMING_BUFFER_SIZE);
                 if (ret == 0) {
                     printf("%s - Captured %d samples\n", __func__, VTS_STREAMING_BUFFER_SIZE);
@@ -388,6 +559,7 @@
                 if ((cap_mode == VTS_TRIGGERED_CAPTURE && vts_dev->thread_exit == true) ||
                     (cap_mode == VTS_NORMAL_CAPTURE && vts_dev->rec_thread_exit == true))
                     break;
+                i++;
             }
         }
 
@@ -443,7 +615,7 @@
 
     memset(fds, 0, 2 * sizeof(struct pollfd));
     fds[0].events = POLLIN;
-    fds[0].fd = uevent_open_socket(64*1024, true);
+    fds[0].fd = uevent_open_socket(64 * 1024, true);
     //fds[0].fd = vts_dev->term_sock;
     if (fds[0].fd == -1) {
         printf("Error opening socket for hotplug uevent");
@@ -471,11 +643,18 @@
                 if (strstr(msg + i, "VOICE_WAKEUP_WORD_ID=1")) {
                     printf("%s VTS Trigger received for model %s\n", __func__, (msg+i));
                     /* Start reading data from the VTS IP */
-                        fetch_streaming_buffer(vts_dev, VTS_TRIGGERED_CAPTURE);
+                    fetch_streaming_buffer(vts_dev, VTS_TRIGGERED_CAPTURE);
                     printf("\n%s Want to Continue...then Start Recognitoin again\n", __func__);
                     goto found;
-                 }
-                 i += strlen(msg + i) + 1;
+                }
+                else if (strstr(msg + i, "VOICE_WAKEUP_WORD_ID=2")) {
+                    printf("%s VTS Trigger received for model %s\n", __func__, (msg+i));
+                    /* Start reading data from the VTS IP */
+                    fetch_streaming_buffer(vts_dev, VTS_TRIGGERED_CAPTURE);
+                    printf("\n%s Want to Continue...then Start Recognitoin again\n", __func__);
+                    goto found;
+                }
+                i += strlen(msg + i) + 1;
             }
 #if EN_DEBUG
             if (i >= n) {
@@ -508,39 +687,48 @@
         /* once callback thread is closed set vts_stop using sysfs */
         /* Set active keyphrase for voice recognition */
         set_mixer_ctrls(vtsMixerHandle, model_recognize_stop_ctlname,
-                odmvoice_triggerrecognize_stop_ctlvalue, MODEL_CONTROL_COUNT, false);
+                svoice_bixbyrecognize_stop_ctlvalue, MODEL_STOP_CONTROL_COUNT, false);
         vts_dev->vts_state = VTS_RECOGNITION_STOPPED_STATE;
         /* reset DMIC controls */
         set_dmic_ctrls(false);
+        set_playback_dmic_ctrls(false);
     }
     vts_dev->thread_exit = false;
     printf("%s: Exit \n", __func__);
     return (void *)(long)err;
 }
 
-void vts_recognition_start(struct vts_hw_device *vts_dev)
+void vts_recognition_start(struct vts_hw_device *vts_dev, int model)
 {
     int ret = 0;
+    char model_bin[50];
+    vts_dev->vts_model_type = model;
+
+    if(model == BIXBY_MODEL)
+        strcpy(model_bin, SOUND_MODEL_SVOICE_BINARY);
+    else
+        strcpy(model_bin, SOUND_MODEL_OKGOOGLE_BINARY);
+
     pthread_mutex_lock(&vts_dev->lock);
     if (vts_dev->vts_state == VTS_RECOGNITION_STOPPED_STATE) {
-        if (!vts_dev->model_loaded ) {
-            FILE *pfile = NULL;
+		if(!(vts_dev->model_loaded & (0x1 << model))) {
+			FILE *pfile = NULL;
             int rd_sz, bin_sz;
             char * data = NULL;
             /* Read model net binay file*/
-            pfile = fopen(SOUND_MODEL_ODMVOICE_BINARY, "rb+");
+            pfile = fopen(model_bin, "rb+");
             if (!pfile) {
                 printf("Model Binary voice_dva_svoice.bin should be copied to \\data\\firmware folder \n");
-                printf("Failed to Open Model Binary from [%s]\n", SOUND_MODEL_ODMVOICE_BINARY);
+                printf("Failed to Open Model Binary from [%s]\n", model_bin);
                 goto error;
             } else {
-                printf("Successfully [%s] file opened!! \n", SOUND_MODEL_ODMVOICE_BINARY);
+                printf("Successfully [%s] file opened!! \n", model_bin);
             }
 
             fseek(pfile, 0L, SEEK_END);
             bin_sz = ftell(pfile);
             fseek(pfile, 0L, SEEK_SET);
-            printf(" Model %s File size %d \n", SOUND_MODEL_ODMVOICE_BINARY, bin_sz);
+            printf(" Model %s File size %d \n", model_bin, bin_sz);
 
             data = (char *)calloc(1, bin_sz);
             if (!data) {
@@ -552,21 +740,25 @@
             rd_sz = fread(data, 1, bin_sz, pfile);
 
             if (rd_sz != bin_sz) {
-                printf("%s -  Failed to read data from %s file\n", __func__, SOUND_MODEL_ODMVOICE_BINARY);
+                printf("%s -  Failed to read data from %s file\n", __func__, model_bin);
                 fclose(pfile);
+                free(data);
                 goto error;
             }
 
             /* Load net binary to VTS driver */
 #ifdef MMAP_INTERFACE_ENABLED
-            load_modelbinary(data, rd_sz);
+            load_modelbinary(data, rd_sz, model);
 #else
-            sysfs_write(VTS_SVOICE_MODEL, data, rd_sz);
+            if(model == BIXBY_MODEL)
+                sysfs_write(VTS_SVOICE_MODEL, data, rd_sz);
+            else
+                sysfs_write(VTS_HOTWORD_MODEL, data, rd_sz);
 #endif
 
             fclose(pfile);
             free(data);
-            vts_dev->model_loaded = true;
+            vts_dev->model_loaded |= (0x1 << model);
         }
 
         /* configure DMIC controls */
@@ -577,14 +769,17 @@
         pthread_create(&vts_dev->callback_thread, (const pthread_attr_t *) NULL,
                             callback_thread_loop, vts_dev);
 
-        set_mixer_ctrls(vtsMixerHandle, model_recognize_start_ctlname,
-                odmvoice_triggerrecognize_start_ctlvalue, MODEL_CONTROL_COUNT, false);
+        if(model == BIXBY_MODEL)
+            set_mixer_ctrls(vtsMixerHandle, model_recognize_start_ctlname,
+                svoice_bixbyrecognize_start_ctlvalue, MODEL_START_CONTROL_COUNT, false);
+        else
+            set_mixer_ctrls(vtsMixerHandle, model_recognize_start_ctlname,
+                hotword_recognize_start_ctlvalue, MODEL_START_CONTROL_COUNT, false);
 
         vts_dev->vts_state = VTS_RECOGNITION_STARTED_STATE;
     } else {
         printf("VTS Voice Recognition already running \n");
     }
-
 error:
     pthread_mutex_unlock(&vts_dev->lock);
     printf("%s: Exit Tar-size 1000ms\n", __func__);
@@ -606,8 +801,12 @@
 
         pthread_mutex_lock(&vts_dev->lock);
 
-        set_mixer_ctrls(vtsMixerHandle, model_recognize_stop_ctlname,
-                odmvoice_triggerrecognize_stop_ctlvalue, MODEL_CONTROL_COUNT, false);
+        if(vts_dev->vts_model_type == BIXBY_MODEL)
+            set_mixer_ctrls(vtsMixerHandle, model_recognize_stop_ctlname,
+                svoice_bixbyrecognize_stop_ctlvalue, MODEL_STOP_CONTROL_COUNT, false);
+        else
+            set_mixer_ctrls(vtsMixerHandle, model_recognize_stop_ctlname,
+                hotword_recognize_stop_ctlvalue, MODEL_STOP_CONTROL_COUNT, false);
 
         /* configure DMIC controls */
         set_dmic_ctrls(false);
@@ -631,7 +830,7 @@
     prctl(PR_SET_NAME, (unsigned long)"VTSRecord", 0, 0, 0);
 
     printf("%s Started!!\n", __func__);
-    fetch_streaming_buffer(vts_dev, VTS_NORMAL_CAPTURE);
+    fetch_streaming_buffer(vts_dev, VTS_NORMAL_CAPTURE); // VTS_TRIGGERED_CAPTURE,VTS_NORMAL_CAPTURE
 
     vts_dev->vts_rec_state = VTS_RECORD_STOPPED_STATE;
 
@@ -688,8 +887,8 @@
     return;
 }
 
-/******** VTS ODM Reserved2 Mode support function ***************/
-static void *odmrsvd2_thread_loop(void * context)
+/******** VTS LPSD (BabyCrying) Mode support function ***************/
+static void *lpsd_thread_loop(void * context)
 {
     char msg[UEVENT_MSG_LEN];
     struct pollfd fds[2];
@@ -698,23 +897,23 @@
     int i, n;
     struct vts_hw_device *vts_dev = (struct vts_hw_device *)context;
 
-    prctl(PR_SET_NAME, (unsigned long)"VTSODMReserved2Mode", 0, 0, 0);
+    prctl(PR_SET_NAME, (unsigned long)"VTSLPSD", 0, 0, 0);
 
     printf("%s Started!!\n", __func__);
 
     memset(fds, 0, 2 * sizeof(struct pollfd));
     fds[0].events = POLLIN;
-    fds[0].fd = uevent_open_socket(64*1024, true);
+    fds[0].fd = uevent_open_socket(64 * 1024, true);
     if (fds[0].fd == -1) {
         printf("Error opening socket for hotplug uevent");
         goto func_exit;
     }
 
     while (1) {
-        printf("%s: ODMReserved2Mode Before poll \n", __func__);
-        /* wait for VTS ODMReserved2Mode Uevent */
+        printf("%s: LPSD Before poll \n", __func__);
+        /* wait for VTS LPSD Uevent */
         err = poll(fds, 1, 10000);
-        printf("%s: ODMReserved2Mode After poll \n", __func__);
+        printf("%s: LPSD After poll \n", __func__);
 
         if (fds[0].revents & POLLIN) {
             n = uevent_kernel_multicast_recv(fds[0].fd, msg, UEVENT_MSG_LEN);
@@ -723,9 +922,9 @@
                 continue;
             }
 
-            for (i=0; i < n;) {
-                if (strstr(msg + i, "VOICE_WAKEUP_WORD_ID=3")) {
-                    printf("%s VTS ODMReserved2Mode UEVENT received %s\n", __func__, (msg+i));
+            for (i = 0; i < n;) {
+                if (strstr(msg + i, "VOICE_WAKEUP_WORD_ID=LPSD")) {
+                    printf("%s VTS LPSD UEVENT received %s\n", __func__, (msg + i));
                     goto found;
                  }
                  i += strlen(msg + i) + 1;
@@ -733,112 +932,773 @@
 #if EN_DEBUG
             if (i >= n) {
                 i = 0;
-                printf("%s ODMReserved2Mode UEVENT MSG INFO: \n", __func__);
+                printf("%s LPSD UEVENT MSG INFO: \n", __func__);
                 while (i < n) {
-                    printf("%s \n", (msg+i));
-                    i += strlen(msg+i)+1;
+                    printf("%s \n", (msg + i));
+                    i += strlen(msg + i) + 1;
                 }
             }
 #else
             if (i >= n)
-                printf("%s Received UEVENT is NOT ODMReserved2Mode event !!\n", __func__);
+                printf("%s Received UEVENT is NOT LPSD event !!\n", __func__);
 #endif
          }  else {
             printf("%s: Poll returned %d\n", __func__, err);
         }
-        if (vts_dev->odmrsvd2_thread_exit == true)
+        if (vts_dev->lpsd_thread_exit == true)
             break;
     }
 
 found:
     close(fds[0].fd);
 func_exit:
-    if (vts_dev->odmrsvd2_thread_exit == false) {
+    if (vts_dev->lpsd_thread_exit == false) {
         /* once callback thread is closed set vts_stop using sysfs */
         set_mixer_ctrls(vtsMixerHandle, model_recognize_stop_ctlname,
-                odmvoice_reserved2recognize_stop_ctlvalue, MODEL_CONTROL_COUNT, false);
+                svoice_lpsdrecognize_stop_ctlvalue, MODEL_STOP_CONTROL_COUNT, false);
 
-        vts_dev->vts_odmrsvd2_state = VTS_RESERVED2_STOPPED_STATE;
+        vts_dev->vts_lpsd_state = VTS_LPSD_STOPPED_STATE;
 
         /* reset DMIC controls */
         set_dmic_ctrls(false);
     }
 
-    vts_dev->odmrsvd2_thread_exit = false;
+    vts_dev->lpsd_thread_exit = false;
     printf("%s: Exit \n", __func__);
     return (void *)(long)err;
 }
 
-void vts_odmrsvd2_start(struct vts_hw_device *vts_dev)
+void vts_lpsd_start(struct vts_hw_device *vts_dev)
 {
     pthread_mutex_lock(&vts_dev->lock);
-    if (vts_dev->vts_odmrsvd2_state == VTS_RESERVED2_STOPPED_STATE) {
-        /* Create odmrsvd2 thread to wait on uevent from VTS IP*/
-        vts_dev->odmrsvd2_thread_exit = false;
-        pthread_create(&vts_dev->odmrsvd2_thread, (const pthread_attr_t *) NULL,
-                            odmrsvd2_thread_loop, vts_dev);
+    if (vts_dev->vts_lpsd_state == VTS_LPSD_STOPPED_STATE) {
+        /* Create lpsd thread to wait on uevent from VTS IP*/
+        vts_dev->lpsd_thread_exit = false;
+        pthread_create(&vts_dev->lpsd_thread, (const pthread_attr_t *) NULL,
+                            lpsd_thread_loop, vts_dev);
 
         /* configure DMIC controls */
         set_dmic_ctrls(true);
 
         set_mixer_ctrls(vtsMixerHandle, model_recognize_start_ctlname,
-                        odmvoice_reserved2recognize_start_ctlvalue, MODEL_CONTROL_COUNT, false);
+                        svoice_lpsdrecognize_start_ctlvalue, MODEL_START_CONTROL_COUNT, false);
 
-        vts_dev->vts_odmrsvd2_state = VTS_RESERVED2_STARTED_STATE;
+        vts_dev->vts_lpsd_state = VTS_LPSD_STARTED_STATE;
     } else {
-        printf("VTS ODMRsvd2 Already started \n");
+        printf("VTS LPSD (BabyCrying) Already started \n");
     }
     pthread_mutex_unlock(&vts_dev->lock);
     printf("%s: Exit \n", __func__);
     return;
 }
 
-void vts_odmrsvd2_stop(struct vts_hw_device *vts_dev)
+void vts_lpsd_stop(struct vts_hw_device *vts_dev)
 {
     pthread_mutex_lock(&vts_dev->lock);
-    if (vts_dev->vts_odmrsvd2_state == VTS_RESERVED2_STARTED_STATE) {
-        /* Stop ODMRsvd2 thread first */
-        vts_dev->odmrsvd2_thread_exit = true;
+    if (vts_dev->vts_lpsd_state == VTS_LPSD_STARTED_STATE) {
+        /* Stop LPSD thread first */
+        vts_dev->lpsd_thread_exit = true;
         /* once callback thread is closed disable voice recognition */
 
         pthread_mutex_unlock(&vts_dev->lock);
-
-        pthread_join(vts_dev->odmrsvd2_thread, (void**)NULL);
-
+        pthread_join(vts_dev->lpsd_thread, (void**)NULL);
         pthread_mutex_lock(&vts_dev->lock);
-
         set_mixer_ctrls(vtsMixerHandle, model_recognize_stop_ctlname,
-                        odmvoice_reserved2recognize_stop_ctlvalue, MODEL_CONTROL_COUNT, false);
+                        svoice_lpsdrecognize_stop_ctlvalue, MODEL_STOP_CONTROL_COUNT, false);
 
         /* configure DMIC controls */
         set_dmic_ctrls(false);
 
-        vts_dev->vts_odmrsvd2_state = VTS_RESERVED2_STOPPED_STATE;
+        vts_dev->vts_lpsd_state = VTS_LPSD_STOPPED_STATE;
     } else {
-        printf("VTS ODMRsvd2 NOT started yet \n");
+        printf("VTS LPSD(BabyCrying) NOT started yet \n");
     }
     pthread_mutex_unlock(&vts_dev->lock);
     printf("%s: Exit \n", __func__);
     return;
 }
 
+/************Voice play support funtion**********************/
+static int play_streaming_buffer(struct vts_hw_device *vts_dev, int cap_mode)
+{
+    int ret = 0, ret_out = 0;
+    unsigned int flags_out;
+    int i = 0, j = 0;
+    struct pcm *vcap_pcm_out = NULL;
+    char *streaming_buf;
+    char *streaming_buf_temp;
+    FILE *file = NULL;
+    size_t num_read;
+    unsigned int pcmnode = (cap_mode == VTS_TRIGGERED_CAPTURE ? VTS_TRICAP_DEVICE_NODE : VTS_RECORD_DEVICE_NODE);
+
+    struct pcm_config pcmconfig_out = {
+        .channels = 2,
+        .rate = 16000,
+        .period_size = 160,
+        .period_count = 1024,
+        .format = PCM_FORMAT_S16_LE,
+        .stop_threshold = UINT_MAX,
+    };
+
+    streaming_buf = malloc(VTS_STREAMING_BUFFER_SIZE);
+    if (!streaming_buf) {
+        printf("Failed to malloc streaming buffer!!\n");
+        goto out3;
+    }
+    streaming_buf_temp = malloc(PLAY_BACK_BUFFER_SIZE);
+    if (!streaming_buf_temp) {
+        printf("Failed to malloc streaming_buf_temp!!\n");
+        goto out2;
+    }
+
+    file = fopen(VTS_NORMAL_CAPTURE_OUTPUT, "rb");
+    if (!file) {
+        printf("Failed to open file '%s'.\n", VTS_NORMAL_CAPTURE_OUTPUT);
+        goto out2;
+    }
+
+    pcmnode = (cap_mode == VTS_TRIGGERED_CAPTURE ? VTS_TRICAP_DEVICE_NODE : VTS_RECORD_DEVICE_NODE);
+    flags_out = PCM_OUT;
+
+    vcap_pcm_out = pcm_open(VTS_SOUND_CARD, PLAYBACK_OUT_DEVICE_NODE, flags_out, &pcmconfig_out);
+    if (vcap_pcm_out && !pcm_is_ready(vcap_pcm_out)) {
+        printf("%s - FAILED to open ( vcap_pcm_out ) VTS PCM Node : %d\n", __func__, PLAYBACK_OUT_DEVICE_NODE);
+        pcm_close(vcap_pcm_out);
+        goto out;
+    }
+    printf("vcap_pcm_out : %p\n", vcap_pcm_out);
+    printf("vcap_pcm_out pcm_is_ready: %d\n", pcm_is_ready(vcap_pcm_out));
+    printf("%s: Fetching bytes \n", __func__);
+
+    while(1){
+        num_read = fread((void*)streaming_buf, 1, (unsigned int)VTS_STREAMING_BUFFER_SIZE, file);
+        printf("num_read : %zu\n", num_read);
+        if (num_read > 0) {
+            printf("%s - Captured %d samples\n", __func__, VTS_STREAMING_BUFFER_SIZE);
+            for(j = 0; j < (VTS_STREAMING_BUFFER_SIZE >> 1); j++) {
+                memcpy(streaming_buf_temp + j * 4, streaming_buf + j * 2, (unsigned int)2);
+                memcpy(streaming_buf_temp + (j * 4) + 2, streaming_buf + j * 2, (unsigned int)2);
+            }
+            //write capture pcm data to output device
+            ret_out = pcm_write(vcap_pcm_out, (void*)streaming_buf_temp, (unsigned int)PLAY_BACK_BUFFER_SIZE);
+            printf("pcm_write -> ret_out : %d\n", ret_out);
+            if(ret_out != 0) {
+                printf("Failed to pcm_write!!\n");
+                break;
+            }
+        } else {
+            printf("Failed to fread\n");
+            break;
+        }
+        if (cap_mode == VTS_NORMAL_CAPTURE && vts_dev->vts_play_thread_exit == true)
+            break;
+    }
+    // Release VTS capture node
+    pcm_close(vcap_pcm_out);
+    vcap_pcm_out = NULL;
+    sysfs_write("/sys/power/wake_unlock", "vtshw-test", sizeof("vtshw-test"));
+    printf("%s - Wake Lock Released\n", __func__);
+out:
+    fclose(file);
+out2:
+    if (streaming_buf_temp)
+        free(streaming_buf_temp);
+out3:
+    if (streaming_buf)
+        free(streaming_buf);
+    return ret_out;
+}
+
+static void *play_thread_loop(void * context)
+{
+    int err = 0;
+    int i, n;
+    struct vts_hw_device *vts_dev = (struct vts_hw_device *)context;
+
+    prctl(PR_SET_NAME, (unsigned long)"VTSRecord", 0, 0, 0);
+    printf("%s Started!!\n", __func__);
+    play_streaming_buffer(vts_dev, VTS_NORMAL_CAPTURE);
+    vts_dev->vts_play_state = VTS_PLAY_STOPPED_STATE;
+    if (vts_dev->play_thread_exit == true) {
+        //reset DMIC controls
+        set_dmic_ctrls(false);
+    }
+    printf("%s: Exit \n", __func__);
+    return (void *)(long)err;
+}
+
+void vts_play_start(struct vts_hw_device *vts_dev)
+{
+    pthread_mutex_lock(&vts_dev->lock);
+    if (vts_dev->vts_play_state == VTS_PLAY_STOPPED_STATE) {
+        //Create lpsd thread to wait on uevent from VTS IP
+        set_dmic_ctrls(true);
+        set_playback_dmic_ctrls(true);
+        vts_dev->vts_play_thread_exit = false;
+        pthread_create(&vts_dev->vts_play_thread, (const pthread_attr_t *) NULL,
+                            play_thread_loop, vts_dev);
+
+        vts_dev->vts_play_state = VTS_PLAY_STARTED_STATE;
+    } else {
+        printf("VTS PLAY Already started \n");
+    }
+    pthread_mutex_unlock(&vts_dev->lock);
+    printf("%s: Exit \n", __func__);
+    return;
+}
+
+
+void vts_play_stop(struct vts_hw_device *vts_dev)
+{
+    pthread_mutex_lock(&vts_dev->lock);
+    if (vts_dev->vts_play_state == VTS_PLAY_STARTED_STATE) {
+        vts_dev->vts_play_thread_exit = true;
+        pthread_mutex_unlock(&vts_dev->lock);
+        pthread_join(vts_dev->vts_play_thread, (void**)NULL);
+        pthread_mutex_lock(&vts_dev->lock);
+        set_mixer_ctrls(vtsMixerHandle, model_recognize_stop_ctlname,
+                        svoice_lpsdrecognize_stop_ctlvalue, MODEL_STOP_CONTROL_COUNT, false);
+
+        set_dmic_ctrls(false);
+        set_playback_dmic_ctrls(false);
+        vts_dev->vts_play_state = VTS_PLAY_STOPPED_STATE;
+    } else {
+        printf("VTS LPSD(BabyCrying) NOT started yet \n");
+    }
+    pthread_mutex_unlock(&vts_dev->lock);
+    printf("%s: Exit \n", __func__);
+    return;
+}
+
+
+/******** Voice Playback support function ***************/
+static int playback_streaming_buffer(struct vts_hw_device *vts_dev, int cap_mode)
+{
+    int ret = -1, ret_out = -1;
+    unsigned int flags, flags_out, frames;
+    int i = 0, j = 0;
+    struct pcm *vcap_pcm = NULL;
+    struct pcm *vcap_pcm_out = NULL;
+    char *streaming_buf;
+    char *streaming_buf_temp;
+    unsigned int pcmnode = (cap_mode == VTS_TRIGGERED_CAPTURE ? VTS_TRICAP_DEVICE_NODE : VTS_RECORD_DEVICE_NODE);
+
+    FILE *file_in = NULL;
+    FILE *file_out = NULL;
+    struct wav_header header_in, header_out;
+    struct pcm_config pcmconfig = {
+        .channels = 1,
+        .rate = 16000,
+        .period_size = 160,
+        .period_count = 512,
+        .format = PCM_FORMAT_S16_LE,
+    };
+    struct pcm_config pcmconfig_out = {
+        .channels = 2,
+        .rate = 16000,
+        .period_size = 160, //960,4
+        .period_count = 512,
+        .format = PCM_FORMAT_S16_LE,
+    .start_threshold = 1,
+        .stop_threshold = UINT_MAX,
+    };
+
+    streaming_buf = malloc(LOOPBACK_BUFFER_SIZE);
+    if (!streaming_buf) {
+        printf("Failed to malloc streaming buffer!!\n");
+        goto out4;
+    }
+    streaming_buf_temp = malloc(PLAY_BACK_BUFFER_SIZE);
+    if (!streaming_buf_temp) {
+        printf("Failed to malloc streaming_buf_temp!!\n");
+        goto out3;
+    }
+    /* initialize the Wav Header information */
+    header_in.riff_id = ID_RIFF;
+    header_in.riff_sz = 0;
+    header_in.riff_fmt = ID_WAVE;
+    header_in.fmt_id = ID_FMT;
+    header_in.fmt_sz = 16;
+    header_in.audio_format = FORMAT_PCM;
+    header_in.num_channels = pcmconfig.channels;
+    header_in.sample_rate = pcmconfig.rate;
+
+    header_in.bits_per_sample = pcm_format_to_bits(PCM_FORMAT_S16_LE);
+    header_in.byte_rate = (header_in.bits_per_sample / 8) * pcmconfig.channels * pcmconfig.rate;
+    header_in.block_align = pcmconfig.channels * (header_in.bits_per_sample / 8);
+    header_in.data_id = ID_DATA;
+
+    /* open an output file to dump capture vts voice commands */
+    file_in = fopen("/sdcard/vts_in.wav", "w+");
+    if(!file_in){
+        printf("%s - FAILED to open output file !!! %s\n", __func__, "/sdcard/vts_in.wav");
+        goto out3;
+    }
+
+    header_out.riff_id = ID_RIFF;
+    header_out.riff_sz = 0;
+    header_out.riff_fmt = ID_WAVE;
+    header_out.fmt_id = ID_FMT;
+    header_out.fmt_sz = 16;
+    header_out.audio_format = FORMAT_PCM;
+    header_out.num_channels = pcmconfig_out.channels;
+    header_out.sample_rate = pcmconfig_out.rate;
+
+    header_out.bits_per_sample = pcm_format_to_bits(PCM_FORMAT_S16_LE);
+    header_out.byte_rate = (header_out.bits_per_sample / 8) * pcmconfig_out.channels * pcmconfig_out.rate;
+    header_out.block_align = pcmconfig_out.channels * (header_out.bits_per_sample / 8);
+    header_out.data_id = ID_DATA;
+
+    /* open an output file to dump capture vts voice commands */
+    file_out = fopen("/sdcard/vts_out.wav", "w+");
+    if(!file_out){
+        printf("%s - FAILED to open output file !!! %s\n", __func__, "/sdcard/vts_out.wav");
+        goto out2;
+    }
+    int k = 0;
+    printf("%s: Fetching bytes \n", __func__);
+    if (!vcap_pcm) {
+        /* Open vts capture pcm node */
+        pcmnode = (cap_mode == VTS_TRIGGERED_CAPTURE ? VTS_TRICAP_DEVICE_NODE : VTS_RECORD_DEVICE_NODE);
+        flags = PCM_IN;
+        flags_out = PCM_OUT;
+
+        vcap_pcm_out = pcm_open(VTS_SOUND_CARD, PLAYBACK_OUT_DEVICE_NODE, flags_out, &pcmconfig_out);
+        if (vcap_pcm_out && !pcm_is_ready(vcap_pcm_out)) {
+            printf("%s - FAILED to open ( vcap_pcm_out ) VTS PCM Node : %d\n", __func__, PLAYBACK_OUT_DEVICE_NODE);
+            goto out;
+        }
+        printf("vcap_pcm_out : %p\n", vcap_pcm_out);
+        printf("vcap_pcm_out pcm_is_ready: %d\n", pcm_is_ready(vcap_pcm_out));
+        printf("vcap_pcm -> pcmnode : %d\n", pcmnode);
+        vcap_pcm = pcm_open(VTS_SOUND_CARD, pcmnode, flags, &pcmconfig);
+        if (vcap_pcm && !pcm_is_ready(vcap_pcm)) {
+            printf("%s - FAILED to open ( vcap_pcm ) VTS PCM Node : %d\n", __func__, pcmnode);
+            pcm_close(vcap_pcm);
+            goto out;
+        }
+        printf("vcap_pcm : %p\n", vcap_pcm);
+        printf("vcap_pcm pcm_is_ready: %d\n", pcm_is_ready(vcap_pcm));
+        sysfs_write("/sys/power/wake_lock", "vtshw-test", sizeof("vtshw-test"));
+        printf("%s - Wake Lock Acquired\n", __func__);
+        fseek(file_in, sizeof(struct wav_header), SEEK_SET);
+        fseek(file_out, sizeof(struct wav_header), SEEK_SET);
+        memset(streaming_buf, 0, (unsigned int)LOOPBACK_BUFFER_SIZE);
+        while(1) {
+            ret = pcm_read(vcap_pcm, (void*)(streaming_buf + (i%NUM_OF_SAMPLES_TO_CAPTURE)*VTS_STREAMING_BUFFER_SIZE), (unsigned int)VTS_STREAMING_BUFFER_SIZE);
+            printf("pcm_read -> ret : %d\n", ret);
+            if (ret == 0 && i >= 10) {
+                memset(streaming_buf_temp, 0, (unsigned int)PLAY_BACK_BUFFER_SIZE);
+                printf("%s - Captured %d samples\n", __func__, VTS_STREAMING_BUFFER_SIZE);
+                for(j = 0; j < (VTS_STREAMING_BUFFER_SIZE >> 1); j++){
+                    memcpy(streaming_buf_temp + j * 4, streaming_buf + (k%NUM_OF_SAMPLES_TO_CAPTURE)*VTS_STREAMING_BUFFER_SIZE + j * 2, (unsigned int)2);
+                    memcpy(streaming_buf_temp + (j * 4) + 2, streaming_buf + (k%NUM_OF_SAMPLES_TO_CAPTURE)*VTS_STREAMING_BUFFER_SIZE + j * 2, (unsigned int)2);
+                }
+                ret_out = pcm_write(vcap_pcm_out, (void*)(streaming_buf_temp), (unsigned int)PLAY_BACK_BUFFER_SIZE);
+                printf("pcm_write -> ret_out : %d\n", ret_out);
+                fwrite((void*)streaming_buf_temp, (unsigned int)PLAY_BACK_BUFFER_SIZE, 1, file_out);
+                k++;
+                if (ret_out != 0) {
+                    printf("Failed to pcm_write!!\n");
+                    break;
+                }
+            } else {
+                printf("%s - Failed to capture requested samples %s \n", __func__, pcm_get_error(vcap_pcm));
+                //sleep(10);
+            }
+            fwrite((void*)(streaming_buf + (i%NUM_OF_SAMPLES_TO_CAPTURE)*VTS_STREAMING_BUFFER_SIZE), (unsigned int)VTS_STREAMING_BUFFER_SIZE, 1, file_in);
+            i++;
+            if (cap_mode == VTS_NORMAL_CAPTURE && vts_dev->play_thread_exit == true)
+                break;
+        }
+        /* Release VTS capture node */
+        frames = pcm_bytes_to_frames(vcap_pcm, (i * VTS_STREAMING_BUFFER_SIZE));
+        header_in.data_sz = frames * header_in.block_align;
+        header_in.riff_sz = (uint32_t)(header_in.data_sz + sizeof(header_in) - 8);
+        fseek(file_in, 0, SEEK_SET);
+        fwrite(&header_in, sizeof(struct wav_header), 1, file_in);
+
+        frames = pcm_bytes_to_frames(vcap_pcm_out, (k * PLAY_BACK_BUFFER_SIZE));
+        header_out.data_sz = frames * header_out.block_align;
+        header_out.riff_sz = (uint32_t)(header_out.data_sz + sizeof(header_out) - 8);
+        fseek(file_out, 0, SEEK_SET);
+        fwrite(&header_out, sizeof(struct wav_header), 1, file_out);
+
+        pcm_close(vcap_pcm);
+        vcap_pcm = NULL;
+        sysfs_write("/sys/power/wake_unlock", "vtshw-test", sizeof("vtshw-test"));
+        printf("%s - Wake Lock Released\n", __func__);
+    }
+out:
+    pcm_close(vcap_pcm_out);
+    vcap_pcm_out = NULL;
+    fclose(file_out);
+    file_out = NULL;
+out2:
+    fclose(file_in);
+    file_in = NULL;
+out3:
+    if (streaming_buf_temp)
+        free(streaming_buf_temp);
+out4:
+    if (streaming_buf)
+        free(streaming_buf);
+    return ret_out;
+}
+
+static int looprec_streaming_buffer(struct vts_hw_device *vts_dev, int cap_mode)
+{
+    int ret = -1;
+    unsigned int flags, frames;
+    int i = 0, j = 0;
+    struct pcm *vcap_pcm = NULL;
+    unsigned int pcmnode = (cap_mode == VTS_TRIGGERED_CAPTURE ? VTS_TRICAP_DEVICE_NODE : VTS_RECORD_DEVICE_NODE);
+
+    FILE *file_in = NULL;
+    struct wav_header header_in;
+    struct pcm_config pcmconfig = {
+        .channels = 1,
+        .rate = 16000,
+        .period_size = 160,
+        .period_count = 512,
+        .format = PCM_FORMAT_S16_LE,
+    };
+
+    loopback_stream = malloc(LOOPBACK_BUFFER_SIZE);
+    if (!loopback_stream) {
+        printf("Failed to malloc streaming buffer!!\n");
+        goto out;
+    }
+    /* initialize the Wav Header information */
+    header_in.riff_id = ID_RIFF;
+    header_in.riff_sz = 0;
+    header_in.riff_fmt = ID_WAVE;
+    header_in.fmt_id = ID_FMT;
+    header_in.fmt_sz = 16;
+    header_in.audio_format = FORMAT_PCM;
+    header_in.num_channels = pcmconfig.channels;
+    header_in.sample_rate = pcmconfig.rate;
+
+    header_in.bits_per_sample = pcm_format_to_bits(PCM_FORMAT_S16_LE);
+    header_in.byte_rate = (header_in.bits_per_sample / 8) * pcmconfig.channels * pcmconfig.rate;
+    header_in.block_align = pcmconfig.channels * (header_in.bits_per_sample / 8);
+    header_in.data_id = ID_DATA;
+
+    /* open an output file to dump capture vts voice commands */
+    file_in = fopen("/sdcard/vts_in.wav", "w+");
+    if(!file_in){
+        printf("%s - FAILED to open output file !!! %s\n", __func__, "/sdcard/vts_in.wav");
+        goto out;
+    }
+
+    int k = 0;
+    printf("%s: Fetching bytes \n", __func__);
+
+    vts_dev->start_loopback_play= false;
+    if (!vcap_pcm) {
+        /* Open vts capture pcm node */
+        pcmnode = (cap_mode == VTS_TRIGGERED_CAPTURE ? VTS_TRICAP_DEVICE_NODE : VTS_RECORD_DEVICE_NODE);
+        flags = PCM_IN;
+
+        printf("vcap_pcm -> pcmnode : %d\n", pcmnode);
+        vcap_pcm = pcm_open(VTS_SOUND_CARD, pcmnode, flags, &pcmconfig);
+        if (vcap_pcm && !pcm_is_ready(vcap_pcm)) {
+            printf("%s - FAILED to open ( vcap_pcm ) VTS PCM Node : %d\n", __func__, pcmnode);
+            pcm_close(vcap_pcm);
+            fclose(file_in);
+            goto out;
+        }
+        printf("vcap_pcm : %p\n", vcap_pcm);
+        printf("vcap_pcm pcm_is_ready: %d\n", pcm_is_ready(vcap_pcm));
+
+        sysfs_write("/sys/power/wake_lock", "vtshw-test", sizeof("vtshw-test"));
+        printf("%s - Wake Lock Acquired\n", __func__);
+        fseek(file_in, sizeof(struct wav_header), SEEK_SET);
+        memset(loopback_stream, 0, (unsigned int)LOOPBACK_BUFFER_SIZE);
+        while(1) {
+            memset((void*)(loopback_stream + (i%NUM_OF_SAMPLES_TO_CAPTURE)*VTS_STREAMING_BUFFER_SIZE), 0, (unsigned int)VTS_STREAMING_BUFFER_SIZE);
+            ret = pcm_read(vcap_pcm, (void*)(loopback_stream + (i%NUM_OF_SAMPLES_TO_CAPTURE)*VTS_STREAMING_BUFFER_SIZE), (unsigned int)VTS_STREAMING_BUFFER_SIZE);
+            printf("pcm_read -> ret : %d\n", ret);
+            if (ret == 0) {
+                vts_dev->start_loopback_play = true;
+                fwrite((void*)(loopback_stream + (i%NUM_OF_SAMPLES_TO_CAPTURE)*VTS_STREAMING_BUFFER_SIZE), (unsigned int)VTS_STREAMING_BUFFER_SIZE, 1, file_in);
+                i++;
+            } else {
+                printf("%s - Failed to capture requested samples %s \n", __func__, pcm_get_error(vcap_pcm));
+                //sleep(10);
+            }
+
+            if (cap_mode == VTS_NORMAL_CAPTURE && vts_dev->play_thread_exit == true)
+                break;
+        }
+        /* Release VTS capture node */
+        frames = pcm_bytes_to_frames(vcap_pcm, (i * VTS_STREAMING_BUFFER_SIZE));
+        header_in.data_sz = frames * header_in.block_align;
+        header_in.riff_sz = (uint32_t)(header_in.data_sz + sizeof(header_in) - 8);
+        fseek(file_in, 0, SEEK_SET);
+        fwrite(&header_in, sizeof(struct wav_header), 1, file_in);
+
+        /* close output file */
+        fclose(file_in);
+        file_in = NULL;
+        pcm_close(vcap_pcm);
+        vcap_pcm = NULL;
+        sysfs_write("/sys/power/wake_unlock", "vtshw-test", sizeof("vtshw-test"));
+        printf("%s - Wake Lock Released\n", __func__);
+    }
+out:
+    if (loopback_stream)
+        free(loopback_stream);
+    return ret;
+}
+
+
+static int loopplay_streaming_buffer(struct vts_hw_device *vts_dev, int cap_mode)
+{
+    int ret = -1, ret_out = -1;
+    unsigned int flags_out, frames;
+    int i = 0, j = 0;
+    struct pcm *vcap_pcm_out = NULL;
+    char *streaming_buf_temp;
+    unsigned int pcmnode = (cap_mode == VTS_TRIGGERED_CAPTURE ? VTS_TRICAP_DEVICE_NODE : VTS_RECORD_DEVICE_NODE);
+
+    FILE *file_out = NULL;
+	struct wav_header header_out;
+    struct pcm_config pcmconfig_out = {
+        .channels = 2,
+        .rate = 16000,
+        .period_size = 160, //960,4
+        .period_count = 512,
+        .format = PCM_FORMAT_S16_LE,
+        .start_threshold = 1,
+        .stop_threshold = UINT_MAX,
+    };
+
+    streaming_buf_temp = malloc(PLAY_BACK_BUFFER_SIZE);
+    if (!streaming_buf_temp) {
+        printf("Failed to malloc streaming_buf_temp!!\n");
+        goto out2;
+    }
+    /* initialize the Wav Header information */
+    header_out.riff_id = ID_RIFF;
+    header_out.riff_sz = 0;
+    header_out.riff_fmt = ID_WAVE;
+    header_out.fmt_id = ID_FMT;
+    header_out.fmt_sz = 16;
+    header_out.audio_format = FORMAT_PCM;
+    header_out.num_channels = pcmconfig_out.channels;
+    header_out.sample_rate = pcmconfig_out.rate;
+
+    header_out.bits_per_sample = pcm_format_to_bits(PCM_FORMAT_S16_LE);
+    header_out.byte_rate = (header_out.bits_per_sample / 8) * pcmconfig_out.channels * pcmconfig_out.rate;
+    header_out.block_align = pcmconfig_out.channels * (header_out.bits_per_sample / 8);
+    header_out.data_id = ID_DATA;
+
+    /* open an output file to dump capture vts voice commands */
+    file_out = fopen("/sdcard/vts_out.wav", "w+");
+    if(!file_out){
+        printf("%s - FAILED to open output file !!! %s\n", __func__, "/sdcard/vts_out.wav");
+        goto out2;
+    }
+    int k = 0;
+    printf("%s: Fetching bytes \n", __func__);
+    if (!vcap_pcm_out) {
+        /* Open vts capture pcm node */
+        pcmnode = (cap_mode == VTS_TRIGGERED_CAPTURE ? VTS_TRICAP_DEVICE_NODE : VTS_RECORD_DEVICE_NODE);
+        flags_out = PCM_OUT;
+
+        vcap_pcm_out = pcm_open(VTS_SOUND_CARD, PLAYBACK_OUT_DEVICE_NODE, flags_out, &pcmconfig_out);
+        if (vcap_pcm_out && !pcm_is_ready(vcap_pcm_out)) {
+            printf("%s - FAILED to open ( vcap_pcm_out ) VTS PCM Node : %d\n", __func__, PLAYBACK_OUT_DEVICE_NODE);
+            pcm_close(vcap_pcm_out);
+            goto out;
+        }
+        printf("vcap_pcm_out : %p\n", vcap_pcm_out);
+        printf("vcap_pcm_out pcm_is_ready: %d\n", pcm_is_ready(vcap_pcm_out));
+
+        sysfs_write("/sys/power/wake_lock", "vtshw-test", sizeof("vtshw-test"));
+        printf("%s - Wake Lock Acquired\n", __func__);
+        fseek(file_out, sizeof(struct wav_header), SEEK_SET);
+        while(1) {
+            if (vts_dev->start_loopback_play) {
+                memset(streaming_buf_temp, 0, (unsigned int)PLAY_BACK_BUFFER_SIZE);
+                printf("%s - Captured %d samples\n", __func__, VTS_STREAMING_BUFFER_SIZE);
+                for(j = 0; j < (VTS_STREAMING_BUFFER_SIZE >> 1); j++){
+                    memcpy(streaming_buf_temp + j * 4, loopback_stream + (k%NUM_OF_SAMPLES_TO_CAPTURE)*VTS_STREAMING_BUFFER_SIZE + j * 2, (unsigned int)2);
+                    memcpy(streaming_buf_temp + (j * 4) + 2, loopback_stream + (k%NUM_OF_SAMPLES_TO_CAPTURE)*VTS_STREAMING_BUFFER_SIZE + j * 2, (unsigned int)2);
+                }
+                ret_out = pcm_write(vcap_pcm_out, (void*)(streaming_buf_temp), (unsigned int)PLAY_BACK_BUFFER_SIZE);
+                printf("pcm_write -> ret_out : %d\n", ret_out);
+                fwrite((void*)streaming_buf_temp, (unsigned int)PLAY_BACK_BUFFER_SIZE, 1, file_out);
+                k++;
+                if (ret_out != 0) {
+                    printf("Failed to pcm_write!!\n");
+                    break;
+                }
+            } else {
+                printf("%s - Failed to capture requested samples %s \n", __func__, pcm_get_error(vcap_pcm_out));
+                //sleep(10);
+            }
+            if (cap_mode == VTS_NORMAL_CAPTURE && vts_dev->play_thread_exit == true)
+                break;
+        }
+        /* Release VTS capture node */
+        frames = pcm_bytes_to_frames(vcap_pcm_out, (k * PLAY_BACK_BUFFER_SIZE));
+        header_out.data_sz = frames * header_out.block_align;
+        header_out.riff_sz = (uint32_t)(header_out.data_sz + sizeof(header_out) - 8);
+        fseek(file_out, 0, SEEK_SET);
+        fwrite(&header_out, sizeof(struct wav_header), 1, file_out);
+
+        /* close output file */
+        pcm_close(vcap_pcm_out);
+        vcap_pcm_out = NULL;
+        sysfs_write("/sys/power/wake_unlock", "vtshw-test", sizeof("vtshw-test"));
+        printf("%s - Wake Lock Released\n", __func__);
+    }
+out:
+    fclose(file_out);
+    file_out = NULL;
+out2:
+    if (streaming_buf_temp)
+        free(streaming_buf_temp);
+    return ret_out;
+}
+
+static void *looprec_thread_loop(void * context)
+{
+    int err = 0;
+    struct vts_hw_device *vts_dev = (struct vts_hw_device *)context;
+
+    prctl(PR_SET_NAME, (unsigned long)"VTSRecord", 0, 0, 0);
+
+    printf("%s Started!!\n", __func__);
+    looprec_streaming_buffer(vts_dev, VTS_NORMAL_CAPTURE); // VTS_TRIGGERED_CAPTURE
+
+    vts_dev->play_back_state = PLAY_BACK_STOPPED_STATE;
+
+    if (vts_dev->play_thread_exit == true) {
+        /* reset DMIC controls */
+        set_dmic_ctrls(false);
+    }
+    printf("%s: Exit \n", __func__);
+    return (void *)(long)err;
+}
+
+
+static void *loopplay_thread_loop(void * context)
+{
+    int err = 0;
+    struct vts_hw_device *vts_dev = (struct vts_hw_device *)context;
+
+    prctl(PR_SET_NAME, (unsigned long)"VTSRecord", 0, 0, 0);
+
+    printf("%s Started!!\n", __func__);
+    loopplay_streaming_buffer(vts_dev, VTS_NORMAL_CAPTURE); // VTS_TRIGGERED_CAPTURE
+
+    vts_dev->play_back_state = PLAY_BACK_STOPPED_STATE;
+
+    if (vts_dev->play_thread_exit == true) {
+        /* reset DMIC controls */
+        set_dmic_ctrls(false);
+    }
+    printf("%s: Exit \n", __func__);
+    return (void *)(long)err;
+}
+
+static void *playback_thread_loop(void * context)
+{
+    int err = 0;
+    struct vts_hw_device *vts_dev = (struct vts_hw_device *)context;
+
+    prctl(PR_SET_NAME, (unsigned long)"VTSRecord", 0, 0, 0);
+
+    printf("%s Started!!\n", __func__);
+    playback_streaming_buffer(vts_dev, VTS_NORMAL_CAPTURE); // VTS_TRIGGERED_CAPTURE
+
+    vts_dev->play_back_state = PLAY_BACK_STOPPED_STATE;
+
+    if (vts_dev->play_thread_exit == true) {
+        /* reset DMIC controls */
+        set_dmic_ctrls(false);
+    }
+    printf("%s: Exit \n", __func__);
+    return (void *)(long)err;
+}
+
+
+void playback_start(struct vts_hw_device *vts_dev)
+{
+    pthread_mutex_lock(&vts_dev->lock);
+    if (vts_dev->play_back_state == PLAY_BACK_STOPPED_STATE) {
+        /* configure DMIC controls */
+        set_dmic_ctrls(true);
+        set_playback_dmic_ctrls(true);
+
+        /* Create recorrd thread to playback*/
+        vts_dev->play_thread_exit = false;
+        // pthread_create(&vts_dev->play_thread, (const pthread_attr_t *) NULL, playback_thread_loop, vts_dev);
+        pthread_create(&vts_dev->rec_thread, (const pthread_attr_t *) NULL, looprec_thread_loop, vts_dev);
+        pthread_create(&vts_dev->play_thread, (const pthread_attr_t *) NULL, loopplay_thread_loop, vts_dev);
+
+        vts_dev->play_back_state = PLAY_BACK_STARTED_STATE;
+    } else {
+        printf("VTS Recording Already started \n");
+    }
+    pthread_mutex_unlock(&vts_dev->lock);
+    printf("%s: Exit \n", __func__);
+    return;
+}
+
+void playback_stop(struct vts_hw_device *vts_dev)
+{
+    pthread_mutex_lock(&vts_dev->lock);
+    if (vts_dev->play_back_state == PLAY_BACK_STARTED_STATE) {
+        vts_dev->play_thread_exit = true;
+
+        if (vts_dev->send_sock >= 0)
+            write(vts_dev->send_sock, "T", 1);
+
+        pthread_mutex_unlock(&vts_dev->lock);
+        pthread_join(vts_dev->play_thread, (void**)NULL);
+        pthread_mutex_lock(&vts_dev->lock);
+
+        /* configure DMIC controls */
+        set_dmic_ctrls(false);
+        set_playback_dmic_ctrls(false);
+        set_mixer_ctrls(vtsMixerHandle, model_recognize_stop_ctlname,
+                svoice_bixbyrecognize_stop_ctlvalue, MODEL_STOP_CONTROL_COUNT, false);
+
+        vts_dev->play_back_state = PLAY_BACK_STOPPED_STATE;
+    } else {
+        printf("playback mode is NOT Started\n");
+    }
+    pthread_mutex_unlock(&vts_dev->lock);
+    printf("%s: Exit \n", __func__);
+    return;
+}
+
+
+
 /****************** Unit test main function *************************/
 
 void print_options(struct vts_hw_device *vts_dev __unused)
 {
-    printf("********************** Generic Dual VA VTS HW Test Options ***********************\n");
+    printf("********************** Generic Dual VA VTS HW Test ***********************\n");
 #ifdef MMAP_INTERFACE_ENABLED
-    printf("********************** MMAP interface for Model Binary loading***********************\n");
+    printf("********************** MMAP interface for Model Binary loading ***********************\n");
 #else
-    printf("********************** SYSFS interface for Model Binary loading***********************\n");
+    printf("********************** SYSFS interface for Model Binary loading ***********************\n");
 #endif
-    printf("1. Voice Recoginition Start\n");
-    printf("2. Voice Recoginition Stop\n");
-    printf("3. VTS Record Start\n");
-    printf("4. VTS Record Stop\n");
-    printf("5. ODMRsvd2 Mode Start\n");
-    printf("6. ODMRsvd2 Mode Stop\n");
-    printf("7. Exit - VTS Test Application\n");
+    printf("1. Voice Bixby Recoginition Start\n");
+    printf("2. Voice Google Recoginition Start\n");
+    printf("3. Voice Recoginition Stop\n");
+    printf("4. VTS Record Start\n");
+    printf("5. VTS Record Stop\n");
+    printf("6. VTS Play Mode Start\n");
+    printf("7. VTS Play Mode Stop\n");
+    printf("8. Voice Playback Start\n");
+    printf("9. Voice Playback End\n");
+    printf("10. Exit - VTS Test Application\n");
     printf("****************************************************************!\n");
     printf("Enter an Option: \n");
     return;
@@ -876,7 +1736,9 @@
     vtsMixerHandle = mixer_open(VTS_MIXER_CARD);
     if (!vtsMixerHandle) {
         printf("%s: Failed to open mixer \n", __func__);
+#ifdef MMAP_INTERFACE_ENABLED
         close(vtsdev_fd);
+#endif
         return -EINVAL;
     }
 
@@ -885,7 +1747,7 @@
     vts_dev->vts_state = VTS_RECOGNITION_STOPPED_STATE;
     vts_dev->vts_rec_state = VTS_RECORD_STOPPED_STATE;
     vts_dev->thread_exit = false;
-    vts_dev->model_loaded = false;
+    vts_dev->model_loaded = 0;
 
     memset(fds, 0, sizeof(struct pollfd));
     fds[0].events = POLLIN;
@@ -895,7 +1757,7 @@
 
     while (1) {
         print_options(vts_dev);
-        ret = poll(fds,1,-1);
+        ret = poll(fds, 1, -1);
         if (fds[0].revents & POLLIN) {
             if (fgets(pstr, 50, stdin) == NULL) {
                 printf("Failed to get data from stdin \n");
@@ -909,35 +1771,44 @@
         printf("%s - Selected option %d\n", __func__, option);
         /* Called corresponding function based on Option selected */
         switch (option) {
-        case 1: /* Start loaded sound Model Recognition */
-            vts_recognition_start(vts_dev);
+        case MENU_START_BIXBY_RECOGNITION: /* Start loaded sound Model Recognition */
+            vts_recognition_start(vts_dev, BIXBY_MODEL);
             break;
-        case 2: /* Stop loaded sound Model Recognition */
+        case MENU_START_GOOGLE_RECOGNITION:
+            vts_recognition_start(vts_dev, GOOGLE_MODEL);
+            break;
+        case MENU_STOP_RECOGNITION: /* Stop loaded sound Model Recognition */
             vts_recognition_stop(vts_dev);
             break;
-        case 3: /* Start VTS recording */
+        case MENU_START_RECORD:
             vts_record_start(vts_dev);
             break;
-        case 4: /* Stop VTS recording */
+        case MENU_STOP_RECORD:
             vts_record_stop(vts_dev);
             break;
-        case 5:
-            vts_odmrsvd2_start(vts_dev);
+        case MENU_START_PLAY:
+            vts_play_start(vts_dev);
             break;
-        case 6:
-            vts_odmrsvd2_stop(vts_dev);
+        case MENU_STOP_PLAY:
+            vts_play_stop(vts_dev);
             break;
-        case 7:
+        case MENU_START_PLAYBACK:
+            playback_start(vts_dev);
+            break;
+        case MENU_STOP_PLAYBACK:
+            playback_stop(vts_dev);
+            break;
+        case MENU_EXIT:
             check_vts_state(vts_dev);
             printf("VTS HW Testing completed\n");
             break;
-
         default:
             printf("UNSUPPORTED Option - Try again !\n");
             break;
         }
 
-        if (option == 7) break;
+        if (option == MENU_EXIT)
+            break;
         option = 0;
     }
 
diff --git a/libaudio/sthal/vts.h b/libaudio/sthal/vts.h
index 8d4baae..d21a1f5 100644
--- a/libaudio/sthal/vts.h
+++ b/libaudio/sthal/vts.h
@@ -27,11 +27,8 @@
 #include <stdlib.h>
 #endif
 
-#define VTSDRV_MISC_IOCTL_WRITE_ODMVOICE	_IOW('V', 0x00, int)
-#define VTSDRV_MISC_IOCTL_WRITE_GOOGLE		_IOW('V', 0x01, int)
-/* Google model binary size is used, as this is greater then SVoice model size */
-#ifndef VTSDRV_MISC_MODEL_BIN_MAXSZ
-#define VTSDRV_MISC_MODEL_BIN_MAXSZ		0xB500
-#endif
+#define VTSDRV_MISC_IOCTL_WRITE_SVOICE _IOW('V', 0x00, int)
+#define VTSDRV_MISC_IOCTL_WRITE_GOOGLE _IOW('V', 0x01, int)
+#define VTSDRV_MISC_IOCTL_READ_GOOGLE_VERSION _IOR('V', 0x02, int)
 
 #endif /* _UAPI__SOUND_VTS_H */