Merge "st-hal: fix session in active even when concurrency disabled"
diff --git a/sound_trigger_hw.c b/sound_trigger_hw.c
index 54d26d7..16eded7 100644
--- a/sound_trigger_hw.c
+++ b/sound_trigger_hw.c
@@ -485,8 +485,7 @@
         goto exit;
     }
 
-    max_sessions = stdev->is_gcs ?
-                   stdev->max_wdsp_sessions : stdev->max_cpe_sessions;
+    max_sessions = stdev->max_wdsp_sessions;
 
     /* Initialize transit cpe phrases/users for all ADSP sessions */
     list_for_each(node, &stdev->sound_model_list) {
@@ -839,7 +838,7 @@
          *       by audio capture usecase, so need to do session pause->resume
          *       to resume tx path.
          */
-        if (!conc_allowed && stdev->session_allowed) {
+        if (!conc_allowed) {
             list_for_each(p_ses_node, &stdev->sound_model_list) {
                 p_ses = node_to_item(p_ses_node, st_session_t, list_node);
                 st_session_pause(p_ses);
@@ -1284,24 +1283,14 @@
      * delegated to sthal level, where sthal returns error if sound model
      * sessions exceed the platform supported for a given execution mode.
      */
-    if (stdev->is_gcs) {
-        stdev->hw_properties->max_sound_models = MAX(stdev->max_wdsp_sessions,
-            stdev->max_ape_sessions);
-        stdev->hw_properties->max_key_phrases = MAX(stdev->avail_cpe_phrases,
-            stdev->avail_ape_phrases);
-        stdev->hw_properties->max_users = MAX(stdev->avail_cpe_users,
-            stdev->avail_ape_users);
-        stdev->hw_properties->max_buffer_ms = ST_GRAPHITE_LAB_BUF_DURATION_MS;
-    } else {
-        stdev->hw_properties->max_sound_models = MAX(stdev->max_cpe_sessions,
-            stdev->max_ape_sessions);
-        stdev->hw_properties->max_key_phrases = MAX(stdev->avail_cpe_phrases,
-            stdev->avail_ape_phrases);
-        stdev->hw_properties->max_users = MAX(stdev->avail_cpe_users,
-            stdev->avail_ape_users);
-        stdev->hw_properties->max_buffer_ms =
-            SOUND_TRIGGER_CPE_LAB_DRV_BUF_DURATION_MS;
-    }
+    stdev->hw_properties->max_sound_models = MAX(stdev->max_wdsp_sessions,
+        stdev->max_ape_sessions);
+    stdev->hw_properties->max_key_phrases = MAX(stdev->avail_cpe_phrases,
+        stdev->avail_ape_phrases);
+    stdev->hw_properties->max_users = MAX(stdev->avail_cpe_users,
+        stdev->avail_ape_users);
+    stdev->hw_properties->max_buffer_ms = ST_GRAPHITE_LAB_BUF_DURATION_MS;
+
     ALOGVV("%s version=0x%x recognition_modes=%d, capture_transition=%d, "
            "concurrent_capture=%d", __func__, stdev->hw_properties->version,
            stdev->hw_properties->recognition_modes,
@@ -1357,8 +1346,7 @@
      */
     if (v_info->exec_mode_cfg == EXEC_MODE_CFG_CPE) {
         /* Algorithm configured for CPE only */
-        if ((!stdev->is_gcs && (num_sessions < stdev->max_cpe_sessions)) ||
-            (stdev->is_gcs && (num_sessions < stdev->max_wdsp_sessions))) {
+        if (num_sessions < stdev->max_wdsp_sessions) {
             if (common_sm->type == SOUND_MODEL_TYPE_KEYPHRASE) {
                 /* Keyphrase sound model */
                 if (check_phrases_users_available(v_info, num_phrases,
@@ -1394,8 +1382,7 @@
              * CPE mode for all sessions.
              */
             ALOGV("%s: EXEC_MODE_CFG_DYNAMIC: req exec mode CPE", __func__);
-            if ((!stdev->is_gcs && (num_sessions < stdev->max_cpe_sessions)) ||
-                (stdev->is_gcs && (num_sessions < stdev->max_wdsp_sessions))) {
+            if (num_sessions < stdev->max_wdsp_sessions) {
                 if (common_sm->type == SOUND_MODEL_TYPE_KEYPHRASE) {
                     /* Keyphrase sound model */
                     if (check_phrases_users_available(v_info, num_phrases,
@@ -1466,10 +1453,7 @@
                 }
             } else {
                 /* Load on WDSP */
-                if ((!stdev->is_gcs &&
-                    (num_sessions < stdev->max_cpe_sessions)) ||
-                    (stdev->is_gcs &&
-                    (num_sessions < stdev->max_wdsp_sessions))) {
+                if (num_sessions < stdev->max_wdsp_sessions) {
                     if (common_sm->type == SOUND_MODEL_TYPE_KEYPHRASE) {
                         /* Keyphrase sound model */
                         if (check_phrases_users_available(v_info, num_phrases,
@@ -2087,15 +2071,6 @@
     st_hw_check_and_update_lpi(stdev, NULL);
     st_hw_check_and_set_lpi_mode(st_session);
 
-    /* CPE DRAM can only be accessed by single client, i.e. Apps or CPE,
-     * but not both in parallel. Sending params here can access DRAM.
-     * If another session is already active, stop it and restart after
-     * sending this session params.
-     * note: TODO: remove checking of "is_gcs" flag here
-     */
-    if ((ST_EXEC_MODE_CPE == st_session->exec_mode) && !stdev->is_gcs)
-        stop_other_sessions(stdev, st_session);
-
     status = st_session_load_sm(st_session);
     if (status) {
         goto exit_3;
@@ -2109,9 +2084,6 @@
         }
     }
 
-    if ((ST_EXEC_MODE_CPE == st_session->exec_mode) && !stdev->is_gcs)
-        start_other_sessions(stdev, st_session);
-
     /* Keyphrase, user information is valid only for keyphrase sound models */
     if ((common_sm->type == SOUND_MODEL_TYPE_KEYPHRASE) && (phrase_sm != NULL))
         update_available_phrase_info(st_session, phrase_sm, false);
@@ -2586,7 +2558,8 @@
 
 static int stdev_close(hw_device_t *device)
 {
-    struct sound_trigger_device *stdev = (struct sound_trigger_device *)device;
+    struct sound_trigger_device *st_device =
+        (struct sound_trigger_device *)device;
     st_session_t *st_session = NULL;
     struct listnode *node = NULL, *tmp_node = NULL;
     int status = 0;
@@ -2595,19 +2568,18 @@
     ATRACE_BEGIN("sthal: stdev_close");
 
     pthread_mutex_lock(&stdev_init_lock);
-    if (!stdev || (--stdev_ref_cnt != 0)) {
+    if (!st_device || (--stdev_ref_cnt != 0)) {
         goto exit;
     }
 
-    pthread_mutex_lock(&stdev->lock);
+    pthread_mutex_lock(&st_device->lock);
     sthw_extn_lpma_deinit();
-    platform_stdev_deinit(stdev->platform);
-    free(stdev->arm_pcm_use_cases);
-    if (!stdev->is_gcs)
-        free(stdev->cpe_pcm_use_cases);
-    free(stdev->ape_pcm_use_cases);
-    free(stdev->dev_ref_cnt);
-    list_for_each_safe(node, tmp_node, &stdev->sound_model_list) {
+    platform_stdev_deinit(st_device->platform);
+    free(st_device->arm_pcm_use_cases);
+    free(st_device->ape_pcm_use_cases);
+    free(st_device->dev_ref_cnt);
+    free(st_device->dev_enable_cnt);
+    list_for_each_safe(node, tmp_node, &st_device->sound_model_list) {
         st_session = node_to_item(node, st_session_t, list_node);
         list_remove(node);
         st_session_stop_lab(st_session);
@@ -2620,28 +2592,29 @@
         free(st_session);
     }
 
-    pthread_mutex_unlock(&stdev->lock);
+    pthread_mutex_unlock(&st_device->lock);
     hw_session_notifier_deinit();
 
-    if (stdev->transit_to_adsp_on_playback ||
-        stdev->transit_to_adsp_on_battery_charging) {
-        stdev->stop_transitions_thread_loop = true;
-        pthread_cond_signal(&stdev->transitions_cond);
-        status = pthread_join(stdev->transitions_thread, NULL);
+    if (st_device->transit_to_adsp_on_playback ||
+        st_device->transit_to_adsp_on_battery_charging) {
+        st_device->stop_transitions_thread_loop = true;
+        pthread_cond_signal(&st_device->transitions_cond);
+        status = pthread_join(st_device->transitions_thread, NULL);
         if (status)
             ALOGE("%s: Error joining transitions thread. status = %d",
                 __func__, status);
     }
 
-    pthread_mutex_destroy(&stdev->lock);
-    pthread_mutex_destroy(&stdev->ref_cnt_lock);
+    pthread_mutex_destroy(&st_device->lock);
+    pthread_mutex_destroy(&st_device->ref_cnt_lock);
     free(device);
     stdev = NULL;
 
 exit:
     pthread_mutex_unlock(&stdev_init_lock);
     ATRACE_END();
-    ALOGD("%s: Exit device=%p cnt=%d ", __func__, stdev, stdev_ref_cnt);
+    ALOGD("%s: Exit device=%p cnt=%d ", __func__, st_device,
+        stdev_ref_cnt);
     return 0;
 }
 
@@ -2698,17 +2671,6 @@
         goto exit_1;
     }
 
-    if (!stdev->is_gcs) {
-        stdev->cpe_pcm_use_cases =
-            calloc(stdev->max_cpe_sessions, sizeof(struct use_case_info));
-
-        if (!stdev->cpe_pcm_use_cases) {
-            ALOGE("%s: ERROR. Mem alloc failed for cpe use cases", __func__);
-            status = -ENODEV;
-            goto exit_1;
-        }
-    }
-
     /* Each arm session is associated with corresponding ec ref session */
     stdev->arm_pcm_use_cases =
         calloc(stdev->max_arm_sessions * 2, sizeof(struct use_case_info));
@@ -2728,6 +2690,15 @@
         goto exit_1;
     }
 
+    stdev->dev_enable_cnt =
+        calloc(ST_EXEC_MODE_MAX * ST_DEVICE_MAX, sizeof(int));
+
+    if (!stdev->dev_enable_cnt) {
+        ALOGE("%s: ERROR. Mem alloc failed dev enable cnt", __func__);
+        status = -ENOMEM;
+        goto exit_1;
+    }
+
     if (hw_session_notifier_init(stdev_session_event_cb) < 0) {
         ALOGE("%s: Failed to initialize notifier", __func__);
         status = -ENOMEM;
@@ -2790,12 +2761,12 @@
     if (stdev->dev_ref_cnt)
         free(stdev->dev_ref_cnt);
 
+    if (stdev->dev_enable_cnt)
+        free(stdev->dev_enable_cnt);
+
     if (stdev->arm_pcm_use_cases)
         free(stdev->arm_pcm_use_cases);
 
-    if (stdev->cpe_pcm_use_cases)
-        free(stdev->cpe_pcm_use_cases);
-
     if (stdev->ape_pcm_use_cases)
         free(stdev->ape_pcm_use_cases);
 
@@ -2885,8 +2856,11 @@
     st_exec_mode_t exec_mode = 0;
     sound_model_handle_t sm_handle = 0;
 
-    if (!stdev)
+    pthread_mutex_lock(&stdev_init_lock);
+    if (!stdev) {
+        pthread_mutex_unlock(&stdev_init_lock);
         return -ENODEV;
+    }
 
     switch (event) {
     case AUDIO_EVENT_PLAYBACK_STREAM_INACTIVE:
@@ -3122,6 +3096,7 @@
         break;
     }
 
+    pthread_mutex_unlock(&stdev_init_lock);
     return ret;
 }
 
diff --git a/sound_trigger_hw.h b/sound_trigger_hw.h
index d1d725e..85b33eb 100644
--- a/sound_trigger_hw.h
+++ b/sound_trigger_hw.h
@@ -178,6 +178,7 @@
     pthread_mutex_t ref_cnt_lock;
     int *dev_ref_cnt;
     struct listnode available_devices;
+    int *dev_enable_cnt;
     pthread_t transitions_thread;
     pthread_cond_t transitions_cond;
 
@@ -218,7 +219,6 @@
 
     unsigned int rx_conc_max_st_ses;
     struct use_case_info *ape_pcm_use_cases;
-    struct use_case_info *cpe_pcm_use_cases;
     struct use_case_info *arm_pcm_use_cases;
     bool detect_failure;
     void *platform;
@@ -245,11 +245,6 @@
     getSizeAfterDeleting_t smlib_getSizeAfterDeleting;
     deleteFromModel_t smlib_deleteFromModel;
 
-    void *adpcm_dec_lib_handle;
-    g722_init_decoder_t adpcm_dec_init;
-    g722_dec_get_total_byte_size_t adpcm_dec_get_scratch_size;
-    g722_dec_process_t adpcm_dec_process;
-
     void *mulaw_dec_lib_handle;
     mulaw_dec_process_t mulaw_dec_process;
 
diff --git a/sound_trigger_platform.c b/sound_trigger_platform.c
index d6fd3ec..18e59e2 100644
--- a/sound_trigger_platform.c
+++ b/sound_trigger_platform.c
@@ -80,7 +80,6 @@
 #define ST_PARAM_KEY_SW_MAD "sw_mad"
 #define ST_PARAM_KEY_BG_KWD "bg_kwd"
 #define ST_PARAM_KEY_ENABLE_FAILURE_DETECTION "enable_failure_detection"
-#define ST_PARAM_KEY_CPE_FE_TO_BE_FIXED "cpe_fe_to_be_fixed"
 #define ST_PARAM_KEY_RX_CONCURRENCY_DISABLED "rx_concurrency_disabled"
 #define ST_PARAM_KEY_RX_MAX_CONC_SESSIONS "rx_conc_max_st_ses"
 #define ST_PARAM_KEY_CONCURRENT_CAPTURE "concurrent_capture"
@@ -398,7 +397,6 @@
     st_xml_tags_t st_xml_tag;
     struct str_parms *kvpairs;
 
-    bool cpe_fe_to_be_fixed;
     char codec_version[15];
 
     char backend_port[ST_BACKEND_PORT_NAME_MAX_SIZE];
@@ -567,39 +565,6 @@
     return status;
 }
 
-static int load_adpcm_decoder(sound_trigger_device_t *stdev)
-{
-    int status = 0;
-
-    stdev->adpcm_dec_lib_handle = dlopen(LIB_ADPCM_DECODER, RTLD_NOW);
-    if (!stdev->adpcm_dec_lib_handle) {
-        ALOGE("%s: ERROR. %s", __func__, dlerror());
-        return -ENODEV;
-    }
-
-    DLSYM(stdev->adpcm_dec_lib_handle, stdev->adpcm_dec_init,
-          g722_init_decoder, status);
-    if (status)
-        goto cleanup;
-    DLSYM(stdev->adpcm_dec_lib_handle, stdev->adpcm_dec_get_scratch_size,
-          g722_dec_get_total_byte_size, status);
-    if (status)
-        goto cleanup;
-    DLSYM(stdev->adpcm_dec_lib_handle, stdev->adpcm_dec_process,
-          g722_dec_process, status);
-    if (status)
-        goto cleanup;
-
-    return 0;
-
-cleanup:
-    if (stdev->adpcm_dec_lib_handle) {
-        dlclose(stdev->adpcm_dec_lib_handle);
-        stdev->adpcm_dec_lib_handle = NULL;
-    }
-    return status;
-}
-
 static int platform_stdev_set_acdb_id(void *userdata __unused, const char* device, int acdb_id)
 {
     int i, j;
@@ -745,7 +710,6 @@
     stdev->support_dynamic_ec_update = true;
     stdev->ec_reset_pending_cnt = 0;
 
-    platform->cpe_fe_to_be_fixed = true;
     platform->bad_mic_channel_index = 0;
     platform->be_dai_name_table = NULL;
     platform->max_be_dai_names = 0;
@@ -902,11 +866,7 @@
         ret = -EINVAL;
         goto error_exit;
     }
-    if (!strcmp(id, "ADPCM_packet")) {
-        sm_info->kw_capture_format |= ADPCM_CUSTOM_PACKET;
-    } else if (!strcmp(id, "ADPCM_raw")) {
-        sm_info->kw_capture_format |= ADPCM_RAW;
-    } else if (!strcmp(id, "MULAW_raw")) {
+    if (!strcmp(id, "MULAW_raw")) {
         sm_info->kw_capture_format |= MULAW_RAW;
     } else if (!strcmp(id, "PCM_packet")) {
         sm_info->kw_capture_format |= PCM_CUSTOM_PACKET;
@@ -997,14 +957,6 @@
             !strncasecmp(str_value, "true", 4) ? true : false;
     }
 
-    err = str_parms_get_str(parms, ST_PARAM_KEY_CPE_FE_TO_BE_FIXED,
-                            str_value, sizeof(str_value));
-    if (err >= 0) {
-        str_parms_del(parms, ST_PARAM_KEY_CPE_FE_TO_BE_FIXED);
-        my_data->cpe_fe_to_be_fixed =
-            !strncasecmp(str_value, "true", 4) ? true : false;
-    }
-
     err = str_parms_get_str(parms, ST_PARAM_KEY_RX_CONCURRENCY_DISABLED,
                             str_value, sizeof(str_value));
     if (err >= 0) {
@@ -3167,13 +3119,13 @@
  */
 static int clear_devices(struct listnode *devices)
 {
-    struct listnode *node = NULL;
+    struct listnode *node = NULL, *temp = NULL;
     struct audio_device_info *item = NULL;
 
     if (devices == NULL)
         return 0;
 
-    list_for_each (node, devices) {
+    list_for_each_safe (node, temp, devices) {
         item = node_to_item(node, struct audio_device_info, list);
         if (item != NULL) {
             list_remove(&item->list);
@@ -3899,12 +3851,6 @@
             v_info->merge_fs_soundmodels = false;
             ALOGV("%s: ISV uuid present", __func__);
         }
-        if (!stdev->adpcm_dec_lib_handle &&
-             (v_info->kw_capture_format & ADPCM)) {
-            ret = load_adpcm_decoder(stdev);
-            if (ret)
-                goto cleanup;
-        }
         if (!stdev->mulaw_dec_lib_handle &&
              (v_info->kw_capture_format & MULAW)) {
             ret = load_mulaw_decoder(stdev);
@@ -3946,9 +3892,6 @@
     if (stdev->mulaw_dec_lib_handle)
         dlclose(stdev->mulaw_dec_lib_handle);
 
-    if (stdev->adpcm_dec_lib_handle)
-        dlclose(stdev->adpcm_dec_lib_handle);
-
     if (my_data->acdb_handle)
         dlclose(my_data->acdb_handle);
 
@@ -4035,8 +3978,6 @@
         dlclose(my_data->acdb_handle);
         if (my_data->stdev->smlib_handle)
             dlclose(my_data->stdev->smlib_handle);
-        if (my_data->stdev->adpcm_dec_lib_handle)
-            dlclose(my_data->stdev->adpcm_dec_lib_handle);
         if (my_data->stdev->mulaw_dec_lib_handle)
             dlclose(my_data->stdev->mulaw_dec_lib_handle);
         audio_route_free(my_data->stdev->audio_route);
@@ -4386,6 +4327,30 @@
     return my_data->codec_backend_cfg.lpi_enable;
 }
 
+int platform_get_lpi_st_device(int st_device)
+{
+    int lpi_device = st_device;
+
+    switch (st_device) {
+    case ST_DEVICE_HANDSET_DMIC:
+        lpi_device = ST_DEVICE_HANDSET_DMIC_LPI;
+        break;
+    case ST_DEVICE_HANDSET_TMIC:
+        lpi_device = ST_DEVICE_HANDSET_TMIC_LPI;
+        break;
+    case ST_DEVICE_HANDSET_QMIC:
+        lpi_device = ST_DEVICE_HANDSET_QMIC_LPI;
+        break;
+    case ST_DEVICE_HEADSET_MIC:
+        lpi_device = ST_DEVICE_HEADSET_MIC_LPI;
+        break;
+    default:
+        ALOGV("%s: No need to convert device %d", __func__, st_device);
+    }
+
+    return lpi_device;
+}
+
 #ifdef SNDRV_IOCTL_HWDEP_VAD_CAL_TYPE
 static int platform_stdev_send_hwvad_cal
 (
@@ -4785,35 +4750,14 @@
 
 void platform_stdev_check_and_update_pcm_config
 (
-   void *platform,
    struct pcm_config *config,
-   struct st_vendor_info *v_info,
-   enum st_exec_mode exec_mode
+   struct st_vendor_info *v_info
 )
 {
-    struct platform_data *my_data = (struct platform_data *)platform;
-    const char *snd_card_name;
-
     /* Update config with params in vendor info */
     config->rate = v_info->sample_rate;
     config->format = v_info->format;
     config->channels = v_info->out_channels;
-
-    if (exec_mode == ST_EXEC_MODE_CPE && !my_data->stdev->is_gcs) {
-        snd_card_name = mixer_get_name(my_data->stdev->mixer);
-        if (strstr(snd_card_name, "tomtom") ||
-            strstr(my_data->codec_version, "WCD9335_1_0") ||
-            strstr(my_data->codec_version, "WCD9335_1_1")) {
-            /* tomtom, Tasha1.0, Tasha1.1 support max 16KHz/24bit bandwidth */
-            config->rate = SOUND_TRIGGER_SAMPLING_RATE_16000;
-            if (config->format != PCM_FORMAT_S16_LE)
-                config->format = PCM_FORMAT_S24_LE;
-        } else {
-            /* Other codecs configured at ftrt 384Khz/32bit */
-            config->rate = SOUND_TRIGGER_SAMPLING_RATE_384000;
-            config->format = PCM_FORMAT_S32_LE;
-        }
-    }
 }
 
 int platform_stdev_connect_mad
@@ -4885,18 +4829,6 @@
                 ALOGE("%s: ERROR. adsp pcm dev_id parse failed", __func__);
 
             snprintf(comp_string, USECASE_STRING_SIZE, "Listen %d Audio Service", i+1);
-        } else if (strstr(line, "CPE Listen") && (j < stdev->max_cpe_sessions)) {
-            stdev->hw_type |= ST_DEVICE_HW_CPE;
-            /* store the Back End types associated with the Front End*/
-            if (strstr(line, "ECPP"))
-                stdev->cpe_pcm_use_cases[j].pcm_back_end = CPE_PCM_BACK_END_ECPP;
-            else
-                stdev->cpe_pcm_use_cases[j].pcm_back_end = CPE_PCM_BACK_END_DEFAULT;
-
-            if (sscanf(&line[3], "%d", &dev_id) == 1)
-                stdev->cpe_pcm_use_cases[j++].pcm_id = dev_id;
-            else
-                ALOGE("%s: ERROR. cpe pcm dev_id parse failed", __func__);
         } else if (strstr(line, CAPTURE_PCM_USECASE_STRING)) {
             stdev->hw_type |= ST_DEVICE_HW_ARM;
             if (sscanf(&line[3], "%d", &dev_id) == 1)
@@ -4946,47 +4878,6 @@
     return 0;
 }
 
-int platform_cpe_get_pcm_device_id
-(
-   void *platform,
-   int sample_rate,
-   unsigned int* use_case_idx
-)
-{
-    struct platform_data *my_data = (struct platform_data *)platform;
-    sound_trigger_device_t *stdev = my_data->stdev;
-    unsigned int i;
-    int ret = -1;
-    bool found = false;
-
-    for (i = 0; i < stdev->max_cpe_sessions; i++) {
-        if (!stdev->cpe_pcm_use_cases[i].active) {
-            /* pcm device nodes are fixed based on backend types. Check for
-            supported combination. */
-            if (my_data->cpe_fe_to_be_fixed &&
-                sample_rate == SOUND_TRIGGER_SAMPLING_RATE_48000) {
-                if (stdev->cpe_pcm_use_cases[i].pcm_back_end == CPE_PCM_BACK_END_ECPP) {
-                    found = true;
-                }
-            } else {
-                found = true;
-            }
-
-            if (found) {
-                stdev->cpe_pcm_use_cases[i].active = true;
-                ret = stdev->cpe_pcm_use_cases[i].pcm_id;
-                *use_case_idx = i;
-                break;
-            }
-        }
-    }
-
-    if (ret < 0)
-        ALOGE("%s: ERROR. no free pcm device available", __func__);
-
-    return ret;
-}
-
 int platform_ape_get_pcm_device_id
 (
    void *platform,
@@ -5030,24 +4921,6 @@
     }
 }
 
-void platform_cpe_free_pcm_device_id
-(
-   void *platform,
-   int pcm_id
-)
-{
-    struct platform_data *my_data = (struct platform_data *)platform;
-    sound_trigger_device_t *stdev = my_data->stdev;
-    unsigned int i;
-
-    for (i = 0; i < stdev->max_cpe_sessions; i++) {
-        if (stdev->cpe_pcm_use_cases[i].pcm_id == pcm_id) {
-            stdev->cpe_pcm_use_cases[i].active = false;
-            break;
-        }
-    }
-}
-
 int platform_arm_get_pcm_device_id
 (
    void *platform,
@@ -5694,10 +5567,12 @@
     if (is_ec_profile(profile_type)) {
         event_info.st_ec_ref_enabled = enable;
         // reset the pending active EC mixer ctls first
-        if (!stdev->audio_ec_enabled && stdev->ec_reset_pending_cnt > 0) {
-            while (stdev->ec_reset_pending_cnt--)
+        if (!stdev->audio_ec_enabled) {
+            while (stdev->ec_reset_pending_cnt > 0) {
                 audio_route_reset_and_update_path(stdev->audio_route,
                         my_data->ec_ref_mixer_path);
+                stdev->ec_reset_pending_cnt--;
+            }
         }
         if (enable) {
             stdev->audio_hal_cb(ST_EVENT_UPDATE_ECHO_REF, &event_info);
diff --git a/sound_trigger_platform.h b/sound_trigger_platform.h
index 7768e05..3686e5e 100644
--- a/sound_trigger_platform.h
+++ b/sound_trigger_platform.h
@@ -64,7 +64,6 @@
 #define MIXER_PATH_FILE_NAME_BG "/vendor/etc/sound_trigger_mixer_paths_bg"
 
 #define LIB_ACDB_LOADER "libacdbloader.so"
-#define LIB_ADPCM_DECODER "libadpcmdec.so"
 #define LIB_MULAW_DECODER "libmulawdec.so"
 #define LIB_SVA_SOUNDMODEL "liblistensoundmodel2.so"
 
@@ -195,12 +194,9 @@
 };
 
 typedef enum {
-    ADPCM_CUSTOM_PACKET = 0x01,
-    ADPCM_RAW = 0x02,
     PCM_CUSTOM_PACKET = 0x04,
     PCM_RAW = 0x08,
     MULAW_RAW = 0x10,
-    ADPCM = (ADPCM_CUSTOM_PACKET | ADPCM_RAW),
     PCM = (PCM_CUSTOM_PACKET | PCM_RAW),
     MULAW = MULAW_RAW
 } st_capture_format_t;
@@ -507,21 +503,12 @@
 
 void platform_stdev_check_and_update_pcm_config
 (
-   void *platform,
    struct pcm_config *config,
-   struct st_vendor_info *v_info,
-   enum st_exec_mode exec_mode
+   struct st_vendor_info *v_info
 );
 
 int platform_stdev_get_hw_type(void *platform);
 
-int platform_cpe_get_pcm_device_id
-(
-   void *platform,
-   int sample_rate,
-   unsigned int* use_case_idx
-);
-
 int platform_ape_get_pcm_device_id
 (
    void *platform,
@@ -534,12 +521,6 @@
    int pcm_id
 );
 
-void platform_cpe_free_pcm_device_id
-(
-   void *platform,
-   int pcm_id
-);
-
 int platform_arm_get_pcm_device_id
 (
    void *platform,
@@ -671,6 +652,8 @@
 
 bool platform_get_lpi_mode(void *my_data);
 
+int platform_get_lpi_st_device(int st_device);
+
 void platform_stdev_reset_backend_cfg(void *platform);
 
 void platform_stdev_get_lpma_config
diff --git a/st_hw_common.c b/st_hw_common.c
index 3c31a2c..e0dab3d 100644
--- a/st_hw_common.c
+++ b/st_hw_common.c
@@ -3,7 +3,7 @@
  * This file contains common functionality between
  * sound trigger hw and sound trigger extension interface.
  *
- * Copyright (c) 2016, 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016, 2018-2020, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -414,27 +414,24 @@
     hist_buf = (struct st_hist_buffer_info *) payload_buf;
     hist_buf->version = DEFAULT_CUSTOM_CONFIG_MINOR_VERSION;
 
+    hist_buf->pre_roll_duration_msec = p_ses->sthw_cfg.client_req_preroll;
+
+    if (p_ses->is_generic_event &&
+            p_ses->sthw_cfg.client_req_preroll < PREROLL_LEN_WARNING)
+        ALOGW("%s: Client requested small preroll length %dms",
+              __func__, p_ses->sthw_cfg.client_req_preroll);
+
     if (p_ses->sthw_cfg.client_req_hist_buf > 0) {
         hist_buf->hist_buffer_duration_msec =
             p_ses->sthw_cfg.client_req_hist_buf;
-        hist_buf->pre_roll_duration_msec = p_ses->sthw_cfg.client_req_preroll;
 
-        if (p_ses->is_generic_event) {
-            if (p_ses->sthw_cfg.client_req_hist_buf <=
-                (p_ses->sthw_cfg.client_req_preroll + KW_LEN_WARNING))
-                ALOGW("%s: Client hist buf and preroll lens leave only"
-                      "%dms for keyword", __func__,
-                      (p_ses->sthw_cfg.client_req_hist_buf -
-                       p_ses->sthw_cfg.client_req_preroll));
-
-            if (p_ses->sthw_cfg.client_req_preroll < PREROLL_LEN_WARNING)
-                ALOGW("%s: Client requested small preroll length %dms",
-                    __func__, p_ses->sthw_cfg.client_req_preroll);
-        }
+        if (p_ses->is_generic_event &&
+                p_ses->sthw_cfg.client_req_hist_buf <= KW_LEN_WARNING)
+                ALOGW("%s: Client requested small hist buf length %dms",
+                      __func__, p_ses->sthw_cfg.client_req_hist_buf);
     } else {
         hist_buf->hist_buffer_duration_msec =
             p_ses->vendor_uuid_info->kw_duration;
-        hist_buf->pre_roll_duration_msec = 0;
     }
     ALOGD("%s: history buf duration %d, preroll %d", __func__,
           hist_buf->hist_buffer_duration_msec,
diff --git a/st_hw_session.h b/st_hw_session.h
index 4a8218d..6188d10 100644
--- a/st_hw_session.h
+++ b/st_hw_session.h
@@ -3,7 +3,7 @@
  * This file contains the API to load sound models with
  * DSP and start/stop detection of associated key phrases.
  *
- * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -50,6 +50,7 @@
 
 typedef enum st_hw_sess_event_id {
     ST_HW_SESS_EVENT_DETECTED,
+    ST_HW_SESS_EVENT_BUFFERING_STOPPED,
     ST_HW_SESS_EVENT_MAX
 }  st_hw_sess_event_id_t;
 
diff --git a/st_hw_session_gcs.c b/st_hw_session_gcs.c
index 53037b7..5131651 100644
--- a/st_hw_session_gcs.c
+++ b/st_hw_session_gcs.c
@@ -3,7 +3,7 @@
  * This file implements the hw session functionality specific to HW
  * sessions that use GCS.
  *
- * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -556,9 +556,7 @@
     }
 
     p_ses->config = stdev_cpe_pcm_config;
-    platform_stdev_check_and_update_pcm_config(p_ses->stdev->platform,
-                                               &p_ses->config, v_info,
-                                               p_ses->exec_mode);
+    platform_stdev_check_and_update_pcm_config(&p_ses->config, v_info);
 
     ALOGD("%s:[%d] calling gcs_open with uid %d, did %d", __func__,
         p_ses->sm_handle, p_gcs_ses->gcs_usecase->uid, device_acdb_id);
diff --git a/st_hw_session_lsm.c b/st_hw_session_lsm.c
index 6ef9673..9b41c03 100644
--- a/st_hw_session_lsm.c
+++ b/st_hw_session_lsm.c
@@ -74,18 +74,7 @@
 static int ape_stop(st_hw_session_t* p_ses);
 static int ape_stop_buffering(st_hw_session_t* p_ses);
 
-static int cpe_reg_sm(st_hw_session_t* p_ses,void *sm_data, unsigned int sm_size, sound_trigger_sound_model_type_t sm_type);
-static int cpe_reg_sm_params(st_hw_session_t* p_ses, unsigned int recognition_mode,
-    bool capture_requested, struct sound_trigger_recognition_config *rc_config,
-    sound_trigger_sound_model_type_t sm_type, void *sm_data);
-
-static int cpe_dereg_sm(st_hw_session_t* p_ses);
-static int cpe_dereg_sm_params(st_hw_session_t* p_ses);
-static int cpe_start(st_hw_session_t* p_ses);
-static int cpe_stop(st_hw_session_t* p_ses);
-static int cpe_stop_buffering(st_hw_session_t *p_ses);
-
-/* Routing layer functions to route to either ADSP or CPE */
+/* Routing layer functions */
 static int route_reg_sm_ape(st_hw_session_t *p_ses,
     void *sm_data, unsigned int sm_size, sound_trigger_sound_model_type_t sm_type);
 static int route_reg_sm_params_ape(st_hw_session_t* p_ses,
@@ -109,28 +98,6 @@
                               unsigned int bytes);
 static void route_audio_capture_ape(st_hw_session_t* p_ses);
 static int route_send_custom_chmix_coeff_ape(st_hw_session_t *p_ses, char *str);
-
-static int route_reg_sm_cpe(st_hw_session_t *p_ses,
-    void *sm_data, unsigned int sm_size, sound_trigger_sound_model_type_t sm_type);
-static int route_reg_sm_params_cpe(st_hw_session_t* p_ses,
-    unsigned int recognition_mode, bool capture_requested,
-    struct sound_trigger_recognition_config *rc_config,
-    sound_trigger_sound_model_type_t sm_type, void *sm_data);
-static int route_dereg_sm_cpe(st_hw_session_t* p_ses);
-static int route_dereg_sm_params_cpe(st_hw_session_t* p_ses);
-static int route_start_cpe(st_hw_session_t* p_ses);
-static int route_restart(st_hw_session_t* p_ses, unsigned int recognition_mode,
-   struct sound_trigger_recognition_config *rc_config __unused,
-   sound_trigger_sound_model_type_t sm_type, void *sm_data);
-static int route_stop_cpe(st_hw_session_t* p_ses);
-static int route_stop_buffering_cpe(st_hw_session_t* p_ses);
-static int route_set_device_cpe(st_hw_session_t* p_ses,
-                                bool enable);
-static int route_read_pcm_cpe(st_hw_session_t *p_ses,
-                              unsigned char *buf,
-                              unsigned int bytes);
-static void route_audio_capture_cpe(st_hw_session_t* p_ses);
-static int route_send_custom_chmix_coeff_cpe(st_hw_session_t *p_ses, char *str);
 static int route_disable_device(st_hw_session_t *p_ses, bool setting_device);
 static int route_enable_device(st_hw_session_t *p_ses, bool setting_device);
 static void request_exit_callback_thread(st_hw_session_lsm_t *p_lsm_ses);
@@ -138,8 +105,6 @@
     void *payload, size_t payload_size, size_t *param_data_size);
 static int send_detection_request(st_hw_session_t *p_ses);
 
-static int dbg_trace_lab_buf_cnt = -1;
-
 typedef struct {
     int16_t target_angle_L16[MAX_DOA_TRACKING_ANGLES];
     int16_t interf_angle_L16[MAX_DOA_TRACKING_ANGLES];
@@ -154,14 +119,6 @@
     .format = PCM_FORMAT_S16_LE,
 };
 
-static struct pcm_config stdev_cpe_pcm_config = {
-    .channels = SOUND_TRIGGER_CHANNEL_MODE_MONO,
-    .rate = SOUND_TRIGGER_SAMPLING_RATE_16000,
-    .period_size = SOUND_TRIGGER_CPE_PERIOD_SIZE,
-    .period_count = SOUND_TRIGGER_CPE_PERIOD_COUNT,
-    .format = PCM_FORMAT_S16_LE,
-};
-
 struct st_session_fptrs ape_fptrs = {
 
     .reg_sm = route_reg_sm_ape ,
@@ -182,25 +139,6 @@
     .send_detection_request = send_detection_request,
 };
 
-struct st_session_fptrs cpe_fptrs = {
-    .reg_sm = route_reg_sm_cpe ,
-    .reg_sm_params = route_reg_sm_params_cpe,
-    .dereg_sm = route_dereg_sm_cpe  ,
-    .dereg_sm_params = route_dereg_sm_params_cpe,
-    .start = route_start_cpe,
-    .restart = route_restart,
-    .stop = route_stop_cpe,
-    .stop_buffering = route_stop_buffering_cpe,
-    .set_device = route_set_device_cpe,
-    .read_pcm = route_read_pcm_cpe,
-    .process_lab_capture = route_audio_capture_cpe,
-    .send_custom_chmix_coeff = route_send_custom_chmix_coeff_cpe,
-    .disable_device = route_disable_device,
-    .enable_device = route_enable_device,
-    .get_param_data = get_param_data,
-    .send_detection_request = send_detection_request,
-};
-
 int pcm_ioctl(struct pcm *pcm, int request, ...)
 {
     va_list ap;
@@ -376,10 +314,6 @@
     struct st_vendor_info *v_info = p_lsm_ses->common.vendor_uuid_info;
     unsigned int fwk_mode = LSM_EVENT_NON_TIME_STAMP_MODE;
 
-    /* set fwk mode is not supported in CPE mode */
-    if (p_lsm_ses->common.exec_mode == ST_EXEC_MODE_CPE)
-        return 0;
-
     if (v_info && (v_info->fwk_mode == SOUND_TRIGGER_EVENT_TIME_STAMP_MODE))
         fwk_mode = LSM_EVENT_TIME_STAMP_MODE;
 
@@ -585,21 +519,6 @@
     return profile_type;
 }
 
-void check_and_exit_lab(st_hw_session_t *p_ses)
-{
-    st_hw_session_lsm_t *p_lsm_ses =
-        (st_hw_session_lsm_t *)p_ses;
-
-    if ((p_lsm_ses->lab_buffers_allocated && !p_lsm_ses->exit_lab_processing) &&
-        CHECK_STATE(p_lsm_ses->common.state, SES_BUFFERING)) {
-
-        pthread_mutex_lock(&p_lsm_ses->lock);
-        p_lsm_ses->exit_lab_processing = true;
-        pthread_cond_signal(&p_lsm_ses->cond);
-        pthread_mutex_unlock(&p_lsm_ses->lock);
-    }
-}
-
 static void ape_enable_use_case(bool enable, st_hw_session_t *p_ses)
 {
     st_hw_session_lsm_t *p_lsm_ses = (st_hw_session_lsm_t *)p_ses;
@@ -760,86 +679,6 @@
     return 0;
 }
 
-static int write_pcm_data_cpe(st_hw_session_lsm_t *p_lsm_ses,
-                     unsigned char *buf,
-                     unsigned int bytes)
-{
-    unsigned int free_bytes = 0, write_bytes = 0;
-    int status = 0;
-    struct listnode *node = NULL, *tmp_node = NULL;
-    st_arm_second_stage_t *st_sec_stage = NULL;
-
-    pthread_mutex_lock(&p_lsm_ses->lock);
-
-    while (!p_lsm_ses->exit_lab_processing && (bytes > 0)) {
-        free_bytes = p_lsm_ses->common.buffer->size -
-            p_lsm_ses->common.buffer->unread_bytes;
-        if (!free_bytes) {
-            ALOGVV("%s: waiting on cond, bytes=%d", __func__, bytes);
-            /* wait till space is avaialable to write */
-            pthread_cond_wait(&p_lsm_ses->cond, &p_lsm_ses->lock);
-            if (p_lsm_ses->exit_lab_processing) {
-                 ALOGVV("%s: buffering stopped while waiting on cond, exiting", __func__);
-                pthread_mutex_unlock(&p_lsm_ses->lock);
-                return -EIO;
-            }
-        }
-        write_bytes = MIN(bytes, free_bytes);
-
-        status = st_buffer_write(p_lsm_ses->common.buffer, buf, write_bytes);
-        if (status) {
-            p_lsm_ses->exit_lab_processing = true;
-            if (p_lsm_ses->common.enable_second_stage) {
-                list_for_each_safe(node, tmp_node, p_lsm_ses->common.second_stage_list) {
-                    st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
-                    pthread_mutex_lock(&st_sec_stage->ss_session->lock);
-                    ALOGW("%s: Exit 2nd stage processing due to buf overflow",
-                        __func__);
-                    st_sec_stage->ss_session->exit_buffering = true;
-                    pthread_cond_signal(&st_sec_stage->ss_session->cond);
-                    pthread_mutex_unlock(&st_sec_stage->ss_session->lock);
-                }
-            }
-            goto exit;
-        }
-        ALOGV("%s: about to signal condition", __func__);
-        pthread_cond_signal(&p_lsm_ses->cond);
-        bytes -= write_bytes;
-        buf += write_bytes;
-        p_lsm_ses->unread_bytes += write_bytes;
-        p_lsm_ses->bytes_written += write_bytes;
-    }
-
-    if (p_lsm_ses->common.enable_second_stage) {
-        list_for_each_safe(node, tmp_node, p_lsm_ses->common.second_stage_list) {
-            st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
-
-            /*
-             * When the current written frame passes the number of bytes indicated
-             * in buf_start, give the second stage session its read pointer.
-             */
-            pthread_mutex_lock(&st_sec_stage->ss_session->lock);
-            if ((p_lsm_ses->bytes_written >= st_sec_stage->ss_session->buf_start) &&
-                !st_sec_stage->ss_session->start_processing) {
-                st_sec_stage->ss_session->hw_rd_ptr =
-                    st_buffer_get_wr_ptr(p_lsm_ses->common.buffer);
-                st_sec_stage->ss_session->hw_rd_ptr -= bytes;
-                st_sec_stage->ss_session->start_processing = true;
-            }
-
-            if (st_sec_stage->ss_session->start_processing) {
-                st_sec_stage->ss_session->unread_bytes += bytes;
-                pthread_cond_signal(&st_sec_stage->ss_session->cond);
-            }
-            pthread_mutex_unlock(&st_sec_stage->ss_session->lock);
-        }
-    }
-
-exit:
-    pthread_mutex_unlock(&p_lsm_ses->lock);
-    return 0;
-}
-
 static int write_pcm_data_ape(st_hw_session_lsm_t *p_lsm_ses,
                      unsigned char *buf,
                      unsigned int bytes)
@@ -898,59 +737,6 @@
     return status;
 }
 
-static bool search_for_syncword(st_hw_session_lsm_t *p_ses,
-                                unsigned char *in_buf,
-                                unsigned int in_size,
-                                unsigned int *pos)
-{
-
-    unsigned char *buf_ptr = in_buf;
-    unsigned int inc_bytes = 2;
-
-    /* S16_LE is sampled at 16bit boundary, 24_LE and 32_LE will be
-       sampled at 4byte boundary */
-    if ((p_ses->lab_config.format == PCM_FORMAT_S32_LE) ||
-        (p_ses->lab_config.format == PCM_FORMAT_S24_LE)) {
-        inc_bytes += 2;
-    }
-    *pos = 0;
-
-    while (buf_ptr < (in_buf + in_size)) {
-        if (*buf_ptr == CPE_PACKET_SYNC_WORD) {
-            *pos = buf_ptr - in_buf;
-            ALOGVV("%s: first syncword found at idx %d for format %d",
-                   __func__, *pos, p_ses->lab_config.format);
-            return true;
-        }
-        buf_ptr += inc_bytes;
-    }
-    return false;
-}
-
-static void get_ftrt_processing_data(st_hw_session_lsm_t *p_ses,
-                              unsigned char *in_buf,
-                              unsigned int in_size,
-                              unsigned char **out_buf,
-                              unsigned int *out_size)
-{
-    unsigned char *src, *dst;
-
-    if (p_ses->lab_config.format == PCM_FORMAT_S24_LE) {
-        /* Construct ftrt packed buffer without gaps by skipping MSB byte */
-        src = dst = in_buf;
-        while (src < (in_buf + in_size)) {
-            memmove(dst, src, 3);
-            src += 4;
-            dst += 3;
-        }
-        *out_buf = in_buf;
-        *out_size = (dst - *out_buf);
-    } else {
-        *out_buf = in_buf;
-        *out_size = in_size;
-    }
-}
-
 static void adjust_ss_buff_end(st_hw_session_t *p_ses,
     uint32_t cnn_append_bytes, uint32_t vop_append_bytes)
 {
@@ -985,413 +771,10 @@
     }
 }
 
-void process_raw_lab_data_cpe(st_hw_session_lsm_t *p_lsm_ses)
+static void *buffer_thread_loop(void *context)
 {
-    int status = 0;
-    struct listnode *node = NULL, *tmp_node = NULL;
-    st_arm_second_stage_t *st_sec_stage = NULL;
-    unsigned int prepend_bytes = 0, cnn_append_bytes = 0, vop_append_bytes = 0;
-    unsigned int kw_duration_bytes = 0;
-    bool real_time_check = false;
-    uint64_t frame_receive_time = 0, frame_send_time = 0;
-    uint64_t frame_read_time = 0;
-
-    ST_DBG_DECLARE(FILE *fptr_drv = NULL; static int file_cnt = 0);
-    if (p_lsm_ses->common.stdev->enable_debug_dumps) {
-        ST_DBG_FILE_OPEN_WR(fptr_drv, ST_DEBUG_DUMP_LOCATION,
-                            "st_lab_drv_data_cpe", "pcm", file_cnt++);
-    }
-
-    p_lsm_ses->lab_processing_active = true;
-    p_lsm_ses->unread_bytes = 0;
-    p_lsm_ses->bytes_written = 0;
-
-    st_buffer_reset(p_lsm_ses->common.buffer);
-
-    if (p_lsm_ses->common.enable_second_stage) {
-        prepend_bytes =
-            convert_ms_to_bytes(
-                p_lsm_ses->common.vendor_uuid_info->kw_start_tolerance,
-                &p_lsm_ses->common.config);
-        if (p_lsm_ses->common.sthw_cfg.client_req_hist_buf) {
-            kw_duration_bytes =
-                convert_ms_to_bytes(
-                    p_lsm_ses->common.sthw_cfg.client_req_hist_buf,
-                    &p_lsm_ses->common.config);
-        } else {
-            kw_duration_bytes =
-                convert_ms_to_bytes(
-                    p_lsm_ses->common.vendor_uuid_info->kw_duration,
-                    &p_lsm_ses->common.config);
-        }
-
-        list_for_each_safe(node, tmp_node, p_lsm_ses->common.second_stage_list) {
-            st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
-
-            pthread_mutex_lock(&st_sec_stage->ss_session->lock);
-            /*
-             * In the generic detection event usecase, the start of the buffer
-             * sent to 2nd stage is determined by the 1st stage keyword start
-             * index. This index can have some error, so the start of the buffer
-             * is moved forward to ensure there are no resulting missed
-             * detections. Similarly, error tolerance is added to the end of the
-             * buffer for generic and non generic detection event usecases.
-             */
-            if (p_lsm_ses->common.kw_start_idx > prepend_bytes) {
-                st_sec_stage->ss_session->buf_start =
-                    p_lsm_ses->common.kw_start_idx - prepend_bytes;
-            } else {
-                st_sec_stage->ss_session->buf_start = 0;
-            }
-
-            if (st_sec_stage->ss_info->sm_detection_type ==
-                ST_SM_TYPE_KEYWORD_DETECTION) {
-                cnn_append_bytes =
-                    convert_ms_to_bytes(
-                        (p_lsm_ses->common.vendor_uuid_info->kw_end_tolerance +
-                         st_sec_stage->ss_info->data_after_kw_end),
-                        &p_lsm_ses->common.config);
-
-                if (p_lsm_ses->common.kw_end_idx < kw_duration_bytes) {
-                    st_sec_stage->ss_session->buf_end =
-                        p_lsm_ses->common.kw_end_idx + cnn_append_bytes;
-                } else {
-                    st_sec_stage->ss_session->buf_end = kw_duration_bytes +
-                        cnn_append_bytes;
-                }
-                /*
-                 * The first second-stage keyword buffer frame needs to contain
-                 * ((kwd_start_idx - kwd_start_tolerance) - kwd_end_idx) from
-                 * the first stage keyword.
-                 */
-                st_sec_stage->ss_session->buff_sz = (p_lsm_ses->common.kw_end_idx -
-                    st_sec_stage->ss_session->buf_start);
-                st_sec_stage->ss_session->lab_buf_sz = p_lsm_ses->lab_drv_buf_size;
-                st_sec_stage->ss_session->det_status = KEYWORD_DETECTION_PENDING;
-            } else if (st_sec_stage->ss_info->sm_detection_type ==
-                ST_SM_TYPE_USER_VERIFICATION) {
-                vop_append_bytes =
-                    convert_ms_to_bytes(
-                        p_lsm_ses->common.vendor_uuid_info->kw_end_tolerance,
-                        &p_lsm_ses->common.config);
-
-                if ((p_lsm_ses->common.kw_end_idx + vop_append_bytes) <
-                    kw_duration_bytes) {
-                    st_sec_stage->ss_session->buf_end =
-                        p_lsm_ses->common.kw_end_idx + vop_append_bytes;
-                } else {
-                    st_sec_stage->ss_session->buf_end = kw_duration_bytes;
-                }
-
-                st_sec_stage->ss_session->buff_sz = (st_sec_stage->ss_session->buf_end -
-                    st_sec_stage->ss_session->buf_start);
-                st_sec_stage->ss_session->det_status = USER_VERIFICATION_PENDING;
-            }
-            st_sec_stage->ss_session->unread_bytes = 0;
-            st_sec_stage->ss_session->exit_buffering = false;
-            st_sec_stage->ss_session->bytes_processed = 0;
-            st_sec_stage->ss_session->start_processing = false;
-            pthread_mutex_unlock(&st_sec_stage->ss_session->lock);
-        }
-
-        if (p_lsm_ses->common.enable_second_stage &&
-            !p_lsm_ses->common.sthw_cfg.client_req_hist_buf)
-            p_lsm_ses->move_client_ptr = true;
-        else
-            p_lsm_ses->move_client_ptr = false;
-
-        if (!p_lsm_ses->common.is_generic_event)
-            real_time_check = true;
-    }
-
-
-    ST_DBG_ATRACE_ASYNC_BEGIN_IF(!(dbg_trace_lab_buf_cnt = 0),"sthal:lsm:cpe: lsm_buffer_read",
-                                    p_lsm_ses->common.sm_handle);
-    while (!p_lsm_ses->exit_lab_processing) {
-        ALOGVV("%s: pcm_read reading bytes=%d", __func__, p_lsm_ses->lab_drv_buf_size);
-        frame_send_time = get_current_time_ns();
-        status = pcm_read(p_lsm_ses->pcm, p_lsm_ses->lab_drv_buf, p_lsm_ses->lab_drv_buf_size);
-        ST_DBG_ATRACE_ASYNC_END_IF((++dbg_trace_lab_buf_cnt == dbg_trace_max_lab_reads),
-                                    "sthal:lsm:cpe: lsm_buffer_read", p_lsm_ses->common.sm_handle);
-        frame_receive_time = get_current_time_ns();
-
-        ALOGVV("%s: pcm_read done", __func__);
-
-        if (p_lsm_ses->common.stdev->enable_debug_dumps) {
-            ST_DBG_FILE_WRITE(fptr_drv, p_lsm_ses->lab_drv_buf,
-                p_lsm_ses->lab_drv_buf_size);
-        }
-
-        if (status) {
-            ALOGE("%s: pcm read failed status %d - %s", __func__, status,
-                  pcm_get_error(p_lsm_ses->pcm));
-            p_lsm_ses->exit_lab_processing = true;
-            p_lsm_ses->common.fptrs->stop_buffering(&p_lsm_ses->common);
-            pcm_stop(p_lsm_ses->pcm);
-            pcm_start(p_lsm_ses->pcm);
-            break;
-        }
-
-        status = write_pcm_data_cpe(p_lsm_ses, p_lsm_ses->lab_drv_buf, p_lsm_ses->lab_drv_buf_size);
-        if (status)
-            break;
-        frame_read_time = frame_receive_time - frame_send_time;
-        if (real_time_check &&
-            (frame_read_time > CPE_MAX_LAB_FTRT_FRAME_RD_TIME_NS)) {
-            uint32_t bytes_written_ms =
-                convert_bytes_to_ms(p_lsm_ses->bytes_written,
-                    &p_lsm_ses->common.config);
-
-            ALOGD("%s: Real time frame received after %dms took %llums",
-                __func__, bytes_written_ms,
-                (frame_read_time / NSECS_PER_MSEC));
-            adjust_ss_buff_end(&p_lsm_ses->common, cnn_append_bytes,
-                vop_append_bytes);
-            real_time_check = false;
-        }
-    }
-
-    p_lsm_ses->lab_processing_active = false;
-    if (p_lsm_ses->common.stdev->enable_debug_dumps)
-        ST_DBG_FILE_CLOSE(fptr_drv);
-    ALOGVV("%s: Exit status=%d", __func__, status);
-}
-
-void process_packetized_lab_data(st_hw_session_lsm_t *p_ses)
-{
-    struct cpe_packet_hdr *prev_packet = NULL;
-    bool first_sync_word_found = false;
-    int sync_max_retry_cnt = SOUND_TRIGGER_SYNC_WORD_MAX_RETRY_CNT;
-    int status = 0, dec_status = 0, out_samples = 0;
-    unsigned int copy_bytes, dec_bytes, tmp_size;
-    unsigned char *driver_rd_buf;
-    unsigned int driver_rd_bytes, dr_buf_idx = 0;
-    unsigned char *ftrt_buf_ptr;
-    unsigned int ftrt_buf_size, ftrt_rem_bytes, ftrt_buf_idx = 0;
-    unsigned char *frame_buf_ptr;
-    unsigned int frame_buf_idx = 0;
-    unsigned char *dec_out_buf;
-    unsigned char packet_hdr[sizeof(struct cpe_packet_hdr)];
-    unsigned int hdr_size = sizeof(struct cpe_packet_hdr);
-    unsigned int hdr_buf_idx = 0;
-
-    ST_DBG_DECLARE(FILE *fptr_drv = NULL, *fptr_pcm = NULL,
-        *fptr_dec = NULL; static int fcnt = 0, dec_fcnt = 0;);
-    if (p_ses->common.stdev->enable_debug_dumps) {
-        ST_DBG_FILE_OPEN_WR(fptr_drv, ST_DEBUG_DUMP_LOCATION,
-            "st_lab_drv_data_cpe", "bin", fcnt);
-        ST_DBG_FILE_OPEN_WR(fptr_pcm, ST_DEBUG_DUMP_LOCATION,
-            "st_lab_output", "pcm", fcnt++);
-    }
-
-    p_ses->lab_processing_active = true;
-    p_ses->unread_bytes = 0;
-    p_ses->bytes_written = 0;
-
-    st_buffer_reset(p_ses->common.buffer);
-
-    driver_rd_buf = p_ses->lab_drv_buf;
-    driver_rd_bytes = p_ses->lab_drv_buf_size;
-
-    /*
-    1. Read from driver
-    2. Find first sync word
-    3. Skip MSB
-    4. Skip Null packets
-    5. Store in buffer
-    */
-    ST_DBG_ATRACE_ASYNC_BEGIN_IF(!(dbg_trace_lab_buf_cnt = 0),"sthal:lsm:cpe: lsm_buffer_read",
-                                p_ses->common.sm_handle);
-    while (!p_ses->exit_lab_processing) {
-
-        ALOGVV("%s: pcm_read reading bytes=%d", __func__, driver_rd_bytes);
-        status = pcm_read(p_ses->pcm, driver_rd_buf, driver_rd_bytes);
-        ST_DBG_ATRACE_ASYNC_END_IF(++dbg_trace_lab_buf_cnt == dbg_trace_max_lab_reads,
-                                    "sthal:lsm:cpe: lsm_buffer_read", p_ses->common.sm_handle);
-        ALOGVV("%s: pcm_read done", __func__);
-
-        if (p_ses->common.stdev->enable_debug_dumps)
-            ST_DBG_FILE_WRITE(fptr_drv, driver_rd_buf, driver_rd_bytes);
-
-        if (status) {
-            ALOGE("%s: pcm read failed status %d - %s", __func__, status,
-                  pcm_get_error(p_ses->pcm));
-            pcm_stop(p_ses->pcm);
-            pcm_start(p_ses->pcm);
-            break;
-        }
-
-        if (!first_sync_word_found) {
-            first_sync_word_found = search_for_syncword(p_ses, driver_rd_buf,
-               driver_rd_bytes, &dr_buf_idx);
-            if (!first_sync_word_found) {
-                if (--sync_max_retry_cnt <= 0) {
-                    ALOGE("%s: max tries for finding sync word reached", __func__);
-                    goto exit;
-                } else {
-                    /* Read next buffer from driver */
-                    dr_buf_idx = 0;
-                    continue;
-                }
-            } else {
-                /* adpcm decoder needs to be initialized upon every utterance.
-                   TODO: format check if compressed/uncompressed switch */
-                if (CHECK_BIT(p_ses->common.vendor_uuid_info->kw_capture_format,
-                              ADPCM)) {
-                    ATRACE_BEGIN("sthal:lsm: adpcm_dec_init");
-                    dec_status = p_ses->common.stdev->adpcm_dec_init(p_ses->adpcm_dec_state);
-                    ATRACE_END();
-                    if (dec_status) {
-                        ALOGE("%s: ERROR. ADPCM decoder init failed status %d",
-                               __func__, dec_status);
-                        goto exit;
-                    }
-                    if (p_ses->common.stdev->enable_debug_dumps) {
-                        ST_DBG_FILE_OPEN_WR(fptr_dec, ST_DEBUG_DUMP_LOCATION,
-                                            "st_lab_adpcm_input", "bin", dec_fcnt++);
-                    }
-                }
-            }
-        }
-        get_ftrt_processing_data(p_ses, &driver_rd_buf[dr_buf_idx],
-                                 driver_rd_bytes - dr_buf_idx,
-                                 &ftrt_buf_ptr, &ftrt_buf_size);
-
-        while (!p_ses->exit_lab_processing) {
-
-            if (!prev_packet) {
-                /* construct new packet */
-                tmp_size = MIN((hdr_size - hdr_buf_idx), (ftrt_buf_size - ftrt_buf_idx));
-                memcpy(&packet_hdr[hdr_buf_idx], &ftrt_buf_ptr[ftrt_buf_idx], tmp_size);
-                hdr_buf_idx += tmp_size;
-                ftrt_buf_idx += tmp_size;
-                if (hdr_buf_idx == hdr_size) {
-                    /* We have a new packet now, parse it */
-                    prev_packet = (struct cpe_packet_hdr *)packet_hdr;
-                    hdr_buf_idx = 0;
-                    /* sync word must be present at packet boundary */
-                    if (prev_packet->sync_word != CPE_PACKET_SYNC_WORD) {
-                        ALOGE("%s: ERROR. sync word not present", __func__);
-                        goto exit;
-                    }
-                    if (prev_packet->format == CPE_PACKET_FORMAT_EOS) {
-                        ALOGVV("%s: EOS ??", __func__);
-                        goto exit; /* TODO-V: Not expected now. FTRT to RT switch */
-                    }
-                }
-            }
-
-            if (prev_packet) {
-                if (prev_packet->format == CPE_PACKET_FORMAT_NULL) {
-                    /* Skip the NULL packets */
-                    tmp_size = MIN(prev_packet->size, (ftrt_buf_size - ftrt_buf_idx));
-                    ALOGVV("%s: null packet skip: size=%d ftrt_buf_idx=%d ftrt_buf_size=%d prev_packet->size=%d",
-                          __func__, tmp_size, ftrt_buf_idx, ftrt_buf_size, prev_packet->size);
-                    prev_packet->size -= tmp_size;
-                    ftrt_buf_idx += tmp_size;
-                } else if (prev_packet->format == CPE_PACKET_FORMAT_PCM) {
-                    copy_bytes = MIN(prev_packet->size, (ftrt_buf_size - ftrt_buf_idx));
-                    status = write_pcm_data_cpe(p_ses, &ftrt_buf_ptr[ftrt_buf_idx], copy_bytes);
-                    if (status)
-                        goto exit;
-                    if (p_ses->common.stdev->enable_debug_dumps)
-                        ST_DBG_FILE_WRITE(fptr_pcm, &ftrt_buf_ptr[ftrt_buf_idx], copy_bytes);
-                    ftrt_buf_idx += copy_bytes;
-                    prev_packet->size -= copy_bytes;
-                } else if (prev_packet->format == CPE_PACKET_FORMAT_ADPCM) {
-                    dec_out_buf = p_ses->dec_buf + ADPCM_MAX_IN_FRAME_SIZE;
-
-                    while (!p_ses->exit_lab_processing &&
-                           (ftrt_buf_idx < ftrt_buf_size) &&
-                           (prev_packet->size > 0)) {
-
-                        dec_bytes = MIN(prev_packet->size, ADPCM_MAX_IN_FRAME_SIZE);
-                        ftrt_rem_bytes = ftrt_buf_size - ftrt_buf_idx;
-
-                        if (!frame_buf_idx && (ftrt_rem_bytes >= dec_bytes)) {
-                            /* There are no cached partial frame samples in frame buf.
-                               We have full frame in ftrt buf for decoding. Use ftrt
-                               buf directly as decoder input */
-                            frame_buf_ptr = &ftrt_buf_ptr[ftrt_buf_idx];
-                        } else {
-                            /* Compute least of all buffer sizes to not to overflow */
-                            dec_bytes = MIN(MIN(dec_bytes, ftrt_rem_bytes),
-                                (ADPCM_MAX_IN_FRAME_SIZE - frame_buf_idx));
-                            memcpy(&p_ses->dec_buf[frame_buf_idx], &ftrt_buf_ptr[ftrt_buf_idx], dec_bytes);
-                            frame_buf_ptr = p_ses->dec_buf;
-                        }
-                        frame_buf_idx += dec_bytes;
-                        ftrt_buf_idx += dec_bytes;
-                        prev_packet->size -= dec_bytes;
-
-                        if (p_ses->common.stdev->enable_debug_dumps)
-                            ST_DBG_FILE_WRITE(fptr_dec, frame_buf_ptr, frame_buf_idx);
-                        if (!prev_packet->size || (frame_buf_idx == ADPCM_MAX_IN_FRAME_SIZE)) {
-                            /* if packet size is zero, we may have partial frame to be decoded */
-                            ALOGVV("%s: enter for decode- frame_buf_idx=%d ftrt_buf_idx=%d prev_packet->size=%d",
-                                   __func__, frame_buf_idx, ftrt_buf_idx, prev_packet->size);
-
-                            /* Decode ADPCM frame and copy the data to pcm out buffer */
-                            ATRACE_BEGIN("sthal:lsm: adpcm_dec_process");
-                            dec_status = p_ses->common.stdev->adpcm_dec_process((short *)frame_buf_ptr,
-                                                                  (short *)dec_out_buf,
-                                                                  frame_buf_idx,
-                                                                  &out_samples,
-                                                                  p_ses->adpcm_dec_state);
-                            ATRACE_END();
-                            if (dec_status) {
-                                ALOGE("%s: ERROR. adpcm dec failed status %d", __func__, dec_status);
-                                goto exit;
-                            }
-                            ALOGVV("%s: adpcm_dec_process done. frame_buf_idx=%d out_samples=%d",
-                                   __func__, frame_buf_idx, out_samples);
-                            if (out_samples) {
-                                if (p_ses->common.stdev->enable_debug_dumps)
-                                    ST_DBG_FILE_WRITE(fptr_pcm, dec_out_buf, out_samples << 1);
-                                status = write_pcm_data_cpe(p_ses, dec_out_buf, out_samples << 1);
-                                if (status)
-                                    goto exit;
-                            }
-                            frame_buf_idx = 0;
-                        }
-                    }
-                } else {
-                    ALOGE("%s: Uknown packet format %d ", __func__, prev_packet->format);
-                    goto exit;
-                }
-
-                if (!prev_packet->size) {
-                    /* packet is processed, remove its reference */
-                    prev_packet = NULL;
-                }
-            }
-
-            if (ftrt_buf_idx == ftrt_buf_size) {
-                ALOGVV("%s: ftrt buffer exhausted, read next buffer ftrt_buf_idx=%d",
-                       __func__, ftrt_buf_idx);
-                ftrt_buf_idx = dr_buf_idx = 0;
-                break;
-            }
-        }
-    }
-
-exit:
-    if (!p_ses->exit_lab_processing) {
-        p_ses->exit_lab_processing = true;
-        p_ses->common.fptrs->stop_buffering(&p_ses->common);
-    }
-
-    if (p_ses->common.stdev->enable_debug_dumps) {
-        ST_DBG_FILE_CLOSE(fptr_drv);
-        ST_DBG_FILE_CLOSE(fptr_dec);
-        ST_DBG_FILE_CLOSE(fptr_pcm);
-    }
-
-    ALOGVV("%s: Exit status=%d", __func__, status);
-}
-
-void process_raw_lab_data_ape(st_hw_session_lsm_t *p_lsm_ses)
-{
+    st_hw_session_lsm_t *p_lsm_ses =
+                                 (st_hw_session_lsm_t *)context;
     int status = 0;
     struct listnode *node = NULL, *tmp_node = NULL;
     st_arm_second_stage_t *st_sec_stage = NULL;
@@ -1401,190 +784,237 @@
     bool real_time_check = true;
     uint64_t frame_receive_time = 0, frame_send_time = 0;
     uint64_t frame_read_time = 0, buffering_start_time = 0;
+    st_hw_sess_event_t hw_sess_event = {0};
 
-    ST_DBG_DECLARE(FILE *fptr_drv = NULL; static int file_cnt = 0);
-    if (p_lsm_ses->common.stdev->enable_debug_dumps) {
-        ST_DBG_FILE_OPEN_WR(fptr_drv, ST_DEBUG_DUMP_LOCATION,
-                            "st_lab_drv_data_ape", "pcm", file_cnt++);
+    if (p_lsm_ses == NULL) {
+        ALOGE("%s: input is NULL, exiting", __func__);
+        return NULL;
     }
 
     pthread_mutex_lock(&p_lsm_ses->lock);
-    p_lsm_ses->lab_processing_active = true;
-    p_lsm_ses->unread_bytes = 0;
-    p_lsm_ses->bytes_written = 0;
-
-    st_buffer_reset(p_lsm_ses->common.buffer);
-
-    if (p_lsm_ses->common.enable_second_stage) {
-        if (p_lsm_ses->common.sthw_cfg.client_req_hist_buf) {
-            kw_duration_bytes =
-                convert_ms_to_bytes(
-                    p_lsm_ses->common.sthw_cfg.client_req_hist_buf,
-                    &p_lsm_ses->common.config);
-        } else {
-            kw_duration_bytes =
-                convert_ms_to_bytes(
-                    p_lsm_ses->common.vendor_uuid_info->kw_duration,
-                    &p_lsm_ses->common.config);
+    while (!p_lsm_ses->exit_buffer_thread) {
+        ALOGV("%s: waiting to start buffering", __func__);
+        pthread_cond_wait(&p_lsm_ses->cond, &p_lsm_ses->lock);
+        ALOGV("%s: done waiting to start buffering, exit = %d", __func__,
+            p_lsm_ses->exit_buffer_thread);
+        if (p_lsm_ses->exit_buffer_thread) {
+            pthread_mutex_unlock(&p_lsm_ses->lock);
+            return NULL;
         }
 
-        list_for_each_safe(node, tmp_node, p_lsm_ses->common.second_stage_list) {
-            st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
-            /*
-             * At the start of buffering, initialize the variables needed by the
-             * second stage sessions.
-             */
-            pthread_mutex_lock(&st_sec_stage->ss_session->lock);
-            /*
-             * In the generic detection event usecase, the start of the buffer
-             * sent to 2nd stage is determined by the 1st stage keyword start
-             * index. This index can have some error, so the start of the buffer
-             * is moved forward to ensure there are no resulting missed
-             * detections. Similarly, error tolerance is added to the end of the
-             * buffer for generic and non generic detection event usecases.
-             */
-            if (st_sec_stage->ss_info->sm_detection_type ==
-                ST_SM_TYPE_KEYWORD_DETECTION) {
-                cnn_prepend_bytes =
-                    convert_ms_to_bytes(
-                        p_lsm_ses->common.vendor_uuid_info->kw_start_tolerance,
-                        &p_lsm_ses->common.config);
-
-                if (p_lsm_ses->common.kw_start_idx > cnn_prepend_bytes) {
-                    st_sec_stage->ss_session->buf_start =
-                        p_lsm_ses->common.kw_start_idx - cnn_prepend_bytes;
-                } else {
-                    st_sec_stage->ss_session->buf_start = 0;
-                }
-
-                cnn_append_bytes =
-                    convert_ms_to_bytes(
-                        (p_lsm_ses->common.vendor_uuid_info->kw_end_tolerance +
-                         st_sec_stage->ss_info->data_after_kw_end),
-                        &p_lsm_ses->common.config);
-
-                if (p_lsm_ses->common.kw_end_idx < kw_duration_bytes) {
-                    st_sec_stage->ss_session->buf_end =
-                        p_lsm_ses->common.kw_end_idx + cnn_append_bytes;
-                } else {
-                    st_sec_stage->ss_session->buf_end = kw_duration_bytes +
-                        cnn_append_bytes;
-                }
-                /*
-                 * The first second-stage keyword buffer frame needs to contain
-                 * ((kwd_start_idx - kwd_start_tolerance) - kwd_end_idx) from
-                 * the first stage keyword.
-                 */
-                st_sec_stage->ss_session->buff_sz = (p_lsm_ses->common.kw_end_idx -
-                    st_sec_stage->ss_session->buf_start);
-                st_sec_stage->ss_session->lab_buf_sz = p_lsm_ses->lab_drv_buf_size;
-                st_sec_stage->ss_session->det_status = KEYWORD_DETECTION_PENDING;
-            } else if (st_sec_stage->ss_info->sm_detection_type ==
-                ST_SM_TYPE_USER_VERIFICATION) {
-                vop_prepend_bytes =
-                    convert_ms_to_bytes(
-                        st_sec_stage->ss_info->data_before_kw_start,
-                        &p_lsm_ses->common.config);
-
-                if (p_lsm_ses->common.kw_start_idx > vop_prepend_bytes) {
-                    st_sec_stage->ss_session->buf_start =
-                        p_lsm_ses->common.kw_start_idx - vop_prepend_bytes;
-                } else {
-                    st_sec_stage->ss_session->buf_start = 0;
-                }
-
-                vop_append_bytes =
-                    convert_ms_to_bytes(
-                        p_lsm_ses->common.vendor_uuid_info->kw_end_tolerance,
-                        &p_lsm_ses->common.config);
-
-                if ((p_lsm_ses->common.kw_end_idx + vop_append_bytes) <
-                    kw_duration_bytes) {
-                    st_sec_stage->ss_session->buf_end =
-                        p_lsm_ses->common.kw_end_idx + vop_append_bytes;
-                } else {
-                    st_sec_stage->ss_session->buf_end = kw_duration_bytes;
-                }
-
-                st_sec_stage->ss_session->buff_sz = (st_sec_stage->ss_session->buf_end -
-                    st_sec_stage->ss_session->buf_start);
-                st_sec_stage->ss_session->det_status = USER_VERIFICATION_PENDING;
-            }
-            st_sec_stage->ss_session->unread_bytes = 0;
-            st_sec_stage->ss_session->exit_buffering = false;
-            st_sec_stage->ss_session->bytes_processed = 0;
-            st_sec_stage->ss_session->start_processing = false;
-            st_sec_stage->ss_session->confidence_score = 0;
-            pthread_mutex_unlock(&st_sec_stage->ss_session->lock);
-        }
-
-        if (p_lsm_ses->common.enable_second_stage &&
-            !p_lsm_ses->common.sthw_cfg.client_req_hist_buf)
-            p_lsm_ses->move_client_ptr = true;
-        else
-            p_lsm_ses->move_client_ptr = false;
-    }
-
-    buffering_start_time = get_current_time_ns();
-
-    while (!p_lsm_ses->exit_lab_processing) {
-        ALOGVV("%s: pcm_read reading bytes=%d", __func__, p_lsm_ses->lab_drv_buf_size);
-        pthread_mutex_unlock(&p_lsm_ses->lock);
-        frame_send_time = get_current_time_ns();
-        ATRACE_ASYNC_BEGIN("sthal:lsm:ape: pcm_read",
-            p_lsm_ses->common.sm_handle);
-        status = pcm_read(p_lsm_ses->pcm, p_lsm_ses->lab_drv_buf, p_lsm_ses->lab_drv_buf_size);
-        ATRACE_ASYNC_END("sthal:lsm:ape: pcm_read",
-            p_lsm_ses->common.sm_handle);
-        pthread_mutex_lock(&p_lsm_ses->lock);
-        frame_receive_time = get_current_time_ns();
-
-        ALOGVV("%s: pcm_read done", __func__);
+        ST_DBG_DECLARE(FILE *fptr_drv = NULL; static int file_cnt = 0);
         if (p_lsm_ses->common.stdev->enable_debug_dumps) {
-            ST_DBG_FILE_WRITE(fptr_drv, p_lsm_ses->lab_drv_buf,
-                p_lsm_ses->lab_drv_buf_size);
+            ST_DBG_FILE_OPEN_WR(fptr_drv, ST_DEBUG_DUMP_LOCATION,
+                                "st_lab_drv_data_ape", "pcm", file_cnt++);
         }
 
+        ATRACE_BEGIN("sthal:lsm: buffer_thread_loop");
+
+        status = 0;
+        real_time_check = true;
+        p_lsm_ses->unread_bytes = 0;
+        p_lsm_ses->bytes_written = 0;
+
+        st_buffer_reset(p_lsm_ses->common.buffer);
+
+        if (p_lsm_ses->common.enable_second_stage) {
+            if (p_lsm_ses->common.sthw_cfg.client_req_hist_buf) {
+                kw_duration_bytes =
+                    convert_ms_to_bytes(
+                        p_lsm_ses->common.sthw_cfg.client_req_hist_buf,
+                        &p_lsm_ses->common.config);
+            } else {
+                kw_duration_bytes =
+                    convert_ms_to_bytes(
+                        p_lsm_ses->common.vendor_uuid_info->kw_duration,
+                        &p_lsm_ses->common.config);
+            }
+
+            list_for_each_safe(node, tmp_node,
+                p_lsm_ses->common.second_stage_list) {
+                st_sec_stage = node_to_item(node, st_arm_second_stage_t,
+                    list_node);
+                /*
+                 * At the start of buffering, initialize the variables needed
+                 * by the second stage sessions.
+                 */
+                pthread_mutex_lock(&st_sec_stage->ss_session->lock);
+                /*
+                 * In the generic detection event usecase, the start of the
+                 * buffer sent to 2nd stage is determined by the 1st stage
+                 * keyword start index. This index can have some error, so the
+                 * start of the buffer is moved forward to ensure there are no
+                 * resulting missed detections. Similarly, error tolerance is
+                 * added to the end of the buffer for generic and non generic
+                 * detection event usecases.
+                 */
+                if (st_sec_stage->ss_info->sm_detection_type ==
+                    ST_SM_TYPE_KEYWORD_DETECTION) {
+                    cnn_prepend_bytes =
+                        convert_ms_to_bytes(
+                            p_lsm_ses->common.vendor_uuid_info->kw_start_tolerance,
+                            &p_lsm_ses->common.config);
+
+                    if (p_lsm_ses->common.kw_start_idx > cnn_prepend_bytes) {
+                        st_sec_stage->ss_session->buf_start =
+                            p_lsm_ses->common.kw_start_idx - cnn_prepend_bytes;
+                    } else {
+                        st_sec_stage->ss_session->buf_start = 0;
+                    }
+
+                    cnn_append_bytes =
+                        convert_ms_to_bytes(
+                            (p_lsm_ses->common.vendor_uuid_info->kw_end_tolerance +
+                             st_sec_stage->ss_info->data_after_kw_end),
+                            &p_lsm_ses->common.config);
+
+                    if (p_lsm_ses->common.kw_end_idx < kw_duration_bytes) {
+                        st_sec_stage->ss_session->buf_end =
+                            p_lsm_ses->common.kw_end_idx + cnn_append_bytes;
+                    } else {
+                        st_sec_stage->ss_session->buf_end = kw_duration_bytes +
+                            cnn_append_bytes;
+                    }
+                    /*
+                     * The first second-stage keyword buffer frame needs to
+                     * contain ((kwd_start_idx - kwd_start_tolerance) -
+                     * kwd_end_idx) from the first stage keyword.
+                     */
+                    st_sec_stage->ss_session->buff_sz =
+                        (p_lsm_ses->common.kw_end_idx -
+                        st_sec_stage->ss_session->buf_start);
+                    st_sec_stage->ss_session->lab_buf_sz =
+                        p_lsm_ses->lab_drv_buf_size;
+                    st_sec_stage->ss_session->det_status =
+                        KEYWORD_DETECTION_PENDING;
+                } else if (st_sec_stage->ss_info->sm_detection_type ==
+                    ST_SM_TYPE_USER_VERIFICATION) {
+                    vop_prepend_bytes =
+                        convert_ms_to_bytes(
+                            st_sec_stage->ss_info->data_before_kw_start,
+                            &p_lsm_ses->common.config);
+
+                    if (p_lsm_ses->common.kw_start_idx > vop_prepend_bytes) {
+                        st_sec_stage->ss_session->buf_start =
+                            p_lsm_ses->common.kw_start_idx - vop_prepend_bytes;
+                    } else {
+                        st_sec_stage->ss_session->buf_start = 0;
+                    }
+
+                    vop_append_bytes =
+                        convert_ms_to_bytes(
+                            p_lsm_ses->common.vendor_uuid_info->kw_end_tolerance,
+                            &p_lsm_ses->common.config);
+
+                    if ((p_lsm_ses->common.kw_end_idx + vop_append_bytes) <
+                        kw_duration_bytes) {
+                        st_sec_stage->ss_session->buf_end =
+                            p_lsm_ses->common.kw_end_idx + vop_append_bytes;
+                    } else {
+                        st_sec_stage->ss_session->buf_end = kw_duration_bytes;
+                    }
+
+                    st_sec_stage->ss_session->buff_sz =
+                        (st_sec_stage->ss_session->buf_end -
+                        st_sec_stage->ss_session->buf_start);
+                    st_sec_stage->ss_session->det_status =
+                        USER_VERIFICATION_PENDING;
+                }
+                st_sec_stage->ss_session->unread_bytes = 0;
+                st_sec_stage->ss_session->exit_buffering = false;
+                st_sec_stage->ss_session->bytes_processed = 0;
+                st_sec_stage->ss_session->start_processing = false;
+                st_sec_stage->ss_session->confidence_score = 0;
+                pthread_mutex_unlock(&st_sec_stage->ss_session->lock);
+            }
+
+            if (p_lsm_ses->common.enable_second_stage &&
+                !p_lsm_ses->common.sthw_cfg.client_req_hist_buf)
+                p_lsm_ses->move_client_ptr = true;
+            else
+                p_lsm_ses->move_client_ptr = false;
+        }
+
+        buffering_start_time = get_current_time_ns();
+
+        while (!p_lsm_ses->exit_lab_processing) {
+            ALOGVV("%s: pcm_read reading bytes=%d", __func__,
+                p_lsm_ses->lab_drv_buf_size);
+            pthread_mutex_unlock(&p_lsm_ses->lock);
+            frame_send_time = get_current_time_ns();
+            ATRACE_ASYNC_BEGIN("sthal:lsm:ape: pcm_read",
+                p_lsm_ses->common.sm_handle);
+            status = pcm_read(p_lsm_ses->pcm, p_lsm_ses->lab_drv_buf,
+                p_lsm_ses->lab_drv_buf_size);
+            ATRACE_ASYNC_END("sthal:lsm:ape: pcm_read",
+                p_lsm_ses->common.sm_handle);
+            pthread_mutex_lock(&p_lsm_ses->lock);
+            frame_receive_time = get_current_time_ns();
+
+            ALOGVV("%s: pcm_read done", __func__);
+            if (p_lsm_ses->common.stdev->enable_debug_dumps) {
+                ST_DBG_FILE_WRITE(fptr_drv, p_lsm_ses->lab_drv_buf,
+                    p_lsm_ses->lab_drv_buf_size);
+            }
+
+            if (status) {
+                ALOGE("%s: pcm read failed status %d - %s", __func__, status,
+                      pcm_get_error(p_lsm_ses->pcm));
+                pcm_stop(p_lsm_ses->pcm);
+                pcm_start(p_lsm_ses->pcm);
+                break;
+            }
+
+            status = write_pcm_data_ape(p_lsm_ses, p_lsm_ses->lab_drv_buf,
+                p_lsm_ses->lab_drv_buf_size);
+            if (status) {
+                ALOGE("%s: Failed to write to circ buff, status %d", __func__,
+                    status);
+                break;
+            }
+            frame_read_time = frame_receive_time - frame_send_time;
+            if (real_time_check &&
+                (frame_read_time > APE_MAX_LAB_FTRT_FRAME_RD_TIME_NS)) {
+                uint32_t ftrt_bytes_written_ms =
+                    convert_bytes_to_ms(p_lsm_ses->bytes_written -
+                        p_lsm_ses->lab_drv_buf_size, &p_lsm_ses->common.config);
+
+                ALOGD("%s: FTRT data transfer: %dms of data received in %llums",
+                    __func__, ftrt_bytes_written_ms, ((frame_send_time -
+                        buffering_start_time) / NSECS_PER_MSEC));
+
+                if (p_lsm_ses->common.enable_second_stage &&
+                    !p_lsm_ses->common.is_generic_event) {
+                    ALOGD("%s: First real time frame took %llums", __func__,
+                        (frame_read_time / NSECS_PER_MSEC));
+                    adjust_ss_buff_end(&p_lsm_ses->common, cnn_append_bytes,
+                        vop_append_bytes);
+                }
+                real_time_check = false;
+            }
+        }
+        ALOGV("%s: Exited buffering, status=%d", __func__, status);
+        ape_stop_buffering(&p_lsm_ses->common);
+        p_lsm_ses->lab_on_detection = false;
+        p_lsm_ses->lab_processing_active = false;
+        pthread_cond_broadcast(&p_lsm_ses->cond);
+        if (p_lsm_ses->common.stdev->enable_debug_dumps)
+            ST_DBG_FILE_CLOSE(fptr_drv);
+        ATRACE_END();
+
         if (status) {
-            ALOGE("%s: pcm read failed status %d - %s", __func__, status,
-                  pcm_get_error(p_lsm_ses->pcm));
-            pcm_stop(p_lsm_ses->pcm);
-            pcm_start(p_lsm_ses->pcm);
-            break;
-        }
-
-        write_pcm_data_ape(p_lsm_ses, p_lsm_ses->lab_drv_buf, p_lsm_ses->lab_drv_buf_size);
-        frame_read_time = frame_receive_time - frame_send_time;
-        if (real_time_check &&
-            (frame_read_time > APE_MAX_LAB_FTRT_FRAME_RD_TIME_NS)) {
-            uint32_t ftrt_bytes_written_ms =
-                convert_bytes_to_ms(p_lsm_ses->bytes_written -
-                    p_lsm_ses->lab_drv_buf_size, &p_lsm_ses->common.config);
-
-            ALOGD("%s: FTRT data transfer: %dms of data received in %llums",
-                __func__, ftrt_bytes_written_ms, ((frame_send_time -
-                    buffering_start_time) / NSECS_PER_MSEC));
-
-            if (p_lsm_ses->common.enable_second_stage && !p_lsm_ses->common.is_generic_event) {
-                ALOGD("%s: First real time frame took %llums", __func__,
-                    (frame_read_time / NSECS_PER_MSEC));
-                adjust_ss_buff_end(&p_lsm_ses->common, cnn_append_bytes,
-                    vop_append_bytes);
-            }
-            real_time_check = false;
+            hw_sess_event.event_id = ST_HW_SESS_EVENT_BUFFERING_STOPPED;
+            pthread_mutex_unlock(&p_lsm_ses->lock);
+            p_lsm_ses->common.callback_to_st_session(&hw_sess_event,
+                p_lsm_ses->common.cookie);
+            pthread_mutex_lock(&p_lsm_ses->lock);
         }
     }
-
-    ape_stop_buffering(&p_lsm_ses->common);
-    p_lsm_ses->lab_on_detection = false;
-    p_lsm_ses->lab_processing_active = false;
-    pthread_cond_broadcast(&p_lsm_ses->cond);
     pthread_mutex_unlock(&p_lsm_ses->lock);
-    if (p_lsm_ses->common.stdev->enable_debug_dumps)
-        ST_DBG_FILE_CLOSE(fptr_drv);
-    ALOGVV("%s: Exit status=%d", __func__, status);
+    return NULL;
 }
 
+
 static void *callback_thread_loop(void *context)
 {
     st_hw_session_lsm_t *p_lsm_ses =
@@ -1746,173 +1176,21 @@
     }
     p_ses->lab_buffers_allocated = false;
 
-    return 0;
-}
-
-static int deallocate_lab_buffers_cpe(st_hw_session_lsm_t* p_ses)
-{
-    ALOGVV("%s:[%d] Enter", __func__, p_ses->common.sm_handle);
-    if (p_ses->adpcm_dec_state) {
-        free(p_ses->adpcm_dec_state);
-        p_ses->adpcm_dec_state = NULL;
-    }
-    if (p_ses->dec_buf) {
-        free(p_ses->dec_buf);
-        p_ses->dec_buf = NULL;
-    }
-    st_buffer_deinit(p_ses->common.buffer);
-    p_ses->common.buffer = NULL;
-    if (p_ses->lab_drv_buf) {
-        free(p_ses->lab_drv_buf);
-        p_ses->lab_drv_buf = NULL;
-    }
-    p_ses->lab_buffers_allocated = false;
+    p_ses->exit_buffer_thread = true;
+    pthread_mutex_lock(&p_ses->lock);
+    pthread_cond_signal(&p_ses->cond);
+    pthread_mutex_unlock(&p_ses->lock);
+    pthread_join(p_ses->buffer_thread, NULL);
 
     return 0;
 }
 
-static int configure_lab(st_hw_session_lsm_t* p_ses, bool capture_requested)
-{
-    int status = 0, buf_en = 0;
-    struct snd_lsm_output_format_cfg media_cfg;
-    struct st_vendor_info *v_info = p_ses->common.vendor_uuid_info;
-
-    media_cfg.format = LSM_OUT_FORMAT_PCM;
-    media_cfg.packing = LSM_OUT_DATA_RAW;
-    media_cfg.mode = LSM_OUT_TRANSFER_MODE_RT;
-    media_cfg.events = LSM_OUT_DATA_EVENTS_DISABLED;
-
-    if (v_info && (v_info->kw_transfer_mode == FTRT_TRANSFER_MODE)) {
-        media_cfg.packing = LSM_OUT_DATA_PACKED;
-        media_cfg.mode = LSM_OUT_TRANSFER_MODE_FTRT;
-
-        if (CHECK_BIT(v_info->kw_capture_format, ADPCM))
-            media_cfg.format = LSM_OUT_FORMAT_ADPCM;
-    }
-
-    ALOGD("%s: media_cfg format=%d, packing=%d, events=%d, mode=%d", __func__,
-       media_cfg.format, media_cfg.packing, media_cfg.events, media_cfg.mode);
-    ATRACE_BEGIN("sthal:lsm: pcm_ioctl sndrv_lsm_out_format_cfg)");
-    status = pcm_ioctl(p_ses->pcm, SNDRV_LSM_OUT_FORMAT_CFG, &media_cfg);
-    ATRACE_END();
-    if (status) {
-        ALOGE("%s: ERROR. SNDRV_LSM_OUT_FORMAT_CFG, status=%d", __func__,
-           status);
-        return status;
-    }
-
-    buf_en = capture_requested ? 1 : 0;
-    ATRACE_BEGIN("sthal:lsm: pcm_ioctl sndrv_lsm_lab_control");
-    status = pcm_ioctl(p_ses->pcm, SNDRV_LSM_LAB_CONTROL, &buf_en);
-    ATRACE_END();
-    if (status) ALOGE("%s: ERROR. SNDRV_LSM_LAB_CONTROL failed, status=%d",
-        __func__, status);
-
-    return status;
-}
-
-static int allocate_lab_buffers_cpe(st_hw_session_lsm_t* p_ses)
-{
-    int status = 0, circ_buff_sz = 0;
-    int adpcm_dec_scratch_size;
-    unsigned int kw_tranfer_duration, rt_bytes_one_sec, ftrt_to_rt_factor;
-    struct st_vendor_info *v_info = p_ses->common.vendor_uuid_info;
-
-    ALOGVV("%s:[%d] Enter", __func__, p_ses->common.sm_handle);
-
-    p_ses->lab_drv_buf_size = pcm_frames_to_bytes(p_ses->pcm, p_ses->lab_config.period_size);
-    p_ses->lab_drv_buf = (unsigned char *)calloc(1, p_ses->lab_drv_buf_size);
-    if (!p_ses->lab_drv_buf) {
-        ALOGE("%s: ERROR. Can not allocate lab buffer size %d", __func__, p_ses->lab_drv_buf_size);
-        status = -ENOMEM;
-        goto error_exit;
-    }
-    ALOGV("%s: Allocated lab buffer period size bytes =%d",
-          __func__, p_ses->lab_drv_buf_size);
-
-    rt_bytes_one_sec = (p_ses->common.config.rate * p_ses->common.config.channels *
-                        (pcm_format_to_bits(p_ses->common.config.format) >> 3));
-
-    circ_buff_sz = (v_info->client_capture_read_delay * rt_bytes_one_sec) / 1000;
-    if (v_info->kw_transfer_mode == FTRT_TRANSFER_MODE) {
-        ftrt_to_rt_factor = (p_ses->lab_config.rate * pcm_format_to_bits(p_ses->lab_config.format)) /
-                            (p_ses->common.config.rate * pcm_format_to_bits(p_ses->common.config.format));
-
-        kw_tranfer_duration = v_info->kw_duration / ftrt_to_rt_factor;
-        ALOGV("%s: kw_tranfer_duration %d, kw_duration %d, ftrt_to_rt_factor %d",
-               __func__, kw_tranfer_duration, v_info->kw_duration, ftrt_to_rt_factor);
-        if (kw_tranfer_duration < v_info->client_capture_read_delay) {
-            /* Full keyword gets transmitted within App delay, accomodate full
-               keyword duration size plus the client read delay time of real time data size.
-               Ex: 2sec keyword duration at 384KHz/32bit FTRT speed gets transfered in ~40ms.
-               If configured App delay is 1sec, accomdate realtime data for 1sec delay in
-               addition to 2sec keyword data. So the buffer size becomes
-               (2000ms + 1000ms) * 32KB/1000ms = ~96KB */
-            circ_buff_sz = (v_info->kw_duration + v_info->client_capture_read_delay) *
-                                      rt_bytes_one_sec / 1000;
-        } else {
-            /* Accomdate client read delay worth of ftrt keyword data.
-               Ex: 2sec keyword duration at 16KHz/32bit FTRT speed gets transfered
-               in 1000ms. If configured App delay is 500ms, all that we need to store
-               is 500ms worth for FTRT data. So the buffer size becomes
-               (500ms * 2) * 32KB/1000ms = 32KB */
-            circ_buff_sz *= ftrt_to_rt_factor;
-        }
-    }
-
-    p_ses->common.buffer = st_buffer_init(circ_buff_sz);
-    if (!p_ses->common.buffer) {
-        ALOGE("%s: failed to allocate circ buffer", __func__);
-        status = -ENOMEM;
-        goto error_exit;
-    }
-
-    ALOGV("%s: Allocated out buffer size=%d", __func__, circ_buff_sz);
-
-    if (CHECK_BIT(v_info->kw_capture_format, ADPCM)) {
-        p_ses->dec_buf = (unsigned char *)calloc(1, ADPCM_MAX_IN_FRAME_SIZE +
-                                                  ADPCM_MAX_OUT_FRAME_SIZE);
-        if (!p_ses->dec_buf) {
-            ALOGE("%s: ERROR. Can not allocate decoder buffer size %d",
-                  __func__, ADPCM_MAX_IN_FRAME_SIZE + ADPCM_MAX_OUT_FRAME_SIZE);
-            status = -ENOMEM;
-            goto error_exit;
-        }
-        ALOGV("%s: Allocated decoder buffers size=%d", __func__,
-               ADPCM_MAX_IN_FRAME_SIZE + ADPCM_MAX_OUT_FRAME_SIZE);
-
-        /* Instantiate the decoder */
-        status = p_ses->common.stdev->adpcm_dec_get_scratch_size(&adpcm_dec_scratch_size);
-        if (status) {
-            ALOGE("%s: ERROR. Can not get adpcm dec scratch", __func__);
-            status = -EINVAL;
-            goto error_exit;
-        }
-
-        p_ses->adpcm_dec_state = (void *)calloc(1, adpcm_dec_scratch_size);
-        if (!p_ses->adpcm_dec_state)
-        {
-            ALOGE("%s: ERROR. Can not allocate decoder scratch", __func__);
-            status = -ENOMEM;
-            goto error_exit;
-        }
-        ALOGV("%s: Allocated adpcm_dec_state size=%d", __func__,
-              adpcm_dec_scratch_size);
-    }
-    p_ses->lab_buffers_allocated = true;
-
-    return 0;
-
-error_exit:
-    deallocate_lab_buffers_cpe(p_ses);
-    return status;
-}
-
 static int allocate_lab_buffers_ape(st_hw_session_lsm_t* p_lsm_ses)
 {
     int status = 0, circ_buff_sz = 0;
     struct st_vendor_info *v_info = p_lsm_ses->common.vendor_uuid_info;
     unsigned int rt_bytes_one_sec;
+    pthread_attr_t attr;
 
     p_lsm_ses->lab_drv_buf_size = pcm_frames_to_bytes(p_lsm_ses->pcm,
         p_lsm_ses->common.config.period_size);
@@ -1950,6 +1228,12 @@
     ALOGV("%s: Allocated out buffer size=%d", __func__, circ_buff_sz);
     p_lsm_ses->lab_buffers_allocated = true;
 
+    p_lsm_ses->exit_buffer_thread = false;
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+    pthread_create(&p_lsm_ses->buffer_thread, &attr,
+        buffer_thread_loop, p_lsm_ses);
+
     return status;
 
 error_exit:
@@ -1964,7 +1248,7 @@
 )
 {
     char st_device_name[DEVICE_NAME_MAX_SIZE] = { 0 };
-    int ref_cnt_idx = 0, ref_cnt = 0;
+    int ref_cnt_idx = 0, ref_cnt = 0, ref_enable_idx = 0;
     int status = 0;
     st_device_t st_device = 0;
     audio_devices_t capture_device = 0;
@@ -2007,6 +1291,8 @@
 
         pthread_mutex_lock(&p_ses->stdev->ref_cnt_lock);
         ref_cnt_idx = (p_ses->exec_mode * ST_DEVICE_MAX) + st_device;
+        ref_enable_idx = (p_ses->exec_mode * ST_DEVICE_MAX) +
+            platform_get_lpi_st_device(st_device);
         ref_cnt = ++(p_ses->stdev->dev_ref_cnt[ref_cnt_idx]);
         app_type = platform_stdev_get_device_app_type(p_ses->stdev->platform,
                                                       profile_type);
@@ -2038,15 +1324,23 @@
                            __func__, p_ses->st_device, p_ses->st_device_name);
                     audio_route_reset_and_update_path(p_ses->stdev->audio_route,
                         st_device_name);
+                    if (0 < p_ses->stdev->dev_enable_cnt[ref_enable_idx])
+                        --(p_ses->stdev->dev_enable_cnt[ref_enable_idx]);
                 }
 
-                ALOGD("%s: enable device (%x) = %s", __func__, st_device,
-                      st_device_name);
-                ATRACE_BEGIN("sthal:lsm: audio_route_apply_and_update_path");
-                audio_route_apply_and_update_path(p_ses->stdev->audio_route,
-                                                  st_device_name);
-                ATRACE_END();
-                update_hw_mad_exec_mode(p_ses->exec_mode, profile_type);
+                if (0 == p_ses->stdev->dev_enable_cnt[ref_enable_idx]) {
+                    ALOGD("%s: enable device (%x) = %s", __func__, st_device,
+                          st_device_name);
+                    ATRACE_BEGIN("sthal:lsm: audio_route_apply_and_update_path");
+                    audio_route_apply_and_update_path(p_ses->stdev->audio_route,
+                                                      st_device_name);
+                    ATRACE_END();
+                    update_hw_mad_exec_mode(p_ses->exec_mode, profile_type);
+                    ++(p_ses->stdev->dev_enable_cnt[ref_enable_idx]);
+                } else {
+                    ALOGD("%s: Device already enabled, no not re-enable",
+                        __func__);
+                }
             }
         } else {
             --(p_ses->stdev->dev_ref_cnt[ref_cnt_idx]);
@@ -2062,6 +1356,8 @@
         }
 
         ref_cnt_idx = (p_ses->exec_mode * ST_DEVICE_MAX) + p_ses->st_device;
+        ref_enable_idx = (p_ses->exec_mode * ST_DEVICE_MAX) +
+            platform_get_lpi_st_device(p_ses->st_device);
         pthread_mutex_lock(&p_ses->stdev->ref_cnt_lock);
         ref_cnt = p_ses->stdev->dev_ref_cnt[ref_cnt_idx];
         if (0 < ref_cnt) {
@@ -2081,6 +1377,8 @@
                                                   p_ses->st_device_name);
                 ATRACE_END();
                 update_hw_mad_exec_mode(ST_EXEC_MODE_NONE, profile_type);
+                if (0 < p_ses->stdev->dev_enable_cnt[ref_enable_idx])
+                    --(p_ses->stdev->dev_enable_cnt[ref_enable_idx]);
             } else {
                 ALOGD("%s: Non-hwmad device, concurrent capture on, do not disable", __func__);
             }
@@ -2175,9 +1473,8 @@
 
     p_lsm_ses->common.config = stdev_ape_pcm_config;
 
-    platform_stdev_check_and_update_pcm_config(p_ses->stdev->platform,
-                                               &p_lsm_ses->common.config,
-                                               v_info, p_ses->exec_mode);
+    platform_stdev_check_and_update_pcm_config(&p_lsm_ses->common.config,
+                                               v_info);
 
     ALOGD("%s: opening pcm device=%d", __func__, p_lsm_ses->pcm_id);
     ALOGV("%s: config: channels=%d rate=%d, period_size=%d, period_cnt=%d, format=%d",
@@ -3035,543 +2332,6 @@
     return status;
 }
 
-static int cpe_reg_sm(st_hw_session_t *p_ses,
-    void* sm_data, unsigned int sm_size,
-    sound_trigger_sound_model_type_t sm_type __unused)
-{
-    int status = 0, fd;
-    struct snd_lsm_module_params lsm_params;
-    struct lsm_params_info param_info;
-    struct st_vendor_info *v_info = p_ses->vendor_uuid_info;
-    struct pcm_config  *config;
-    pthread_attr_t attr;
-    st_hw_session_lsm_t *p_lsm_ses =  (st_hw_session_lsm_t *)p_ses;
-    struct st_module_param_info *mparams = NULL;
-
-    ALOGD("%s:[%d] Enter", __func__, p_lsm_ses->common.sm_handle);
-
-    p_lsm_ses->pcm_id = platform_cpe_get_pcm_device_id(p_ses->stdev->platform,
-        v_info->sample_rate, &p_ses->use_case_idx);
-    if (p_lsm_ses->pcm_id < 0)
-        return -ENODEV;
-
-    platform_get_lsm_usecase(p_ses->stdev->platform, v_info,
-        &p_lsm_ses->lsm_usecase, p_ses->exec_mode, p_ses->lpi_enable);
-    if (!p_lsm_ses->lsm_usecase) {
-        ALOGE("%s: couldn't get lsm usecase", __func__);
-        goto sm_error;
-    }
-    /* Backward compatibility with previous XML version <= 0x0102 */
-    int app_type = (v_info->app_type == 0) ?
-        p_lsm_ses->lsm_usecase->app_type : v_info->app_type;
-
-    status = platform_stdev_send_calibration(p_ses->stdev->platform,
-                                              AUDIO_DEVICE_NONE,
-                                              p_ses->exec_mode,
-                                              p_ses->vendor_uuid_info,
-                                              app_type, true,
-                                              ST_SESSION_CAL);
-
-    if (status) {
-        ALOGE("%s: ERROR. sending session calibration failed status %d",
-               __func__, status);
-        goto sm_error;
-    }
-
-    if (strcmp(v_info->cpe_firmware_image,"")) {
-        ALOGD("%s: cpe firmware image %s", __func__, v_info->cpe_firmware_image);
-        /* Write the vendor firmware image name in sysfs entry */
-        fd = open("/sys/kernel/wcd_cpe0/fw_name", O_WRONLY);
-        if (fd >= 0) {
-            write(fd, v_info->cpe_firmware_image,
-               strlen(v_info->cpe_firmware_image));
-            close(fd);
-        }
-        else {
-            ALOGE("%s: ERROR. sysfs open to write firmware name failed : %s",
-                  __func__, strerror(errno));
-            goto sm_error;
-        }
-    }
-    p_lsm_ses->common.config = stdev_cpe_pcm_config;
-    p_lsm_ses->lab_config = stdev_cpe_pcm_config;
-    config = &p_lsm_ses->lab_config;
-
-    p_lsm_ses->lab_config.rate = v_info->sample_rate;
-    if (v_info->kw_transfer_mode == FTRT_TRANSFER_MODE) {
-        platform_stdev_check_and_update_pcm_config(p_ses->stdev->platform,
-                                                   &p_lsm_ses->lab_config,
-                                                   v_info,
-                                                   p_ses->exec_mode);
-
-        p_lsm_ses->lab_config.period_size =
-           CALCULATE_PERIOD_SIZE(SOUND_TRIGGER_CPE_LAB_DRV_BUF_DURATION_MS,
-                                 p_lsm_ses->lab_config.rate,
-                                 SOUND_TRIGGER_CPE_PERIOD_COUNT, 32);
-
-        ALOGV("%s: ftrt rate=%d format=%d", __func__,
-            p_lsm_ses->lab_config.rate, p_lsm_ses->lab_config.format);
-
-        if (CHECK_BIT(v_info->kw_capture_format, ADPCM))
-           p_lsm_ses->common.config.period_size = ADPCM_MAX_OUT_SAMPLES_PER_FRAME;
-    }
-
-    ALOGD("%s: opening pcm device=%d", __func__, p_lsm_ses->pcm_id);
-    ALOGD("%s: config: channels=%d rate=%d, period_size=%d, "
-          "period_cnt=%d, format=%d", __func__, config->channels,
-          config->rate, config->period_size,
-          config->period_count, config->format);
-
-    ATRACE_BEGIN("sthal:lsm: pcm_open");
-    p_lsm_ses->pcm = pcm_open(p_ses->stdev->snd_card, p_lsm_ses->pcm_id,
-                          PCM_IN, config);
-    ATRACE_END();
-
-    if (!p_lsm_ses->pcm) {
-        ALOGE("%s: ERROR. pcm_open failed", __func__);
-        status = -ENODEV;
-        goto sm_error;
-    }
-    if (!pcm_is_ready(p_lsm_ses->pcm)) {
-        ALOGE("%s: ERROR. pcm_is_ready failed err=%s", __func__,
-              pcm_get_error(p_lsm_ses->pcm));
-        status = -ENODEV;
-        goto sm_error;
-    }
-
-    mparams = p_lsm_ses->lsm_usecase->params;
-    param_info.param_type = LSM_REG_SND_MODEL;
-    param_info.module_id = mparams[LOAD_SOUND_MODEL].module_id;
-    param_info.param_id = mparams[LOAD_SOUND_MODEL].param_id;
-    param_info.param_data = sm_data;
-    param_info.param_size = sm_size;
-
-    lsm_params.num_params = 1;
-    lsm_params.params = (unsigned char*)&param_info;
-    lsm_params.data_size = lsm_params.num_params * sizeof(struct lsm_params_info);
-
-    ALOGV("%s: sm data size=%d", __func__, param_info.param_size);
-
-    ATRACE_BEGIN("sthal:lsm: pcm_ioctl sndrv_lsm_set_module_params");
-    status = pcm_ioctl(p_lsm_ses->pcm, SNDRV_LSM_SET_MODULE_PARAMS,
-        &lsm_params);
-    ATRACE_END();
-
-    if (status) {
-        ALOGE("%s: ERROR. SNDRV_LSM_SET_MODULE_PARAMS->reg status=%d",
-              __func__, status);
-        goto sm_error;
-    }
-
-    /* Callback thread to wait on event detection */
-    p_lsm_ses->exit_callback_thread = false;
-    pthread_attr_init(&attr);
-    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
-    pthread_create(&p_lsm_ses->callback_thread, &attr,
-                        callback_thread_loop, p_ses);
-
-    ALOGD("%s:[%d] Exit, status=%d", __func__, p_lsm_ses->common.sm_handle,
-        status);
-    return 0;
-
-sm_error:
-    platform_cpe_free_pcm_device_id(p_ses->stdev->platform, p_lsm_ses->pcm_id);
-    if (p_lsm_ses->pcm) {
-        pcm_close(p_lsm_ses->pcm);
-        p_lsm_ses->pcm = NULL;
-    }
-
-    ALOGD("%s:[%d] Exit, status=%d", __func__, p_lsm_ses->common.sm_handle,
-        status);
-    return status;
-}
-
-static int cpe_dereg_sm(st_hw_session_t *p_ses)
-{
-    int status = 0, buf_en;
-    struct snd_lsm_module_params lsm_params;
-    struct lsm_params_info param_info;
-    st_hw_session_lsm_t *p_lsm_ses = (st_hw_session_lsm_t *)p_ses;
-    struct st_module_param_info *mparams = p_lsm_ses->lsm_usecase->params;
-
-    ALOGD("%s:[%d] Enter", __func__, p_lsm_ses->common.sm_handle);
-
-    if (!p_lsm_ses->pcm) {
-        ALOGV("%s: pcm NULL", __func__);
-        return status;
-    }
-
-    /* Exit the callback thread waiting on event detection */
-    request_exit_callback_thread(p_lsm_ses);
-
-    /* note see note in ape_dereg_sm */
-    pthread_join(p_lsm_ses->callback_thread, (void **) NULL);
-
-    if (p_ses->lab_enabled) {
-        buf_en = 0;
-        ATRACE_BEGIN("sthal:lsm: pcm_ioctl sndrv_lsm_lab_control");
-        status = pcm_ioctl(p_lsm_ses->pcm, SNDRV_LSM_LAB_CONTROL, &buf_en);
-        ATRACE_END();
-        if (status)
-            ALOGE("%s: ERROR. SNDRV_LSM_LAB_CONTROL failed, status=%d",
-            __func__, status);
-
-        if (p_lsm_ses->lab_buffers_allocated) {
-            /* Deallocate lab buffes allocated during start_recognition */
-            deallocate_lab_buffers_cpe(p_lsm_ses);
-        }
-    }
-
-    param_info.param_type = LSM_DEREG_SND_MODEL;
-    param_info.module_id = mparams[UNLOAD_SOUND_MODEL].module_id;
-    param_info.param_id = mparams[UNLOAD_SOUND_MODEL].param_id;
-    param_info.param_size = 0;
-
-    lsm_params.num_params = 1;
-    lsm_params.params = (unsigned char*)&param_info;
-    lsm_params.data_size =
-        lsm_params.num_params * sizeof(struct lsm_params_info);
-
-    ATRACE_BEGIN("sthal:lsm: pcm_ioctl sndrv_lsm_set_module_params");
-    status = pcm_ioctl(p_lsm_ses->pcm, SNDRV_LSM_SET_MODULE_PARAMS,
-       &lsm_params);
-    ATRACE_END();
-
-    if (status)
-        ALOGE("%s: ERROR. SNDRV_LSM_SET_MODULE_PARAMS->dereg status=%d",
-              __func__, status);
-
-    ATRACE_BEGIN("sthal:lsm: pcm_close");
-    pcm_close(p_lsm_ses->pcm);
-    ATRACE_END();
-    p_lsm_ses->pcm = NULL;
-    platform_cpe_free_pcm_device_id(p_ses->stdev->platform, p_lsm_ses->pcm_id);
-
-    ALOGD("%s:[%d] Exit, status=%d", __func__, p_lsm_ses->common.sm_handle,
-        status);
-    return status;
-}
-
-static int cpe_reg_sm_params(st_hw_session_t* p_ses,
-    unsigned int recognition_mode, bool capture_requested,
-    struct sound_trigger_recognition_config *rc_config __unused,
-    sound_trigger_sound_model_type_t sm_type, void *sm_data __unused)
-{
-    int status = 0, idx = 0;
-    int retry_num = 0, offset = 0;
-    bool disable_custom_config = false;
-    st_hw_session_lsm_t *p_lsm_ses = (st_hw_session_lsm_t*)p_ses;
-    struct st_vendor_info *v_info = p_lsm_ses->common.vendor_uuid_info;
-    struct snd_lsm_module_params lsm_params;
-    struct lsm_params_info param_info[3];
-    struct lsm_params_info *cfl_params;
-    struct lsm_params_info *op_params;
-    struct lsm_params_info *cus_params;
-    struct snd_lsm_detect_mode det_mode;
-    int param_tag_tracker;
-    unsigned char *custom_payload = NULL;
-    struct lsm_param_payload custom_conf_params;
-    uint32_t custom_payload_size;
-    struct st_module_param_info *mparams = p_lsm_ses->lsm_usecase->params;
-
-    ALOGD("%s:[%d] Enter", __func__, p_lsm_ses->common.sm_handle);
-    if (!p_lsm_ses->pcm) {
-        ALOGW("%s: pcm NULL", __func__);
-        return status;
-    }
-
-    if (v_info == NULL) {
-        ALOGE("%s: ERROR. v_info is null", __func__);
-        return -EINVAL;
-    }
-
-    status = lsm_set_port(p_lsm_ses);
-    if (status) {
-        ALOGE("%s: ERROR. set port failed, returned status %d",
-              __func__, status);
-        return status;
-    }
-
-    if (!capture_requested && v_info->is_qcva_uuid &&
-        (p_ses->sthw_cfg.custom_data_size > CUSTOM_CONFIG_OPAQUE_DATA_SIZE))
-        disable_custom_config = true;
-
-    ATRACE_BEGIN("sthal:lsm: pcm_start");
-    status = pcm_start(p_lsm_ses->pcm);
-    while (status && (retry_num < SOUND_TRIGGER_PCM_MAX_RETRY)) {
-        usleep(SOUND_TRIGGER_PCM_SLEEP_WAIT);
-        retry_num++;
-        ALOGI("%s: pcm_start retrying..status %d errno %d, retry cnt %d",
-              __func__, status, errno, retry_num);
-        status = pcm_start(p_lsm_ses->pcm);
-    }
-    ATRACE_END();
-    if (status) {
-        ALOGE("%s: ERROR. pcm_start failed, returned status %d",
-              __func__, status);
-        return status;
-    }
-
-    memset(&det_mode, 0, sizeof(struct snd_lsm_detect_mode));
-    if (sm_type == SOUND_MODEL_TYPE_KEYPHRASE) {
-        /* SVA doesn't support per keyword recogntion mode.
-         * Use the per soundmodel recognition mode
-         */
-        if (recognition_mode & RECOGNITION_MODE_VOICE_TRIGGER){
-            det_mode.mode= LSM_MODE_KEYWORD_ONLY_DETECTION;
-            if (recognition_mode & RECOGNITION_MODE_USER_IDENTIFICATION)
-                det_mode.mode = LSM_MODE_USER_KEYWORD_DETECTION;
-        } else {
-            ALOGE("%s: Unknown recognition mode %d", __func__, recognition_mode);
-            goto err_exit_1;
-        }
-    }
-
-    lsm_params.num_params = 0;
-    param_tag_tracker = p_lsm_ses->lsm_usecase->param_tag_tracker;
-
-    /*
-     * If this is generic sound model or other than QTI VA, pass only the
-     * opaque data as custom params and ignore sending all other params.
-     */
-    if ((v_info->is_qcva_uuid || v_info->is_qcmd_uuid) &&
-        (sm_type == SOUND_MODEL_TYPE_KEYPHRASE)) {
-        det_mode.detect_failure = p_ses->stdev->detect_failure;
-        ALOGV("%s: dm %d df %d lab %d", __func__,
-               det_mode.mode, det_mode.detect_failure, capture_requested);
-
-        if ((param_tag_tracker & PARAM_CONFIDENCE_LEVELS_BIT) &&
-             p_ses->sthw_cfg.conf_levels) {
-            /* fill confidence level params if present */
-            cfl_params = &param_info[idx++];
-            cfl_params->param_type = LSM_MIN_CONFIDENCE_LEVELS;
-            cfl_params->module_id = mparams[CONFIDENCE_LEVELS].module_id;
-            cfl_params->param_id = mparams[CONFIDENCE_LEVELS].param_id;
-            cfl_params->param_size = p_ses->sthw_cfg.num_conf_levels;
-            cfl_params->param_data = p_ses->sthw_cfg.conf_levels;
-            lsm_params.num_params++;
-            {
-                unsigned int i;
-                ALOGD("%s: ncl %d", __func__, cfl_params->param_size);
-                for (i = 0; i < cfl_params->param_size; i++) {
-                    ALOGV("%s: conf_levels[%d] = %d", __func__,
-                                        i, cfl_params->param_data[i]);
-                }
-            }
-        }
-        if (param_tag_tracker & PARAM_OPERATION_MODE_BIT) {
-            /* fill operation mode params */
-            op_params = &param_info[idx++];
-            op_params->param_type = LSM_OPERATION_MODE;
-            op_params->module_id = mparams[OPERATION_MODE].module_id;
-            op_params->param_id = mparams[OPERATION_MODE].param_id;
-            op_params->param_size = sizeof(det_mode);
-            op_params->param_data = (unsigned char *)&det_mode;
-            lsm_params.num_params++;
-        }
-    }
-
-    if (p_ses->sthw_cfg.custom_data_size && !disable_custom_config) {
-        /* fill opaque data as custom params */
-        cus_params = &param_info[idx++];
-        if (param_tag_tracker & PARAM_CUSTOM_CONFIG_BIT) {
-            /* Fill custom config params, module id,
-               param id and size. Append it with payload data. */
-            custom_conf_params.module_id = mparams[CUSTOM_CONFIG].module_id;
-            custom_conf_params.param_id = mparams[CUSTOM_CONFIG].param_id;
-            custom_conf_params.p_size = sizeof(struct st_hist_buffer_info);
-
-            custom_payload_size = sizeof(struct lsm_param_payload) +
-                    sizeof(struct st_hist_buffer_info);
-            custom_payload = (unsigned char *)calloc(1, custom_payload_size);
-            if (!custom_payload) {
-                  ALOGE("%s: ERROR. Cannot allcoate memory for custom_payload", __func__);
-                  goto error_exit;
-            }
-            /* copy custom config params to payload */
-            memcpy(custom_payload, &custom_conf_params, sizeof(struct lsm_param_payload));
-            offset += sizeof(struct lsm_param_payload);
-            /* copy opaque data from recognition config to payload */
-            if (v_info->is_qcva_uuid &&
-                ((p_ses->sthw_cfg.custom_data_size == 0) ||
-                 (p_ses->sthw_cfg.custom_data_size >
-                  CUSTOM_CONFIG_OPAQUE_DATA_SIZE))) {
-               st_hw_ses_get_hist_buff_payload(p_ses,
-                   (uint8_t *)custom_payload + offset,
-                   custom_payload_size - offset);
-            } else {
-              /* copy opaque data from recognition config to payload */
-              memcpy((char *)custom_payload + offset,
-                    p_ses->sthw_cfg.custom_data, p_ses->sthw_cfg.custom_data_size);
-            }
-        } else {
-            /*
-             * Send opaque data as it is,
-             * Using legacy custom param where app needs to form appropriate payload.
-             */
-            custom_payload_size = p_ses->sthw_cfg.custom_data_size;
-            custom_payload = calloc(1, custom_payload_size);
-            if (!custom_payload) {
-                ALOGE("%s: ERROR. Cannot allocate memory for custom_payload", __func__);
-                goto error_exit;
-            }
-            memcpy(custom_payload, p_ses->sthw_cfg.custom_data,
-                p_ses->sthw_cfg.custom_data_size);
-        }
-        cus_params->param_type = LSM_CUSTOM_PARAMS;
-        cus_params->param_size = custom_payload_size;
-        cus_params->param_data = (unsigned char *)custom_payload;
-        lsm_params.num_params++;
-    }
-
-    if (lsm_params.num_params) {
-        lsm_params.params = (unsigned char*)param_info;
-        lsm_params.data_size =
-            lsm_params.num_params * sizeof(struct lsm_params_info);
-
-        ATRACE_BEGIN("sthal:lsm: pcm_ioctl sndrv_lsm_set_module_params");
-        status = pcm_ioctl(p_lsm_ses->pcm, SNDRV_LSM_SET_MODULE_PARAMS, &lsm_params);
-        ATRACE_END();
-        if (status) {
-            ALOGE("%s: ERROR. SNDRV_LSM_SET_MODULE_PARAMS->reg_params %d, status=%d",
-                  __func__, lsm_params.num_params, status);
-            goto err_exit_1;
-        }
-    }
-
-    if (capture_requested) {
-        if (!p_lsm_ses->lab_buffers_allocated) {
-            /* Instead of allocating and deallocating during frequent
-               start/stop_recogntion, allocate once and dellocate during
-               unload_sound_model */
-            status = allocate_lab_buffers_cpe(p_lsm_ses);
-            if (status)
-                goto err_exit_1;
-        }
-        status = configure_lab(p_lsm_ses, capture_requested);
-        if (status)
-            goto err_exit_1;
-    }
-    p_ses->lab_enabled = capture_requested;
-    ALOGD("%s:[%d] Exit, status=%d", __func__, p_lsm_ses->common.sm_handle, status);
-    return 0;
-error_exit:
-    if (custom_payload)
-        free(custom_payload);
-err_exit_1:
-    if (p_lsm_ses->lab_buffers_allocated)
-        deallocate_lab_buffers_cpe(p_lsm_ses);
-
-    pcm_stop(p_lsm_ses->pcm);
-
-    return status;
-}
-
-static int cpe_dereg_sm_params(st_hw_session_t* p_ses)
-{
-    int status = 0;
-    st_hw_session_lsm_t *p_lsm_ses =
-       (st_hw_session_lsm_t *)p_ses;
-
-    ALOGD("%s:[%d] Enter", __func__, p_lsm_ses->common.sm_handle);
-    if (p_lsm_ses->pcm) {
-        ATRACE_BEGIN("sthal:lsm: pcm_stop");
-        status = pcm_stop(p_lsm_ses->pcm);
-        ATRACE_END();
-        if (status)
-            ALOGE("%s: ERROR. pcm_stop failed: %s", __func__,
-               pcm_get_error(p_lsm_ses->pcm));
-
-    }
-
-    ALOGD("%s:[%d] Exit", __func__, p_lsm_ses->common.sm_handle);
-    return status;
-}
-
-static int cpe_start(st_hw_session_t* p_ses)
-{
-    int status = 0;
-    st_hw_session_lsm_t *p_lsm_ses = (st_hw_session_lsm_t *)p_ses;
-
-    ALOGD("%s:[%d] Enter", __func__, p_lsm_ses->common.sm_handle);
-    if (!p_lsm_ses->pcm) {
-        ALOGW("%s: pcm NULL", __func__);
-        return status;
-    }
-
-    ATRACE_BEGIN("sthal:lsm: pcm_ioctl sndrv_lsm_start");
-    status = pcm_ioctl(p_lsm_ses->pcm, SNDRV_LSM_START);
-    ATRACE_END();
-    if (status) {
-        ALOGE("%s: ERROR. SNDRV_LSM_START failed, status=%d", __func__, status);
-    }
-
-    ALOGD("%s:[%d] Exit, status=%d", __func__, p_lsm_ses->common.sm_handle,
-        status);
-
-    SET_STATE(p_lsm_ses->common.state, SES_STARTED);
-    return status;
-}
-
-static int cpe_stop(st_hw_session_t* p_ses)
-{
-    int status = 0;
-    st_hw_session_lsm_t *p_lsm_ses = (st_hw_session_lsm_t *)p_ses;
-
-    ALOGD("%s:[%d] Enter", __func__, p_lsm_ses->common.sm_handle);
-    if (!p_lsm_ses->pcm) {
-        ALOGW("%s: pcm NULL", __func__);
-        return status;
-    }
-
-    ATRACE_BEGIN("sthal:lsm: pcm_ioctl sndrv_lsm_stop");
-    status = pcm_ioctl(p_lsm_ses->pcm, SNDRV_LSM_STOP);
-    ATRACE_END();
-    if (status)
-        ALOGE("%s: ERROR. SNDDRV_LSM_STOP failed, status=%d", __func__, status);
-
-    ALOGD("%s:[%d] Exit, status=%d", __func__, p_lsm_ses->common.sm_handle,
-        status);
-    return status;
-}
-
-static int cpe_stop_buffering(st_hw_session_t* p_ses)
-{
-    int status = 0;
-    st_hw_session_lsm_t *p_lsm_ses =
-       (st_hw_session_lsm_t *)p_ses;
-
-    ALOGD("%s:[%d] Enter pcm %p", __func__, p_lsm_ses->common.sm_handle,
-        p_lsm_ses->pcm);
-    if (!p_lsm_ses->pcm) {
-        ALOGW("%s: pcm NULL", __func__);
-        return status;
-    }
-
-    ATRACE_BEGIN("sthal:lsm: pcm_ioctl sndrv_lsm_stop_lab");
-    status = pcm_ioctl(p_lsm_ses->pcm, SNDRV_LSM_STOP_LAB);
-    ATRACE_END();
-    if (status) {
-        ALOGE("%s: ERROR. SNDRV_LSM_STOP_BUFFERING failed status %d", __func__,
-           status);
-    } else {
-        ATRACE_BEGIN("sthal:lsm: pcm_ioctl sndrv_pcm_ioctl_reset");
-        status = pcm_ioctl(p_lsm_ses->pcm, SNDRV_PCM_IOCTL_RESET);
-        ATRACE_END();
-        if (status)
-            ALOGE("%s: ERROR. SNDRV_PCM_IOCTL_RESET failed status %d",
-               __func__, status);
-    }
-    if (p_ses->lab_enabled) {
-        pthread_mutex_lock(&p_lsm_ses->lock);
-        pthread_cond_broadcast(&p_lsm_ses->cond);
-        pthread_mutex_unlock(&p_lsm_ses->lock);
-    }
-
-    ALOGD("%s:[%d] Exit, status=%d", __func__, p_ses->sm_handle, status);
-    return status;
-}
-
 static int route_reg_sm_ape(st_hw_session_t *p_ses,void *sm_data,
     unsigned int sm_size, sound_trigger_sound_model_type_t sm_type)
 {
@@ -3708,9 +2468,10 @@
 {
     st_hw_session_lsm_t *p_lsm_ses = (st_hw_session_lsm_t *)p_ses;
 
-    ATRACE_BEGIN("sthal:lsm: process_raw_lab_data_ape");
-    process_raw_lab_data_ape(p_lsm_ses);
-    ATRACE_END();
+    pthread_mutex_lock(&p_lsm_ses->lock);
+    p_lsm_ses->lab_processing_active = true;
+    pthread_cond_signal(&p_lsm_ses->cond);
+    pthread_mutex_unlock(&p_lsm_ses->lock);
 }
 
 int route_send_custom_chmix_coeff_ape(st_hw_session_t *p_ses, char *str)
@@ -3723,134 +2484,12 @@
                                                                   str);
 }
 
-static int route_reg_sm_cpe(st_hw_session_t *p_ses, void* sm_data,
-    unsigned int sm_size, sound_trigger_sound_model_type_t sm_type)
-{
-    return cpe_reg_sm(p_ses, sm_data, sm_size, sm_type);
-}
-
-static int route_reg_sm_params_cpe(st_hw_session_t* p_ses,
-    unsigned int recognition_mode, bool capture_requested,
-    struct sound_trigger_recognition_config *rc_config,
-    sound_trigger_sound_model_type_t sm_type, void *sm_data)
-{
-    return cpe_reg_sm_params(p_ses, recognition_mode, capture_requested,
-        rc_config, sm_type, sm_data);
-}
-
-static int route_dereg_sm_params_cpe(st_hw_session_t* p_ses)
-{
-    return cpe_dereg_sm_params(p_ses);
-}
-
-static int route_dereg_sm_cpe(st_hw_session_t* p_ses)
-{
-    return cpe_dereg_sm(p_ses);
-}
-
-static int route_start_cpe(st_hw_session_t* p_ses)
-{
-    return cpe_start(p_ses);
-}
-
-static int route_restart(st_hw_session_t* p_ses __unused, unsigned int recognition_mode __unused,
-   struct sound_trigger_recognition_config *rc_config __unused,
-   sound_trigger_sound_model_type_t sm_type __unused, void *sm_data __unused)
-{
-    /*
-     * this is a noop, in the case of LSM if session is already
-     * started there is no need to stop/start even after detection
-     */
-    return 0;
-}
-
-static int route_stop_cpe(st_hw_session_t* p_ses)
-{
-    return cpe_stop(p_ses);
-}
-
-static int route_stop_buffering_cpe(st_hw_session_t* p_ses)
-{
-    int status = 0;
-    st_arm_second_stage_t *st_sec_stage;
-    struct listnode *node = NULL, *tmp_node = NULL;
-
-    if (!CHECK_STATE(p_ses->state, SES_BUFFERING)) {
-        return status;
-    }
-
-    if (p_ses->enable_second_stage) {
-        list_for_each_safe(node, tmp_node, p_ses->second_stage_list) {
-            st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
-            pthread_mutex_lock(&st_sec_stage->ss_session->lock);
-            st_sec_stage->ss_session->exit_buffering = true;
-            pthread_cond_signal(&st_sec_stage->ss_session->cond);
-            pthread_mutex_unlock(&st_sec_stage->ss_session->lock);
-        }
-    }
-
-    check_and_exit_lab(p_ses);
-    status = cpe_stop_buffering(p_ses);
-
-    CLEAR_STATE(p_ses->state, SES_BUFFERING);
-    return status;
-}
-
-static int route_set_device_cpe(st_hw_session_t *p_ses,
-                                bool enable)
-{
-    return sound_trigger_set_device(p_ses, enable);
-}
-
-static int route_read_pcm_cpe(st_hw_session_t *p_ses,
-                              unsigned char *buf,
-                              unsigned int bytes)
-{
-    int status = 0;
-    st_hw_session_lsm_t *p_lsm_ses = (st_hw_session_lsm_t *)p_ses;
-
-    pthread_mutex_lock(&p_lsm_ses->lock);
-    if (p_lsm_ses->exit_lab_processing) {
-        ALOGE("%s: No active buffering", __func__);
-        pthread_mutex_unlock(&p_lsm_ses->lock);
-        return -EIO;
-    }
-    pthread_mutex_unlock(&p_lsm_ses->lock);
-
-    status = read_pcm_data(p_lsm_ses, buf, bytes);
-
-    return status;
-}
-
-static void route_audio_capture_cpe(st_hw_session_t *p_ses)
-{
-    SET_STATE(p_ses->state, SES_BUFFERING);
-    st_hw_session_lsm_t *p_lsm_ses = (st_hw_session_lsm_t *)p_ses;
-
-    pthread_mutex_lock(&p_lsm_ses->lock);
-    p_lsm_ses->exit_lab_processing = false;
-    pthread_mutex_unlock(&p_lsm_ses->lock);
-
-    if (p_ses->vendor_uuid_info &&
-        p_ses->vendor_uuid_info->kw_transfer_mode == FTRT_TRANSFER_MODE) {
-        process_packetized_lab_data(p_lsm_ses);
-    } else {
-        process_raw_lab_data_cpe(p_lsm_ses);
-    }
-}
-
-int route_send_custom_chmix_coeff_cpe(st_hw_session_t *p_ses __unused, char *str __unused)
-{
-    /* custom chmix coeff not supported for CPE */
-    return 0;
-}
-
 static int route_disable_device(st_hw_session_t *p_ses, bool setting_device)
 {
     int status = 0;
     st_hw_session_lsm_t *p_lsm_ses = (st_hw_session_lsm_t*)p_ses;
 
-    if (!setting_device || (p_ses->exec_mode == ST_EXEC_MODE_CPE))
+    if (!setting_device)
         return status;
 
     ALOGD("%s: Enter", __func__);
@@ -3881,9 +2520,6 @@
     st_hw_session_lsm_t *p_lsm_ses = (st_hw_session_lsm_t*)p_ses;
     audio_devices_t capture_device = 0;
 
-    if (p_ses->exec_mode == ST_EXEC_MODE_CPE)
-        return status;
-
     ALOGD("%s: Enter", __func__);
 
     if (!p_lsm_ses->pcm) {
@@ -4026,11 +2662,6 @@
         goto exit;
     }
 
-    if (p_lsm_ses->common.exec_mode == ST_EXEC_MODE_CPE) {
-        ALOGE("%s: ERROR. GetParam unsupported for CPE", __func__);
-        goto exit;
-    }
-
     ALOGD("%s:[%d] Enter param %s", __func__, p_lsm_ses->common.sm_handle, param);
     if (!strncmp(param, QSTHW_PARAMETER_DIRECTION_OF_ARRIVAL,
             sizeof(QSTHW_PARAMETER_DIRECTION_OF_ARRIVAL))) {
@@ -4199,13 +2830,7 @@
     st_hw_session_lsm_t *p_lsm_ses = (st_hw_session_lsm_t *)p_ses;
 
     p_ses->exec_mode = exec_mode;
-    if (ST_EXEC_MODE_CPE == exec_mode) {
-        ALOGV("%s: CPE mode", __func__);
-        p_ses->fptrs = &cpe_fptrs;
-    } else if (ST_EXEC_MODE_ADSP == exec_mode){
-        ALOGV("%s: APE mode", __func__);
-        p_ses->fptrs = &ape_fptrs;
-    }
+    p_ses->fptrs = &ape_fptrs;
 
     p_ses->callback_to_st_session = cb;
     p_ses->cookie = cookie;
diff --git a/st_hw_session_lsm.h b/st_hw_session_lsm.h
index fa1378b..d99a7bc 100644
--- a/st_hw_session_lsm.h
+++ b/st_hw_session_lsm.h
@@ -1,6 +1,6 @@
 /* st_hw_session_lsm.h
  *
- * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -51,11 +51,6 @@
     ((((SOUND_TRIGGER_SAMPLING_RATE_16000 * SOUND_TRIGGER_APE_BUFFER_DURATION_MS) \
        /(SOUND_TRIGGER_APE_PERIOD_COUNT * 1000)) + 0x1f) & ~0x1f)
 
-#define SOUND_TRIGGER_CPE_PERIOD_COUNT (6)
-#define SOUND_TRIGGER_CPE_PERIOD_SIZE \
-    CALCULATE_PERIOD_SIZE(SOUND_TRIGGER_CPE_LAB_DRV_BUF_DURATION_MS, \
-    SOUND_TRIGGER_SAMPLING_RATE_16000, SOUND_TRIGGER_CPE_PERIOD_COUNT, 32)
-
 /*
  * The chosen theshold for determining FTRT vs. RT data is one tenth of the
  * buffer duration. There can be frames received that are partially FTRT and
@@ -67,33 +62,6 @@
 #define APE_MAX_LAB_FTRT_FRAME_RD_TIME_NS \
     ((SOUND_TRIGGER_APE_BUFFER_DURATION_MS * NSECS_PER_MSEC)\
     / (10 * SOUND_TRIGGER_APE_PERIOD_COUNT))
-#define CPE_MAX_LAB_FTRT_FRAME_RD_TIME_NS \
-    ((SOUND_TRIGGER_CPE_LAB_DRV_BUF_DURATION_MS * NSECS_PER_MSEC)\
-    / (2 * SOUND_TRIGGER_CPE_PERIOD_COUNT))
-
-#define CEIL(a, b) (((a) + ((b)-1)) / (b))
-/* Number of pcm reads to try to find the first sync word */
-#define SOUND_TRIGGER_CPE_FTRT_SYNC_MAX_RETRY_DURATION_MS (160)
-#define SOUND_TRIGGER_SYNC_WORD_MAX_RETRY_CNT ( \
-    (CEIL((SOUND_TRIGGER_CPE_FTRT_SYNC_MAX_RETRY_DURATION_MS * \
-     SOUND_TRIGGER_CPE_PERIOD_COUNT), \
-     SOUND_TRIGGER_CPE_LAB_DRV_BUF_DURATION_MS)))
-
-/* ADPCM decoder sample sizes */
-#define ADPCM_COMPRESSION_RATIO (4)
-#define ADPCM_MAX_IN_FRAME_SIZE (162)
-#define ADPCM_MAX_OUT_SAMPLES_PER_FRAME (320)
-#define ADPCM_MAX_OUT_FRAME_SIZE (ADPCM_MAX_OUT_SAMPLES_PER_FRAME << 1)
-
-/* CPE LAB Buffer configuration params  */
-#define CPE_PACKET_SYNC_WORD (0xAA)
-#define CPE_PACKET_FORMAT_MEDIA_TYPE (0x80)
-#define CPE_PACKET_FORMAT_EOS (0x81)
-#define CPE_PACKET_FORMAT_NULL (0xFF)
-#define CPE_PACKET_FORMAT_ADPCM (0x01)
-#define CPE_PACKET_FORMAT_PCM (0x00)
-#define CPE_PACKET_DATA_FORMAT_RAW (0x01)
-#define CPE_PACKET_DATA_FORMAT_PACKED (0x00)
 
 #define LSM_ABORT_RETRY_COUNT (5)
 #define LSM_ABORT_WAIT_TIMEOUT_NS (30 * NSECS_PER_MSEC)
@@ -150,20 +118,15 @@
     struct lsm_param_payload common;
 }__packed;
 
-struct cpe_packet_hdr {
-    unsigned char sync_word;
-    unsigned char stream_type;
-    unsigned char stream_id;
-    unsigned char format;
-    unsigned short size;
-} __packed;
-
 struct st_hw_session_lsm {
     st_hw_session_t common;
     struct st_lsm_params* lsm_usecase;
     pthread_t callback_thread;
     bool exit_callback_thread;
 
+    pthread_t buffer_thread;
+    bool exit_buffer_thread;
+
     int pcm_id;
     struct pcm *pcm;
     struct pcm_config  lab_config;
@@ -176,7 +139,6 @@
     unsigned char *lab_drv_buf; /* small buffer to hold one chunk received from
                                    pcm read */
     unsigned int lab_drv_buf_size;
-    unsigned char *dec_buf;
     unsigned int unread_bytes;
     pthread_cond_t cond;
     pthread_mutex_t lock;
@@ -189,8 +151,6 @@
     bool lab_buffers_allocated;
     bool lab_on_detection;
 
-    void *adpcm_dec_state;
-
     unsigned int bytes_written;
     long first_stage_det_event_timestamp;
     bool move_client_ptr;
diff --git a/st_hw_session_pcm.c b/st_hw_session_pcm.c
index 2ed7243..7fee392 100644
--- a/st_hw_session_pcm.c
+++ b/st_hw_session_pcm.c
@@ -1268,9 +1268,8 @@
     p_pcm_ses->out_config = p_pcm_ses->common.config;
     p_pcm_ses->capture_config = p_pcm_ses->common.config;
     p_pcm_ses->lab_config = p_pcm_ses->common.config;
-    platform_stdev_check_and_update_pcm_config(p_ses->stdev->platform,
-                                               &p_pcm_ses->capture_config,
-                                               v_info, p_ses->exec_mode);
+    platform_stdev_check_and_update_pcm_config(&p_pcm_ses->capture_config,
+                                               v_info);
 
     p_pcm_ses->capture_config.period_size =
                CALCULATE_PERIOD_SIZE(SOUND_TRIGGER_PCM_BUFFER_DURATION_MS,
diff --git a/st_session.c b/st_session.c
index 0ccdeaf..a32b71d 100644
--- a/st_session.c
+++ b/st_session.c
@@ -203,6 +203,7 @@
                 ev.payload.detected.detect_status = 3;
 
             DISPATCH_EVENT(st_ses, ev, status);
+            break;
         }
 
         if (!lock_status)
@@ -210,11 +211,51 @@
         break;
     }
 
+    case ST_HW_SESS_EVENT_BUFFERING_STOPPED:
+    {
+        st_session_ev_t ev;
+        ev.ev_id = ST_SES_EV_DEFERRED_STOP;
+        ev.stc_ses = st_ses->det_stc_ses;
+
+        /*
+         * If detection is sent to client while in buffering state,
+         * and if internal buffering is stopped due to errors, stop
+         * session internally as client is expected to restart the
+         * detection if required.
+         * Note: It is possible that detection event is not sent to
+         * client if second stage is not yet detected during internal
+         * buffering stop, in which case restart is posted from second
+         * stage thread for further detections. Only if the second
+         * stage detection hasn't be started due to internal buffering
+         * stop too early, restart session should be explictily issued.
+         */
+
+        do {
+            lock_status = pthread_mutex_trylock(&st_ses->lock);
+        } while (lock_status && !st_ses->det_stc_ses->pending_stop &&
+                 (st_ses->current_state == buffering_state_fn));
+
+        if (st_ses->det_stc_ses->pending_stop)
+            ALOGV("%s:[%d] pending stop already queued, ignore event",
+                __func__, st_ses->sm_handle);
+        else if (!st_ses->det_stc_ses->detection_sent)
+            ALOGV("%s:[%d] client callback hasn't been called, ignore event",
+                __func__, st_ses->sm_handle);
+        else if (st_ses->current_state != buffering_state_fn)
+            ALOGV("%s:[%d] session already stopped buffering, ignore event",
+                __func__, st_ses->sm_handle);
+        else if (!lock_status)
+            DISPATCH_EVENT(st_ses, ev, status);
+
+        if (!lock_status)
+            pthread_mutex_unlock(&st_ses->lock);
+        break;
+    }
+
     default:
         ALOGD("%s:[%d] unhandled event", __func__, st_ses->sm_handle);
         break;
     };
-
 }
 
 static inline void free_array_ptrs(char **arr, unsigned int arr_len)
@@ -1299,7 +1340,7 @@
             payload += i;
         }
     } else {
-        if ((st_ses->exec_mode == ST_EXEC_MODE_CPE) && st_ses->stdev->is_gcs) {
+        if (st_ses->exec_mode == ST_EXEC_MODE_CPE) {
             *conf_levels = payload + 2;
             *conf_levels_size = payload_size - 2;
         } else {
@@ -2033,7 +2074,7 @@
         for (i = 0; i < conf_levels->num_sound_models; i++) {
             sm_levels = &conf_levels->conf_levels[i];
             if (sm_levels->sm_id == ST_SM_ID_SVA_GMM) {
-                if ((st_ses->stdev->is_gcs) && (st_hw_ses == st_ses->hw_ses_cpe))
+                if (st_hw_ses == st_ses->hw_ses_cpe)
                     status =
                         generate_sound_trigger_recognition_config_payload_v2(
                         (void *)sm_levels, out_conf_levels, out_num_conf_levels,
@@ -2090,8 +2131,7 @@
         for (i = 0; i < conf_levels_v2->num_sound_models; i++) {
             sm_levels_v2 = &conf_levels_v2->conf_levels[i];
             if (sm_levels_v2->sm_id == ST_SM_ID_SVA_GMM) {
-                if ((st_ses->stdev->is_gcs) &&
-                    (st_hw_ses == st_ses->hw_ses_cpe))
+                if (st_hw_ses == st_ses->hw_ses_cpe)
                     status =
                         generate_sound_trigger_recognition_config_payload_v2(
                         (void *)sm_levels_v2, out_conf_levels, out_num_conf_levels,
@@ -2269,7 +2309,7 @@
 
         if (st_ses->vendor_uuid_info->is_qcva_uuid ||
             st_ses->vendor_uuid_info->is_qcmd_uuid) {
-            if (st_ses->stdev->is_gcs && st_hw_ses == st_ses->hw_ses_cpe)
+            if (st_hw_ses == st_ses->hw_ses_cpe)
                 status = generate_conf_levels_payload_from_rc_config_v2(
                     phrase_sm, rc_config, &conf_levels, &num_conf_levels);
             else
@@ -2646,7 +2686,12 @@
         st_ses->hw_session_started = true;
     } else {
         ALOGE("%s:[%d] failed to restart", __func__, st_ses->sm_handle);
-        st_ses->hw_session_started = false;
+        /*
+         * lower layers like gcs/lsm need to handle double stop calls properly
+         * to avoid possible crash, as some of the clean ups are already issued
+         * during fptrs->restart() when it's failed.
+         */
+        stop_hw_session(st_ses, hw_ses, true);
     }
 
     return status;
@@ -2763,12 +2808,10 @@
         }
 
         if (is_active_vop_session) {
-            if ((st_ses->exec_mode == ST_EXEC_MODE_CPE) &&
-                 st_ses->stdev->is_gcs) {
+            if (st_ses->exec_mode == ST_EXEC_MODE_CPE) {
                 hw_ses->user_level = (int32_t)(*(payload_ptr +
                     GCS_NON_GENERIC_USER_LEVEL_OFFSET));
-            } else if ((st_ses->exec_mode == ST_EXEC_MODE_ADSP) ||
-                       !st_ses->stdev->is_gcs) {
+            } else if (st_ses->exec_mode == ST_EXEC_MODE_ADSP) {
                 hw_ses->user_level = (int32_t)(*(payload_ptr +
                     LSM_NON_GENERIC_USER_LEVEL_OFFSET));
             }
@@ -2784,7 +2827,7 @@
     return 0;
 }
 
-static inline int prepapre_second_stage_for_client(st_session_t *stc_ses)
+static inline int prepare_second_stage_for_client(st_session_t *stc_ses)
 {
     struct listnode *node = NULL;
     st_arm_second_stage_t *st_sec_stage = NULL;
@@ -3419,11 +3462,10 @@
             sizeof(struct sound_trigger_phrase_recognition_event);
         local_event->common.data_size = opaque_size;
         opaque_data = (uint8_t *)local_event + local_event->common.data_offset;
-        if ((st_ses->exec_mode == ST_EXEC_MODE_CPE) && st_ses->stdev->is_gcs) {
+        if (st_ses->exec_mode == ST_EXEC_MODE_CPE) {
             payload_ptr = (uint8_t *)payload + 2;
             payload_size -= 2; /* Re-use */
-        } else if ((st_ses->exec_mode == ST_EXEC_MODE_ADSP) ||
-                   !st_ses->stdev->is_gcs) {
+        } else if (st_ses->exec_mode == ST_EXEC_MODE_ADSP) {
             payload_ptr = (uint8_t *)payload;
         } else {
             ALOGE("%s: Invalid execution mode, exiting", __func__);
@@ -3503,8 +3545,7 @@
     } else {
         if (st_ses->vendor_uuid_info->is_qcva_uuid ||
             st_ses->vendor_uuid_info->is_qcmd_uuid) {
-            if (st_ses->stdev->is_gcs &&
-                ST_EXEC_MODE_CPE == st_ses->exec_mode &&
+            if (ST_EXEC_MODE_CPE == st_ses->exec_mode &&
                 !st_hw_ses->is_generic_event) {
                 payload_ptr = payload;
                 payload_ptr += 2; /* Skip minor_version and num_active_models */
@@ -4591,6 +4632,11 @@
         STATE_TRANSITION(st_ses, loaded_state_fn);
         break;
 
+    case ST_SES_EV_RESUME:
+        if (stc_ses->paused == true)
+            stc_ses->paused = false;
+        break;
+
     case ST_SES_EV_STOP:
         status = stop_session(st_ses, hw_ses, false);
         if (status)
@@ -4647,6 +4693,7 @@
              */
             if (st_ses->lab_enabled)
                 hw_ses->fptrs->stop_buffering(hw_ses);
+            pthread_mutex_unlock(&st_ses->lock);
             break;
         }
         st_ses->det_stc_ses = stc_ses;
@@ -4672,6 +4719,7 @@
                 hw_ses->fptrs->stop_buffering(hw_ses);
                 if (event)
                     free(event);
+                pthread_mutex_unlock(&st_ses->lock);
                 break;
             }
         } else {
@@ -4737,6 +4785,7 @@
             status = -EINVAL;
             if (event)
                 free(event);
+            pthread_mutex_unlock(&st_ses->lock);
             break;
         }
         /*
@@ -4753,15 +4802,22 @@
                 __func__, stc_ses->sm_handle);
             ATRACE_ASYNC_END("sthal: detection success",
                 st_ses->sm_handle);
+            if (!lab_enabled) {
+                st_session_ev_t deferred_ev = {
+                    .ev_id = ST_SES_EV_DEFERRED_STOP,
+                    .stc_ses = stc_ses
+                };
+                DISPATCH_EVENT(st_ses, deferred_ev, status);
+            }
             pthread_mutex_unlock(&st_ses->lock);
             ATRACE_BEGIN("sthal: client detection callback");
             callback(event, cookie);
             ATRACE_END();
+            if (event)
+                free(event);
         } else {
             pthread_mutex_unlock(&st_ses->lock);
         }
-        if (event)
-            free(event);
 
         /*
          * TODO: Add RECOGNITION_STATUS_GET_STATE_RESPONSE to
@@ -4774,88 +4830,6 @@
             /* Cache lab data to internal buffers (blocking call) */
             hw_ses->fptrs->process_lab_capture(hw_ses);
         }
-
-        /*
-         * It is possible that the client may start/stop/unload the session
-         * with the same lock held, before we aqcuire lock here.
-         * We need further processing only if client starts in detected state
-         * or buffering state if lab was enabled, else return gracefully.
-         * For multi-client scenario, only one client is assumed to be
-         * detected/bufffering, so the logic remains same.
-         */
-         do {
-             status = pthread_mutex_trylock(&st_ses->lock);
-         } while (status && ((st_ses->current_state == detected_state_fn) ||
-                  (st_ses->current_state == buffering_state_fn)) &&
-                  !st_ses->stdev->ssr_offline_received);
-
-        if (st_ses->current_state != detected_state_fn) {
-            ALOGV("%s:[%d] client not in detected state, lock status %d",
-                __func__, st_ses->sm_handle, status);
-            if (!status) {
-                /*
-                 * If detection is sent to client while in buffering state,
-                 * and if internal buffering is stopped due to errors, stop
-                 * session internally as client is expected to restart the
-                 * detection if required.
-                 * Note: It is possible that detection event is not sent to
-                 * client if second stage is not yet detected during internal
-                 * buffering stop, in which case restart is posted from second
-                 * stage thread for further detections. Only if the second
-                 * stage detection hasn't be started due to internal buffering
-                 * stop too early, restart session should be explictily issued.
-                 */
-                if (st_ses->current_state == buffering_state_fn) {
-                    if (stc_ses->detection_sent) {
-                        if (!stc_ses->pending_stop) {
-                            ALOGD("%s:[%d] buffering stopped internally, post c%d stop",
-                                __func__, st_ses->sm_handle,
-                                st_ses->det_stc_ses->sm_handle);
-                            status = hw_session_notifier_enqueue(stc_ses->sm_handle,
-                                ST_SES_EV_DEFERRED_STOP,
-                                ST_SES_DEFERRED_STOP_SS_DELAY_MS);
-                            if (!status)
-                                stc_ses->pending_stop = true;
-                        }
-                    } else {
-                        list_for_each(node, &stc_ses->second_stage_list) {
-                            st_sec_stage = node_to_item(node, st_arm_second_stage_t,
-                                                        list_node);
-                            if (!st_sec_stage->ss_session->start_processing) {
-                                st_session_ev_t ev = {.ev_id = ST_SES_EV_RESTART,
-                                                      .stc_ses = stc_ses};
-                                DISPATCH_EVENT(st_ses, ev, status);
-                                break;
-                            }
-                        }
-                    }
-                }
-                pthread_mutex_unlock(&st_ses->lock);
-            }
-            status = 0;
-            break;
-        }
-
-        /*
-         * If we are not buffering (i.e capture is not requested), then
-         * trigger a deferred stop. Most applications issue (re)start
-         * almost immediately. Delaying stop allows unnecessary teardown
-         * and reinitialization of backend.
-         */
-        if (!lab_enabled) {
-            /*
-             * Note that this event will only be posted to the detected state
-             * The current state may switch to active if the client
-             * issues start/restart before control of the callback thread
-             * reaches this point.
-             */
-            st_session_ev_t deferred_ev = { .ev_id = ST_SES_EV_DEFERRED_STOP,
-                .stc_ses = stc_ses};
-            DISPATCH_EVENT(st_ses, deferred_ev, status);
-        } else {
-            ALOGE("%s:[%d] capture is requested but state is still detected!?",
-                __func__, st_ses->sm_handle);
-        }
         break;
 
     case ST_SES_EV_SSR_OFFLINE:
@@ -5183,6 +5157,15 @@
         }
         break;
 
+    case ST_SES_EV_DEFERRED_STOP:
+        ALOGD("%s:[%d] post internal deferred stop from buffering state",
+            __func__, st_ses->sm_handle);
+        status = hw_session_notifier_enqueue(stc_ses->sm_handle,
+            ST_SES_EV_DEFERRED_STOP, ST_SES_DEFERRED_STOP_DELAY_MS);
+        if (!status)
+            stc_ses->pending_stop = true;
+        break;
+
     case ST_SES_EV_STOP:
          ALOGD("%s:[c%d-%d] handle event STOP", __func__, stc_ses->sm_handle,
              st_ses->sm_handle);
@@ -5260,6 +5243,7 @@
         hw_ses->fptrs->stop_buffering(hw_ses);
         if (hw_ses->sthw_cfg_updated || ev->ev_id == ST_SES_EV_START) {
             status = stop_session(st_ses, hw_ses, false);
+            STATE_TRANSITION(st_ses, loaded_state_fn);
             if (status) {
                 ALOGE("%s:[%d] failed to stop session, err %d", __func__,
                     st_ses->sm_handle, status);
@@ -5467,7 +5451,6 @@
                 status = -EINVAL;
                 break;
             }
-            prepapre_second_stage_for_client(stc_ses);
             stc_ses->state = ST_STATE_LOADED;
         } else {
             ALOGE("%s: received unexpected event, client state = %d",
@@ -5481,7 +5464,6 @@
             if (status)
                 ALOGE("%s:[c%d] update sound_model failed %d", __func__,
                     stc_ses->sm_handle, status);
-            stop_second_stage_for_client(stc_ses);
             stc_ses->state = ST_STATE_IDLE;
         } else {
             ALOGE("%s: received unexpected event, client state = %d",
@@ -5574,7 +5556,7 @@
     pthread_mutex_lock(&st_ses->lock);
     DISPATCH_EVENT(st_ses, ev, status);
     if (!status) {
-        prepapre_second_stage_for_client(stc_ses);
+        prepare_second_stage_for_client(stc_ses);
         stc_ses->state = ST_STATE_LOADED;
     }
     pthread_mutex_unlock(&st_ses->lock);
@@ -6207,70 +6189,38 @@
 
     if (v_info && (EXEC_MODE_CFG_DYNAMIC == v_info->exec_mode_cfg)) {
         st_ses->enable_trans = true;
-        if (stdev->is_gcs) {
             /* alloc and init cpe session*/
-            st_ses->hw_ses_cpe =
-                (st_hw_session_t *)calloc(1, sizeof(st_hw_session_gcs_t));
-            if (!st_ses->hw_ses_cpe) {
-                status = -ENOMEM;
-                goto cleanup;
-            }
-            status = st_hw_sess_gcs_init(st_ses->hw_ses_cpe, hw_sess_cb,
-                (void *)st_ses, ST_EXEC_MODE_CPE, v_info, sm_handle, stdev);
-            if (status) {
-                ALOGE("%s: initializing gcs hw session failed %d", __func__,
-                    status);
-                goto cleanup;
-            }
-
-            /* alloc and init adsp session*/
-            st_ses->hw_ses_adsp =
-                (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
-            if (!st_ses->hw_ses_adsp) {
-                st_hw_sess_gcs_deinit(st_ses->hw_ses_cpe);
-                status = -ENOMEM;
-                goto cleanup;
-            }
-
-            status = st_hw_sess_lsm_init(st_ses->hw_ses_adsp, hw_sess_cb,
-                (void *)st_ses, ST_EXEC_MODE_ADSP, v_info, sm_handle, stdev);
-            if (status) {
-                ALOGE("%s: initializing lsm session failed", __func__);
-                st_hw_sess_gcs_deinit(st_ses->hw_ses_cpe);
-                goto cleanup;
-            }
-
-        } else {
-            /* alloc and init cpe session*/
-            st_ses->hw_ses_cpe =
-                (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
-            if (!st_ses->hw_ses_cpe) {
-                status = -ENOMEM;
-                goto cleanup;
-            }
-            status = st_hw_sess_lsm_init(st_ses->hw_ses_cpe, hw_sess_cb,
-                (void *)st_ses, ST_EXEC_MODE_CPE, v_info, sm_handle, stdev);
-            if (status) {
-                ALOGE("%s: initialzing lsm hw session failed %d", __func__,
-                    status);
-                goto cleanup;
-            }
-            /* alloc and init adsp session*/
-            st_ses->hw_ses_adsp =
-                (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
-            if (!st_ses->hw_ses_adsp) {
-                status = -ENOMEM;
-                st_hw_sess_lsm_deinit(st_ses->hw_ses_cpe);
-                goto cleanup;
-            }
-            status = st_hw_sess_lsm_init(st_ses->hw_ses_adsp, hw_sess_cb,
-                (void *)st_ses, ST_EXEC_MODE_ADSP, v_info, sm_handle, stdev);
-            if (status) {
-                ALOGE("%s: initializing lsm session failed", __func__);
-                st_hw_sess_lsm_deinit(st_ses->hw_ses_cpe);
-                goto cleanup;
-            }
+        st_ses->hw_ses_cpe =
+            (st_hw_session_t *)calloc(1, sizeof(st_hw_session_gcs_t));
+        if (!st_ses->hw_ses_cpe) {
+            status = -ENOMEM;
+            goto cleanup;
         }
+        status = st_hw_sess_gcs_init(st_ses->hw_ses_cpe, hw_sess_cb,
+            (void *)st_ses, ST_EXEC_MODE_CPE, v_info, sm_handle, stdev);
+        if (status) {
+            ALOGE("%s: initializing gcs hw session failed %d", __func__,
+                status);
+            goto cleanup;
+        }
+
+        /* alloc and init adsp session*/
+        st_ses->hw_ses_adsp =
+            (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
+        if (!st_ses->hw_ses_adsp) {
+            st_hw_sess_gcs_deinit(st_ses->hw_ses_cpe);
+            status = -ENOMEM;
+            goto cleanup;
+        }
+
+        status = st_hw_sess_lsm_init(st_ses->hw_ses_adsp, hw_sess_cb,
+            (void *)st_ses, ST_EXEC_MODE_ADSP, v_info, sm_handle, stdev);
+        if (status) {
+            ALOGE("%s: initializing lsm session failed", __func__);
+            st_hw_sess_gcs_deinit(st_ses->hw_ses_cpe);
+            goto cleanup;
+        }
+
         /* set current hw_session */
         if (exec_mode == ST_EXEC_MODE_CPE)
             st_ses->hw_ses_current = st_ses->hw_ses_cpe;
@@ -6278,36 +6228,22 @@
             st_ses->hw_ses_current = st_ses->hw_ses_adsp;
     } else if (v_info && (EXEC_MODE_CFG_CPE == v_info->exec_mode_cfg)) {
         st_ses->enable_trans = false;
-        if (stdev->is_gcs) {
-            ALOGD("%s: initializing gcs hw session", __func__);
-            st_ses->hw_ses_cpe =
-                (st_hw_session_t *)calloc(1, sizeof(st_hw_session_gcs_t));
-            if (!st_ses->hw_ses_cpe) {
-                status = -ENOMEM;
-                goto cleanup;
-            }
-            status = st_hw_sess_gcs_init(st_ses->hw_ses_cpe, hw_sess_cb,
-                (void *)st_ses, exec_mode, v_info, sm_handle, stdev);
-            if (status) {
-                ALOGE("%s: initializing gcs hw session failed %d",
-                    __func__, status);
-                goto cleanup;
-            }
-        } else {
-            st_ses->hw_ses_cpe =
-                (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
-            if (!st_ses->hw_ses_cpe) {
-                status = -ENOMEM;
-                goto cleanup;
-            }
-            status = st_hw_sess_lsm_init(st_ses->hw_ses_cpe, hw_sess_cb,
-                (void *)st_ses, exec_mode, v_info, sm_handle, stdev);
-            if (status) {
-                ALOGE("%s: initializing lsm hw session failed %d",
-                    __func__, status);
-                goto cleanup;
-            }
+
+        ALOGD("%s: initializing gcs hw session", __func__);
+        st_ses->hw_ses_cpe =
+            (st_hw_session_t *)calloc(1, sizeof(st_hw_session_gcs_t));
+        if (!st_ses->hw_ses_cpe) {
+            status = -ENOMEM;
+            goto cleanup;
         }
+        status = st_hw_sess_gcs_init(st_ses->hw_ses_cpe, hw_sess_cb,
+            (void *)st_ses, exec_mode, v_info, sm_handle, stdev);
+        if (status) {
+            ALOGE("%s: initializing gcs hw session failed %d",
+                __func__, status);
+            goto cleanup;
+        }
+
         st_ses->hw_ses_current = st_ses->hw_ses_cpe;
     } else if (v_info && (EXEC_MODE_CFG_APE == v_info->exec_mode_cfg)) {
         /*
@@ -6444,10 +6380,7 @@
     }
     /* deinit cpe session */
     if (st_ses->hw_ses_cpe) {
-        if (st_ses->stdev->is_gcs)
-            st_hw_sess_gcs_deinit(st_ses->hw_ses_cpe);
-        else
-            st_hw_sess_lsm_deinit(st_ses->hw_ses_cpe);
+        st_hw_sess_gcs_deinit(st_ses->hw_ses_cpe);
         free(st_ses->hw_ses_cpe);
         st_ses->hw_ses_cpe = NULL;
     }