Merge pie-platform-release to aosp-master - DO NOT MERGE

Change-Id: I2bbd0ebb165a7013daff8a84dec747cf0e24c02e
diff --git a/hal/audio_extn/a2dp.c b/hal/audio_extn/a2dp.c
index d1671a8..797daee 100644
--- a/hal/audio_extn/a2dp.c
+++ b/hal/audio_extn/a2dp.c
@@ -159,6 +159,11 @@
     IMC_ENABLE,
 } imc_status_t;
 
+typedef enum {
+    MTU_SIZE,
+    PEAK_BIT_RATE,
+} frame_control_type_t;
+
 /* PCM config for ABR Feedback hostless front end */
 static struct pcm_config pcm_config_abr = {
     .channels = 1,
@@ -288,6 +293,17 @@
     uint32_t comm_instance;
 };
 
+/* Structure to control frame size of AAC encoded frames. */
+struct aac_frame_size_control_t {
+    /* Type of frame size control: MTU_SIZE / PEAK_BIT_RATE*/
+    uint32_t ctl_type;
+    /* Control value
+     * MTU_SIZE: MTU size in bytes
+     * PEAK_BIT_RATE: Peak bitrate in bits per second.
+     */
+    uint32_t ctl_value;
+};
+
 /* Structure used for ABR config of AFE encoder and decoder. */
 struct abr_enc_cfg_t {
     /* Link quality level to bitrate mapping info sent to DSP. */
@@ -310,10 +326,7 @@
  * These values should match with DSP interface defintion
  */
 
-/* AAC encoder configuration structure. */
-typedef struct aac_enc_cfg_t aac_enc_cfg_t;
-
-struct aac_enc_cfg_t {
+struct aac_cfg_blk_t {
     /* Encoder media format for AAC */
     uint32_t      enc_format;
 
@@ -333,6 +346,14 @@
     uint32_t      sample_rate;
 } __attribute__ ((packed));
 
+/* AAC encoder configuration structure. */
+typedef struct aac_enc_cfg_t aac_enc_cfg_t;
+
+struct aac_enc_cfg_t {
+    struct aac_cfg_blk_t aac_cfg;
+    struct aac_frame_size_control_t frame_ctl;
+} __attribute__ ((packed));
+
 /* SBC encoder configuration structure. */
 typedef struct sbc_enc_cfg_t sbc_enc_cfg_t;
 
@@ -493,6 +514,7 @@
     uint32_t sampling_rate;
     uint32_t bitrate;
     uint32_t bits_per_sample;
+    struct aac_frame_size_control_t frame_ctl;
 } audio_aac_encoder_config;
 
 /* Information about Bluetooth LDAC encoder configuration
@@ -807,20 +829,21 @@
     }
 
     // Set Tx backend sample rate
-    if (a2dp.abr_config.is_abr_enabled)
+    if (a2dp.abr_config.is_abr_enabled) {
         rate_str = ABR_TX_SAMPLE_RATE;
 
-    ALOGV("%s: set backend tx sample rate = %s", __func__, rate_str);
-    ctl_sample_rate = mixer_get_ctl_by_name(a2dp.adev->mixer,
-                                        MIXER_SAMPLE_RATE_TX);
-    if (!ctl_sample_rate) {
-        ALOGE("%s: ERROR backend sample rate mixer control not identifed", __func__);
-        return -ENOSYS;
-    }
-    if (mixer_ctl_set_enum_by_string(ctl_sample_rate, rate_str) != 0) {
-        ALOGE("%s: Failed to set backend sample rate = %s",
-                                    __func__, rate_str);
-        return -ENOSYS;
+        ALOGV("%s: set backend tx sample rate = %s", __func__, rate_str);
+        ctl_sample_rate = mixer_get_ctl_by_name(a2dp.adev->mixer,
+                                            MIXER_SAMPLE_RATE_TX);
+        if (!ctl_sample_rate) {
+            ALOGE("%s: ERROR backend sample rate mixer control not identifed", __func__);
+            return -ENOSYS;
+        }
+        if (mixer_ctl_set_enum_by_string(ctl_sample_rate, rate_str) != 0) {
+            ALOGE("%s: Failed to set backend sample rate = %s",
+                                        __func__, rate_str);
+            return -ENOSYS;
+        }
     }
 
     // Configure AFE input channels
@@ -901,15 +924,17 @@
         return -ENOSYS;
     }
 
-    ctl_sample_rate_tx = mixer_get_ctl_by_name(a2dp.adev->mixer,
-                                        MIXER_SAMPLE_RATE_TX);
-    if (!ctl_sample_rate_tx) {
-        ALOGE("%s: ERROR Tx backend sample rate mixer control not identifed", __func__);
-        return -ENOSYS;
-    }
-    if (mixer_ctl_set_enum_by_string(ctl_sample_rate_tx, rate_str) != 0) {
-        ALOGE("%s: Failed to reset Tx backend sample rate = %s", __func__, rate_str);
-        return -ENOSYS;
+    if (a2dp.abr_config.is_abr_enabled) {
+        ctl_sample_rate_tx = mixer_get_ctl_by_name(a2dp.adev->mixer,
+                                            MIXER_SAMPLE_RATE_TX);
+        if (!ctl_sample_rate_tx) {
+            ALOGE("%s: ERROR Tx backend sample rate mixer control not identifed", __func__);
+            return -ENOSYS;
+        }
+        if (mixer_ctl_set_enum_by_string(ctl_sample_rate_tx, rate_str) != 0) {
+            ALOGE("%s: Failed to reset Tx backend sample rate = %s", __func__, rate_str);
+            return -ENOSYS;
+        }
     }
 
     // Reset AFE input channels
@@ -1184,23 +1209,25 @@
         goto exit;
     }
     memset(&aac_dsp_cfg, 0x0, sizeof(aac_dsp_cfg));
-    aac_dsp_cfg.enc_format = ENC_MEDIA_FMT_AAC;
-    aac_dsp_cfg.bit_rate = aac_bt_cfg->bitrate;
-    aac_dsp_cfg.sample_rate = aac_bt_cfg->sampling_rate;
+    aac_dsp_cfg.aac_cfg.enc_format = ENC_MEDIA_FMT_AAC;
+    aac_dsp_cfg.aac_cfg.bit_rate = aac_bt_cfg->bitrate;
+    aac_dsp_cfg.aac_cfg.sample_rate = aac_bt_cfg->sampling_rate;
     switch (aac_bt_cfg->enc_mode) {
         case 0:
-            aac_dsp_cfg.enc_mode = MEDIA_FMT_AAC_AOT_LC;
+            aac_dsp_cfg.aac_cfg.enc_mode = MEDIA_FMT_AAC_AOT_LC;
             break;
         case 2:
-            aac_dsp_cfg.enc_mode = MEDIA_FMT_AAC_AOT_PS;
+            aac_dsp_cfg.aac_cfg.enc_mode = MEDIA_FMT_AAC_AOT_PS;
             break;
         case 1:
         default:
-            aac_dsp_cfg.enc_mode = MEDIA_FMT_AAC_AOT_SBR;
+            aac_dsp_cfg.aac_cfg.enc_mode = MEDIA_FMT_AAC_AOT_SBR;
             break;
     }
-    aac_dsp_cfg.aac_fmt_flag = aac_bt_cfg->format_flag;
-    aac_dsp_cfg.channel_cfg = aac_bt_cfg->channels;
+    aac_dsp_cfg.aac_cfg.aac_fmt_flag = aac_bt_cfg->format_flag;
+    aac_dsp_cfg.aac_cfg.channel_cfg = aac_bt_cfg->channels;
+    aac_dsp_cfg.frame_ctl.ctl_type = aac_bt_cfg->frame_ctl.ctl_type;
+    aac_dsp_cfg.frame_ctl.ctl_value = aac_bt_cfg->frame_ctl.ctl_value;
     ret = mixer_ctl_set_array(ctl_enc_data, (void *)&aac_dsp_cfg,
                               sizeof(aac_dsp_cfg));
     if (ret != 0) {
@@ -1218,7 +1245,7 @@
     a2dp.enc_sampling_rate = aac_bt_cfg->sampling_rate;
     a2dp.enc_channels = aac_bt_cfg->channels;
     ALOGV("%s: Successfully updated AAC enc format with sampling rate: %d channels:%d",
-           __func__, aac_dsp_cfg.sample_rate, aac_dsp_cfg.channel_cfg);
+           __func__, aac_dsp_cfg.aac_cfg.sample_rate, aac_dsp_cfg.aac_cfg.channel_cfg);
 exit:
     return is_configured;
 }
@@ -1457,6 +1484,15 @@
     return ret;
 }
 
+static void reset_a2dp_config() {
+    reset_a2dp_enc_config_params();
+    reset_a2dp_dec_config_params();
+    a2dp_reset_backend_cfg();
+    if (a2dp.abr_config.is_abr_enabled && a2dp.abr_config.abr_started)
+        stop_abr();
+    a2dp.abr_config.is_abr_enabled = false;
+}
+
 int audio_extn_a2dp_stop_playback()
 {
     int ret = 0;
@@ -1479,12 +1515,8 @@
             ALOGE("%s: stop stream to Bluetooth IPC lib failed", __func__);
         else
             ALOGV("%s: stop steam to Bluetooth IPC lib successful", __func__);
-        reset_a2dp_enc_config_params();
-        reset_a2dp_dec_config_params();
-        a2dp_reset_backend_cfg();
-        if (a2dp.abr_config.is_abr_enabled && a2dp.abr_config.abr_started)
-            stop_abr();
-        a2dp.abr_config.is_abr_enabled = false;
+        if (!a2dp.a2dp_suspended)
+            reset_a2dp_config();
         a2dp.a2dp_started = false;
     }
     ALOGD("%s: Stop A2DP playback total active sessions :%d", __func__,
@@ -1495,13 +1527,14 @@
 int audio_extn_a2dp_set_parameters(struct str_parms *parms, bool *reconfig)
 {
      int ret = 0, val;
+     int status = 0;
      char value[32] = {0};
      struct audio_usecase *uc_info;
      struct listnode *node;
 
      if (a2dp.is_a2dp_offload_enabled == false) {
         ALOGV("%s: No supported encoders identified,ignoring A2DP setparam", __func__);
-        ret = -EINVAL;
+        status = -EINVAL;
         goto param_handled;
      }
 
@@ -1549,8 +1582,7 @@
                         pthread_mutex_lock(&a2dp.adev->lock);
                     }
                 }
-                reset_a2dp_enc_config_params();
-                reset_a2dp_dec_config_params();
+                reset_a2dp_config();
                 if (a2dp.audio_stream_suspend) {
                    a2dp.audio_stream_suspend();
                 }
@@ -1580,12 +1612,23 @@
                 if (a2dp.a2dp_total_active_session_request > 0) {
                     ALOGD("%s: Calling Bluetooth IPC lib start post suspend state", __func__);
                     if (a2dp.audio_stream_start) {
-                        ret =  a2dp.audio_stream_start();
-                        if (ret != 0) {
+                        status =  a2dp.audio_stream_start();
+                        if (status != 0) {
                             ALOGE("%s: Bluetooth controller start failed", __func__);
                             a2dp.a2dp_started = false;
+                        } else {
+                            if (!configure_a2dp_encoder_format()) {
+                                ALOGE("%s: Encoder params configuration failed post suspend", __func__);
+                                a2dp.a2dp_started = false;
+                                status = -ETIMEDOUT;
+                            }
                         }
                     }
+                    if (a2dp.a2dp_started) {
+                        a2dp_set_backend_cfg();
+                        if (a2dp.abr_config.is_abr_enabled)
+                            start_abr();
+                    }
                 }
                 list_for_each(node, &a2dp.adev->usecase_list) {
                     uc_info = node_to_item(node, struct audio_usecase, list);
@@ -1613,7 +1656,7 @@
 
 param_handled:
      ALOGV("%s: end of A2DP setparam", __func__);
-     return ret;
+     return status;
 }
 
 void audio_extn_a2dp_set_handoff_mode(bool is_on)
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index b1c701d..1c28b6b 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -42,6 +42,7 @@
 #define audio_extn_spkr_prot_stop_processing(snd_device)     (0)
 #define audio_extn_spkr_prot_is_enabled() (false)
 #define audio_extn_get_spkr_prot_snd_device(snd_device) (snd_device)
+#define audio_extn_spkr_prot_deinit(adev)       (0)
 #else
 void audio_extn_spkr_prot_init(void *adev);
 int audio_extn_spkr_prot_start_processing(snd_device_t snd_device);
@@ -49,6 +50,8 @@
 bool audio_extn_spkr_prot_is_enabled();
 int audio_extn_get_spkr_prot_snd_device(snd_device_t snd_device);
 void audio_extn_spkr_prot_calib_cancel(void *adev);
+void audio_extn_spkr_prot_deinit(void *adev);
+
 #endif
 
 #ifndef HFP_ENABLED
diff --git a/hal/audio_extn/cirrus_playback.c b/hal/audio_extn/cirrus_playback.c
index 21dbc10..25fe258 100644
--- a/hal/audio_extn/cirrus_playback.c
+++ b/hal/audio_extn/cirrus_playback.c
@@ -155,7 +155,11 @@
 
 static struct cirrus_playback_session handle;
 
+#ifdef CIRRUS_FACTORY_CALIBRATION
 static void *audio_extn_cirrus_calibration_thread();
+#else
+static void *audio_extn_cirrus_config_thread();
+#endif
 
 #ifdef ENABLE_CIRRUS_DETECTION
 static void *audio_extn_cirrus_failure_detect_thread();
@@ -175,11 +179,30 @@
 
     pthread_mutex_init(&handle.fb_prot_mutex, NULL);
 
+#ifdef CIRRUS_FACTORY_CALIBRATION
     (void)pthread_create(&handle.calibration_thread,
                 (const pthread_attr_t *) NULL,
                 audio_extn_cirrus_calibration_thread, &handle);
+#else
+    (void)pthread_create(&handle.calibration_thread,
+                (const pthread_attr_t *) NULL,
+                audio_extn_cirrus_config_thread, &handle);
+#endif
 }
 
+void audio_extn_spkr_prot_deinit(void *adev __unused) {
+    ALOGV("%s: Entry", __func__);
+
+#ifdef ENABLE_CIRRUS_DETECTION
+    pthread_join(handle.failure_detect_thread, NULL);
+#endif
+    pthread_join(handle.calibration_thread, NULL);
+    pthread_mutex_destroy(&handle.fb_prot_mutex);
+
+    ALOGV("%s: Exit", __func__);
+}
+
+#ifdef CIRRUS_FACTORY_CALIBRATION
 static int audio_extn_cirrus_run_calibration() {
     struct audio_device *adev = handle.adev_handle;
     struct crus_sp_ioctl_header header;
@@ -282,7 +305,6 @@
         if (ret < 0)
             goto exit;
 
-#ifdef ENABLED_CIRRUS_WRITE_CAL_FILE
         cal_file = fopen(CRUS_CAL_FILE, "wb");
         if (cal_file == NULL) {
             ALOGE("%s: Cannot create Cirrus SP calibration file (%s)",
@@ -305,7 +327,6 @@
 
         ALOGI("%s: Cirrus calibration file successfully written",
               __func__);
-#endif
     }
 
     header.size = sizeof(header);
@@ -531,6 +552,89 @@
     return NULL;
 }
 
+#else
+static void *audio_extn_cirrus_config_thread(void) {
+    struct audio_device *adev = handle.adev_handle;
+    struct crus_sp_ioctl_header header;
+    struct cirrus_cal_result_t result;
+    struct mixer_ctl *ctl_config = NULL;
+    FILE *cal_file = NULL;
+    int ret = 0, dev_file = -1;
+
+    ALOGI("%s: ++", __func__);
+
+    memset(&result, 0, sizeof(result));
+
+    dev_file = open(CRUS_SP_FILE, O_RDWR | O_NONBLOCK);
+    if (dev_file < 0) {
+        ALOGE("%s: Failed to open Cirrus Playback IOCTL (%d)",
+              __func__, dev_file);
+        ret = -EINVAL;
+        goto exit;
+    }
+
+    cal_file = fopen(CRUS_CAL_FILE, "r");
+    if (cal_file) {
+        ret = fread(&result, sizeof(result), 1, cal_file);
+
+        if (ret != 1) {
+            ALOGE("%s: Cirrus SP calibration file cannot be read , read size: %lu file error: %d",
+                 __func__, (unsigned long)ret * sizeof(result), ferror(cal_file));
+            ret = -EINVAL;
+            goto exit;
+        }
+    }
+
+    header.size = sizeof(header);
+    header.module_id = CRUS_MODULE_ID_TX;
+    header.param_id = 0;
+    header.data_length = sizeof(result);
+    header.data = &result;
+
+    ret = ioctl(dev_file, CRUS_SP_IOCTL_SET_CALIB, &header);
+
+    if (ret < 0) {
+        ALOGE("%s: Cirrus SP calibration IOCTL failure", __func__);
+        goto exit;
+    }
+
+    ctl_config = mixer_get_ctl_by_name(adev->mixer,
+                       CRUS_SP_LOAD_CONF_MIXER);
+    if (!ctl_config) {
+        ALOGE("%s: Could not get ctl for mixer commands", __func__);
+        ret = -EINVAL;
+        goto exit;
+    }
+
+    ret = mixer_ctl_set_value(ctl_config, 0, 2);
+    if (ret < 0) {
+        ALOGE("%s load tx config failed", __func__);
+        goto exit;
+    }
+
+    ret = mixer_ctl_set_value(ctl_config, 0, 1);
+    if (ret < 0) {
+        ALOGE("%s load rx config failed", __func__);
+        goto exit;
+    }
+
+    ret = mixer_ctl_set_value(ctl_config, 0, 0);
+    if (ret < 0) {
+        ALOGE("%s set idle state failed", __func__);
+        goto exit;
+    }
+
+exit:
+    if (dev_file >= 0)
+        close(dev_file);
+    if (cal_file)
+        fclose(cal_file);
+
+    ALOGI("%s: ret: %d --", __func__, ret);
+    return NULL;
+}
+#endif
+
 #ifdef ENABLE_CIRRUS_DETECTION
 void *audio_extn_cirrus_failure_detect_thread() {
     struct audio_device *adev = handle.adev_handle;
diff --git a/hal/audio_extn/maxxaudio.c b/hal/audio_extn/maxxaudio.c
index 9007da7..fc65332 100644
--- a/hal/audio_extn/maxxaudio.c
+++ b/hal/audio_extn/maxxaudio.c
@@ -37,7 +37,7 @@
 #define PRESET_PATH "/vendor/etc"
 #define MPS_BASE_STRING "default"
 #define USER_PRESET_PATH ""
-#define CONFIG_PATH "/vendor/etc/maxx_conf.ini"
+#define CONFIG_BASE_STRING "maxx_conf"
 #define CAL_PRESIST_STR "cal_persist"
 #define CAL_SAMPLERATE_STR "cal_samplerate"
 
@@ -344,6 +344,7 @@
     int ret = 0;
     char lib_path[128] = {0};
     char mps_path[128] = {0};
+    char cnf_path[128] = {0};
     struct snd_card_split *snd_split_handle = NULL;
     snd_split_handle = audio_extn_get_snd_card_split();
 
@@ -427,8 +428,17 @@
                  PRESET_PATH, MPS_BASE_STRING, snd_split_handle->form_factor);
     }
 
+    /* get config files */
+    if (snd_split_handle == NULL) {
+        snprintf(cnf_path, sizeof(cnf_path), "%s/%s.ini",
+                 PRESET_PATH, CONFIG_BASE_STRING);
+    } else {
+        snprintf(cnf_path, sizeof(cnf_path), "%s/%s_%s.ini",
+                 PRESET_PATH, CONFIG_BASE_STRING, snd_split_handle->form_factor);
+    }
+
     /* check file */
-    if (access(mps_path, F_OK) < 0) {
+    if (access(mps_path, R_OK) < 0) {
         ALOGW("%s: file %s isn't existed.", __func__, mps_path);
         goto error;
     } else
@@ -440,16 +450,18 @@
         goto error;
     }
     */
-    if (access(CONFIG_PATH, F_OK) < 0) {
-        ALOGW("%s: file %s isn't existed.", __func__, CONFIG_PATH);
+
+    if (access(cnf_path, R_OK) < 0) {
+        ALOGW("%s: file %s isn't existed.", __func__, cnf_path);
         goto error;
-    }
+    } else
+        ALOGD("%s: Loading ini file: %s", __func__, cnf_path);
 
     /* init ma parameter */
     if (my_data->ma_param_init(&g_ma_audio_cal_handle,
                                mps_path,
                                USER_PRESET_PATH, /* unused */
-                               CONFIG_PATH,
+                               cnf_path,
                                &set_audio_cal)) {
         if (!g_ma_audio_cal_handle) {
             ALOGE("%s: ma parameters initialize failed", __func__);
diff --git a/hal/audio_extn/sndmonitor.c b/hal/audio_extn/sndmonitor.c
index 6e06d03..2e8fd43 100644
--- a/hal/audio_extn/sndmonitor.c
+++ b/hal/audio_extn/sndmonitor.c
@@ -51,6 +51,11 @@
 #define MAX_CPE_SLEEP_RETRY 2
 #define CPE_SLEEP_WAIT 100
 
+#define SPLI_STATE_PATH "/proc/wcd-spi-ac/svc-state"
+#define SLPI_MAGIC_NUM 0x3000
+#define MAX_SLPI_SLEEP_RETRY 2
+#define SLPI_SLEEP_WAIT_MS 100
+
 #define MAX_SLEEP_RETRY 100
 #define AUDIO_INIT_SLEEP_WAIT 100 /* 100 ms */
 
@@ -245,6 +250,31 @@
     if (line)
         free(line);
     fclose(fp);
+
+    /* Add fd to query for SLPI status */
+    if (access(SPLI_STATE_PATH, R_OK) < 0) {
+        ALOGV("access to %s failed: %s", SPLI_STATE_PATH, strerror(errno));
+    } else {
+        tries = MAX_SLPI_SLEEP_RETRY;
+        ALOGV("Open %s", SPLI_STATE_PATH);
+        while (tries--) {
+            if ((fd = open(SPLI_STATE_PATH, O_RDONLY)) < 0) {
+                ALOGW("Open %s failed %s, retry", SPLI_STATE_PATH,
+                      strerror(errno));
+                usleep(SLPI_SLEEP_WAIT_MS * 1000);
+                continue;
+            }
+            break;
+        }
+        if (fd >= 0) {
+            ret = add_new_sndcard(SLPI_MAGIC_NUM, fd);
+            if (ret != 0)
+                close(fd);
+            else
+                num_cards++;
+        }
+    }
+
     ALOGV("sndmonitor registerer num_cards %d", num_cards);
     sndmonitor.num_cards = num_cards;
     return num_cards ? 0 : -1;
@@ -383,7 +413,6 @@
 
     ALOGV("card num %d, new state %s", s->card, rd_buf);
 
-    bool is_cpe = (s->card >= CPE_MAGIC_NUM);
     if (strstr(rd_buf, "OFFLINE"))
         status = CARD_STATUS_OFFLINE;
     else if (strstr(rd_buf, "ONLINE"))
@@ -404,11 +433,18 @@
         return -1;
 
     char val[32] = {0};
-    // cpe actual card num is (card - MAGIC_NUM). so subtract accordingly
-    snprintf(val, sizeof(val), "%d,%s", s->card - (is_cpe ? CPE_MAGIC_NUM : 0),
+    bool is_cpe = ((s->card >= CPE_MAGIC_NUM) && (s->card < SLPI_MAGIC_NUM));
+    bool is_slpi = (s->card == SLPI_MAGIC_NUM);
+    /*
+     * cpe actual card num is (card - CPE_MAGIC_NUM), so subtract accordingly.
+     * SLPI actual fd num is (card - SLPI_MAGIC_NUM), so subtract accordingly.
+     */
+    snprintf(val, sizeof(val), "%d,%s",
+        s->card - (is_cpe ? CPE_MAGIC_NUM : (is_slpi ? SLPI_MAGIC_NUM : 0)),
                  status == CARD_STATUS_ONLINE ? "ONLINE" : "OFFLINE");
 
-    if (str_parms_add_str(params, is_cpe ? "CPE_STATUS" : "SND_CARD_STATUS",
+    if (str_parms_add_str(params,
+            is_cpe ? "CPE_STATUS" : (is_slpi ? "SLPI_STATUS" : "SND_CARD_STATUS"),
                           val) < 0)
         return -1;
 
diff --git a/hal/audio_extn/soundtrigger.c b/hal/audio_extn/soundtrigger.c
index c11e747..063a7ba 100644
--- a/hal/audio_extn/soundtrigger.c
+++ b/hal/audio_extn/soundtrigger.c
@@ -78,7 +78,9 @@
     SND_CARD_STATUS_OFFLINE,
     SND_CARD_STATUS_ONLINE,
     CPE_STATUS_OFFLINE,
-    CPE_STATUS_ONLINE
+    CPE_STATUS_ONLINE,
+    SLPI_STATUS_OFFLINE,
+    SLPI_STATUS_ONLINE,
 } ssr_event_status_t;
 
 struct sound_trigger_session_info {
@@ -362,9 +364,6 @@
     if (!st_dev)
        return;
 
-    if (st_dev->sthal_prop_api_version >= STHAL_PROP_API_VERSION_1_0)
-        return;
-
     if (snd_device >= SND_DEVICE_OUT_BEGIN &&
         snd_device < SND_DEVICE_OUT_END) {
         device_type = PCM_PLAYBACK;
@@ -484,6 +483,19 @@
         event.u.value = val;
         st_dev->st_callback(AUDIO_EVENT_NUM_ST_SESSIONS, &event);
     }
+
+    ret = str_parms_get_str(params, "SLPI_STATUS", value, sizeof(value));
+    if (ret > 0) {
+        if (strstr(value, "OFFLINE")) {
+            event.u.status = SLPI_STATUS_OFFLINE;
+            st_dev->st_callback(AUDIO_EVENT_SSR, &event);
+        } else if (strstr(value, "ONLINE")) {
+            event.u.status = SLPI_STATUS_ONLINE;
+            st_dev->st_callback(AUDIO_EVENT_SSR, &event);
+        } else {
+            ALOGE("%s: unknown SLPI status", __func__);
+        }
+    }
 }
 
 int audio_extn_sound_trigger_init(struct audio_device *adev)
diff --git a/hal/audio_extn/spkr_protection.c b/hal/audio_extn/spkr_protection.c
index 8c09a29..dba69a0 100644
--- a/hal/audio_extn/spkr_protection.c
+++ b/hal/audio_extn/spkr_protection.c
@@ -780,6 +780,11 @@
     }
 }
 
+void audio_extn_spkr_prot_deinit(void *adev __unused)
+{
+    ALOGV("%s: Entry", __func__);
+}
+
 int audio_extn_get_spkr_prot_snd_device(snd_device_t snd_device)
 {
     if (!handle.spkr_prot_enable)
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index 1751a30..73de0ab 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -345,6 +345,8 @@
     int sample_rate;
     int app_type;
     int acdb_dev_id;
+    int new_snd_device[2] = {0};
+    int i = 0, num_devices = 1;
     size_t app_type_cfg[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
     char mixer_ctl_name[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
     int pcm_device_id;
@@ -379,18 +381,33 @@
         return -1;
     }
 
-    acdb_dev_id = derive_acdb_dev_id(adev, usecase);
-    if (acdb_dev_id <= 0) {
-        ALOGE("%s: Couldn't get the acdb dev id", __func__);
-        return -1;
-    }
+    if (usecase->type == PCM_PLAYBACK) {
+        if (platform_can_split_snd_device(usecase->out_snd_device,
+                                          &num_devices, new_snd_device) < 0)
+            new_snd_device[0] = usecase->out_snd_device;
+
+    } else if (usecase->type == PCM_CAPTURE)
+        new_snd_device[0] = usecase->in_snd_device;
 
     pcm_device_id = platform_get_pcm_device_id(usecase->id, usecase->type);
-    set_stream_app_type_mixer_ctrl(adev, pcm_device_id, app_type, acdb_dev_id,
-                                   sample_rate,
-                                   usecase->type,
-                                   usecase->type == PCM_PLAYBACK ? usecase->out_snd_device :
-                                                                   usecase->in_snd_device);
+
+    for (i = 0; i < num_devices; i++) {
+        acdb_dev_id = platform_get_snd_device_acdb_id(new_snd_device[i]);
+
+        if (acdb_dev_id < 0) {
+            ALOGE("%s: Could not find acdb id for device(%d)",
+                  __func__, new_snd_device[i]);
+            return -EINVAL;
+        }
+        ALOGV("%s: sending app type for snd_device(%d) acdb_id(%d) i %d",
+              __func__, new_snd_device[i], acdb_dev_id, i);
+
+        set_stream_app_type_mixer_ctrl(adev, pcm_device_id, app_type, acdb_dev_id,
+                                       sample_rate,
+                                       usecase->type,
+                                       new_snd_device[i]);
+    }
+
     return 0;
 }
 
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 0a12cff..fb15db5 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -1954,6 +1954,8 @@
     int i, ret = 0;
     struct audio_usecase *uc_info;
     struct audio_device *adev = out->dev;
+    bool has_voip_usecase =
+        get_usecase_from_list(adev, USECASE_AUDIO_PLAYBACK_VOIP) != NULL;
 
     ALOGV("%s: enter: usecase(%d: %s)", __func__,
           out->usecase, use_case_table[out->usecase]);
@@ -1987,15 +1989,7 @@
     /* Must be called after removing the usecase from list */
     if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
         check_and_set_hdmi_channels(adev, DEFAULT_HDMI_OUT_CHANNELS);
-    else if (out->devices & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
-        struct listnode *node;
-        struct audio_usecase *usecase;
-        list_for_each(node, &adev->usecase_list) {
-            usecase = node_to_item(node, struct audio_usecase, list);
-            if (usecase->devices & AUDIO_DEVICE_OUT_SPEAKER)
-                select_devices(adev, usecase->id);
-        }
-    } else if (audio_is_usb_out_device(out->devices & AUDIO_DEVICE_OUT_ALL_USB)) {
+    else if (audio_is_usb_out_device(out->devices & AUDIO_DEVICE_OUT_ALL_USB)) {
         ret = check_and_set_usb_service_interval(adev, uc_info, false /*min*/);
         if (ret == 0) {
             /* default service interval was successfully updated,
@@ -2005,6 +1999,22 @@
         ret = 0;
     }
 
+    if (has_voip_usecase ||
+            out->devices & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
+        struct listnode *node;
+        struct audio_usecase *usecase;
+        list_for_each(node, &adev->usecase_list) {
+            usecase = node_to_item(node, struct audio_usecase, list);
+            if (usecase->type == PCM_CAPTURE || usecase == uc_info)
+                continue;
+
+            ALOGD("%s: select_devices at usecase(%d: %s) after removing the usecase(%d: %s)",
+                __func__, usecase->id, use_case_table[usecase->id],
+                out->usecase, use_case_table[out->usecase]);
+            select_devices(adev, usecase->id);
+        }
+    }
+
     free(uc_info);
     ALOGV("%s: exit: status(%d)", __func__, ret);
     return ret;
@@ -2105,8 +2115,13 @@
         if (out->offload_callback)
             compress_nonblock(out->compr, out->non_blocking);
 
-        if (adev->visualizer_start_output != NULL)
-            adev->visualizer_start_output(out->handle, out->pcm_device_id);
+        if (adev->visualizer_start_output != NULL) {
+            int capture_device_id =
+                platform_get_pcm_device_id(USECASE_AUDIO_RECORD_AFE_PROXY,
+                                           PCM_CAPTURE);
+            adev->visualizer_start_output(out->handle, out->pcm_device_id,
+                                          adev->snd_card, capture_device_id);
+        }
         if (adev->offload_effects_start_output != NULL)
             adev->offload_effects_start_output(out->handle, out->pcm_device_id);
     } else if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
@@ -5608,7 +5623,7 @@
     } else {
         ALOGV("%s: DLOPEN successful for %s", __func__, VISUALIZER_LIBRARY_PATH);
         adev->visualizer_start_output =
-                    (int (*)(audio_io_handle_t, int))dlsym(adev->visualizer_lib,
+                    (int (*)(audio_io_handle_t, int, int, int))dlsym(adev->visualizer_lib,
                                                     "visualizer_hal_start_output");
         adev->visualizer_stop_output =
                     (int (*)(audio_io_handle_t, int))dlsym(adev->visualizer_lib,
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 921c249..6379844 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -337,7 +337,7 @@
     card_status_t card_status;
 
     void *visualizer_lib;
-    int (*visualizer_start_output)(audio_io_handle_t, int);
+    int (*visualizer_start_output)(audio_io_handle_t, int, int, int);
     int (*visualizer_stop_output)(audio_io_handle_t, int);
 
     /* The pcm_params use_case_table is loaded by adev_verify_devices() upon
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index d92243e..8edd999 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -1205,6 +1205,8 @@
     struct operator_specific_device *device_item;
     struct listnode *node;
 
+    audio_extn_spkr_prot_deinit(my_data->adev);
+
     hw_info_deinit(my_data->hw_info);
 
     for (dev = 0; dev < SND_DEVICE_MAX; dev++) {
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 429291c..820b47f 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -1834,6 +1834,8 @@
     struct platform_data *my_data = (struct platform_data *)platform;
     close_csd_client(my_data->csd);
 
+    audio_extn_spkr_prot_deinit(my_data->adev);
+
     hw_info_deinit(my_data->hw_info);
 
     for (dev = 0; dev < SND_DEVICE_MAX; dev++) {
diff --git a/visualizer/Android.mk b/visualizer/Android.mk
index 7d7cfe9..13a45c7 100644
--- a/visualizer/Android.mk
+++ b/visualizer/Android.mk
@@ -27,14 +27,6 @@
 	libdl \
 	libtinyalsa
 
-# HACK to set the right record proxy effect card number.
-# It should be retrieved from the primary hal USECASE_AUDIO_RECORD_AFE_PROXY.
-ifneq ($(filter msm8998,$(TARGET_BOARD_PLATFORM)),)
-  LOCAL_CFLAGS := -DCAPTURE_DEVICE=7
-else
-  LOCAL_CFLAGS := -DCAPTURE_DEVICE=8
-endif
-
 LOCAL_CFLAGS += \
     -Wall \
     -Werror \
diff --git a/visualizer/offload_visualizer.c b/visualizer/offload_visualizer.c
index 860dfce..74beac7 100644
--- a/visualizer/offload_visualizer.c
+++ b/visualizer/offload_visualizer.c
@@ -145,6 +145,12 @@
         NULL,
 };
 
+struct pcm_capture_config {
+    int snd_card_num;
+    int capture_device_id;
+};
+
+struct pcm_capture_config capture_config;
 
 pthread_once_t once = PTHREAD_ONCE_INIT;
 int init_status;
@@ -172,16 +178,12 @@
 /* 0 if the capture thread was created successfully */
 int thread_status;
 
-
 #define DSP_OUTPUT_LATENCY_MS 0 /* Fudge factor for latency after capture point in audio DSP */
 
 /* Retry for delay for mixer open */
 #define RETRY_NUMBER 10
 #define RETRY_US 500000
 
-#define MIXER_CARD 0
-#define SOUND_CARD 0
-
 /* Proxy port supports only MMAP read and those fixed parameters*/
 #define AUDIO_CAPTURE_CHANNEL_COUNT 2
 #define AUDIO_CAPTURE_SMP_RATE 48000
@@ -338,10 +340,10 @@
 
     pthread_mutex_lock(&lock);
 
-    mixer = mixer_open(MIXER_CARD);
+    mixer = mixer_open(capture_config.snd_card_num);
     while (mixer == NULL && retry_num < RETRY_NUMBER) {
         usleep(RETRY_US);
-        mixer = mixer_open(MIXER_CARD);
+        mixer = mixer_open(capture_config.snd_card_num);
         retry_num++;
     }
     if (mixer == NULL) {
@@ -357,7 +359,8 @@
             if (!capture_enabled) {
                 ret = configure_proxy_capture(mixer, 1);
                 if (ret == 0) {
-                    pcm = pcm_open(SOUND_CARD, CAPTURE_DEVICE,
+                    pcm = pcm_open(capture_config.snd_card_num,
+                                   capture_config.capture_device_id,
                                    PCM_IN|PCM_MMAP|PCM_NOIRQ, &pcm_config_capture);
                     if (pcm && !pcm_is_ready(pcm)) {
                         ALOGW("%s: %s", __func__, pcm_get_error(pcm));
@@ -427,7 +430,8 @@
  */
 
 __attribute__ ((visibility ("default")))
-int visualizer_hal_start_output(audio_io_handle_t output, int pcm_id) {
+int visualizer_hal_start_output(audio_io_handle_t output, int pcm_id,
+                                int card_number, int pcm_capture_id) {
     int ret = 0;
     struct listnode *node;
 
@@ -444,6 +448,11 @@
         goto exit;
     }
 
+    ALOGV("%s card number %d pcm_capture_id %d",
+          __func__, card_number, pcm_capture_id);
+    capture_config.snd_card_num = card_number;
+    capture_config.capture_device_id = pcm_capture_id;
+
     output_context_t *out_ctxt = (output_context_t *)malloc(sizeof(output_context_t));
     out_ctxt->handle = output;
     list_init(&out_ctxt->effects_list);