Merge "For msm8996, add dep on sound_trigger.primary_headers"
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 4af1e9c..7a019ba 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -44,6 +44,7 @@
 #include <hardware/audio_effect.h>
 #include <hardware/audio_alsaops.h>
 #include <system/thread_defs.h>
+#include <tinyalsa/asoundlib.h>
 #include <audio_effects/effect_aec.h>
 #include <audio_effects/effect_ns.h>
 #include "audio_hw.h"
@@ -85,7 +86,9 @@
 
 
 #define MMAP_PERIOD_SIZE (DEFAULT_OUTPUT_SAMPLING_RATE/1000)
-#define MMAP_PERIOD_COUNT 512
+#define MMAP_PERIOD_COUNT_MIN 32
+#define MMAP_PERIOD_COUNT_MAX 512
+#define MMAP_PERIOD_COUNT_DEFAULT (MMAP_PERIOD_COUNT_MAX)
 
 
 /* This constant enables extended precision handling.
@@ -144,7 +147,7 @@
     .channels = DEFAULT_CHANNEL_COUNT,
     .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
     .period_size = MMAP_PERIOD_SIZE,
-    .period_count = MMAP_PERIOD_COUNT,
+    .period_count = MMAP_PERIOD_COUNT_DEFAULT,
     .format = PCM_FORMAT_S16_LE,
     .start_threshold = MMAP_PERIOD_SIZE*8,
     .stop_threshold = INT32_MAX,
@@ -178,7 +181,7 @@
     .channels = DEFAULT_CHANNEL_COUNT,
     .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
     .period_size = MMAP_PERIOD_SIZE,
-    .period_count = MMAP_PERIOD_COUNT,
+    .period_count = MMAP_PERIOD_COUNT_DEFAULT,
     .format = PCM_FORMAT_S16_LE,
     .start_threshold = 0,
     .stop_threshold = INT_MAX,
@@ -1313,14 +1316,10 @@
     select_devices(adev, in->usecase);
 
     if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
-        if (!pcm_is_ready(in->pcm)) {
+        if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
             ALOGE("%s: pcm stream not ready", __func__);
             goto error_open;
         }
-        ret = pcm_prepare(in->pcm);
-        if (ret < 0) {
-            ALOGE("%s: MMAP pcm_prepare failed ret %d", __func__, ret);
-            goto error_open;        }
         ret = pcm_start(in->pcm);
         if (ret < 0) {
             ALOGE("%s: MMAP pcm_start failed ret %d", __func__, ret);
@@ -1738,14 +1737,10 @@
         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) {
-        if (!pcm_is_ready(out->pcm)) {
+        if (out->pcm == NULL || !pcm_is_ready(out->pcm)) {
             ALOGE("%s: pcm stream not ready", __func__);
             goto error_open;
         }
-        ret = pcm_prepare(out->pcm);
-        if (ret < 0) {
-            ALOGE("%s: MMAP pcm_prepare failed ret %d", __func__, ret);
-            goto error_open;        }
         ret = pcm_start(out->pcm);
         if (ret < 0) {
             ALOGE("%s: MMAP pcm_start failed ret %d", __func__, ret);
@@ -1921,6 +1916,7 @@
 {
     struct stream_out *out = (struct stream_out *)stream;
     struct audio_device *adev = out->dev;
+    bool do_stop = true;
 
     ALOGV("%s: enter: usecase(%d: %s)", __func__,
           out->usecase, use_case_table[out->usecase]);
@@ -1937,6 +1933,7 @@
                 out->pcm = NULL;
             }
             if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
+                do_stop = out->playback_started;
                 out->playback_started = false;
             }
         } else {
@@ -1948,7 +1945,9 @@
                 out->compr = NULL;
             }
         }
-        stop_output_stream(out);
+        if (do_stop) {
+            stop_output_stream(out);
+        }
         pthread_mutex_unlock(&adev->lock);
     }
     pthread_mutex_unlock(&out->lock);
@@ -2575,9 +2574,7 @@
             out->playback_started && out->pcm != NULL) {
         pcm_stop(out->pcm);
         ret = stop_output_stream(out);
-        if (ret == 0) {
-            out->playback_started = false;
-        }
+        out->playback_started = false;
     }
     pthread_mutex_unlock(&adev->lock);
     return ret;
@@ -2602,6 +2599,26 @@
     return ret;
 }
 
+/*
+ * Modify config->period_count based on min_size_frames
+ */
+static void adjust_mmap_period_count(struct pcm_config *config, int32_t min_size_frames)
+{
+    int periodCountRequested = (min_size_frames + config->period_size - 1)
+                               / config->period_size;
+    int periodCount = MMAP_PERIOD_COUNT_MIN;
+
+    ALOGV("%s original config.period_size = %d config.period_count = %d",
+          __func__, config->period_size, config->period_count);
+
+    while (periodCount < periodCountRequested && (periodCount * 2) < MMAP_PERIOD_COUNT_MAX) {
+        periodCount *= 2;
+    }
+    config->period_count = periodCount;
+
+    ALOGV("%s requested config.period_count = %d", __func__, config->period_count);
+}
+
 static int out_create_mmap_buffer(const struct audio_stream_out *stream,
                                   int32_t min_size_frames,
                                   struct audio_mmap_buffer_info *info)
@@ -2617,10 +2634,12 @@
     pthread_mutex_lock(&adev->lock);
 
     if (info == NULL || min_size_frames == 0) {
+        ALOGE("%s: info = %p, min_size_frames = %d", __func__, info, min_size_frames);
         ret = -EINVAL;
         goto exit;
     }
     if (out->usecase != USECASE_AUDIO_PLAYBACK_MMAP || !out->standby) {
+        ALOGE("%s: usecase = %d, standby = %d", __func__, out->usecase, out->standby);
         ret = -ENOSYS;
         goto exit;
     }
@@ -2631,6 +2650,9 @@
         ret = -EINVAL;
         goto exit;
     }
+
+    adjust_mmap_period_count(&out->config, min_size_frames);
+
     ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
           __func__, adev->snd_card, out->pcm_device_id, out->config.channels);
     out->pcm = pcm_open(adev->snd_card, out->pcm_device_id,
@@ -2657,6 +2679,8 @@
         step = "commit";
         goto exit;
     }
+
+    out->standby = false;
     ret = 0;
 
     ALOGV("%s: got mmap buffer address %p info->buffer_size_frames %d",
@@ -2664,8 +2688,10 @@
 
 exit:
     if (ret != 0) {
-        ALOGE("%s: %s %s", __func__, step, pcm_get_error(out->pcm));
-        if (out->pcm != NULL) {
+        if (out->pcm == NULL) {
+            ALOGE("%s: %s - %d", __func__, step, ret);
+        } else {
+            ALOGE("%s: %s %s", __func__, step, pcm_get_error(out->pcm));
             pcm_close(out->pcm);
             out->pcm = NULL;
         }
@@ -2744,6 +2770,8 @@
     struct stream_in *in = (struct stream_in *)stream;
     struct audio_device *adev = in->dev;
     int status = 0;
+    bool do_stop = true;
+
     ALOGV("%s: enter", __func__);
 
     lock_input_stream(in);
@@ -2761,6 +2789,7 @@
         pthread_mutex_lock(&adev->lock);
         in->standby = true;
         if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
+            do_stop = in->capture_started;
             in->capture_started = false;
         }
         if (in->pcm) {
@@ -2769,7 +2798,9 @@
         }
         adev->enable_voicerx = false;
         platform_set_echo_reference(adev, false, AUDIO_DEVICE_NONE );
-        status = stop_input_stream(in);
+        if (do_stop) {
+            status = stop_input_stream(in);
+        }
         pthread_mutex_unlock(&adev->lock);
     }
     pthread_mutex_unlock(&in->lock);
@@ -3074,9 +3105,7 @@
             in->capture_started && in->pcm != NULL) {
         pcm_stop(in->pcm);
         ret = stop_input_stream(in);
-        if (ret == 0) {
-            in->capture_started = false;
-        }
+        in->capture_started = false;
     }
     pthread_mutex_unlock(&adev->lock);
     return ret;
@@ -3116,12 +3145,14 @@
 
     pthread_mutex_lock(&adev->lock);
     ALOGV("%s in %p", __func__, in);
+
     if (info == NULL || min_size_frames == 0) {
-        ALOGV("%s invalid argument info %p min_size_frames %d", __func__, info, min_size_frames);
+        ALOGE("%s invalid argument info %p min_size_frames %d", __func__, info, min_size_frames);
         ret = -EINVAL;
         goto exit;
     }
     if (in->usecase != USECASE_AUDIO_RECORD_MMAP || !in->standby) {
+        ALOGE("%s: usecase = %d, standby = %d", __func__, in->usecase, in->standby);
         ALOGV("%s in %p", __func__, in);
         ret = -ENOSYS;
         goto exit;
@@ -3133,6 +3164,9 @@
         ret = -EINVAL;
         goto exit;
     }
+
+    adjust_mmap_period_count(&in->config, min_size_frames);
+
     ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
           __func__, adev->snd_card, in->pcm_device_id, in->config.channels);
     in->pcm = pcm_open(adev->snd_card, in->pcm_device_id,
@@ -3161,14 +3195,18 @@
         goto exit;
     }
 
+    in->standby = false;
+    ret = 0;
+
     ALOGV("%s: got mmap buffer address %p info->buffer_size_frames %d",
           __func__, info->shared_memory_address, info->buffer_size_frames);
-    ret = 0;
 
 exit:
     if (ret != 0) {
-        ALOGE("%s: %s %s", __func__, step, pcm_get_error(in->pcm));
-        if (in->pcm != NULL) {
+        if (in->pcm == NULL) {
+            ALOGE("%s: %s - %d", __func__, step, ret);
+        } else {
+            ALOGE("%s: %s %s", __func__, step, pcm_get_error(in->pcm));
             pcm_close(in->pcm);
             in->pcm = NULL;
         }
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 3308940..a77be16 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -28,8 +28,8 @@
 #include "audio_extn.h"
 #include <linux/msm_audio.h>
 
-#define MIXER_XML_DEFAULT_PATH "/system/etc/mixer_paths.xml"
-#define MIXER_XML_BASE_STRING "/system/etc/mixer_paths"
+#define MIXER_XML_DEFAULT_PATH "mixer_paths.xml"
+#define MIXER_XML_BASE_STRING "mixer_paths"
 #define TOMTOM_8226_SND_CARD_NAME "msm8226-tomtom-snd-card"
 #define TOMTOM_MIXER_FILE_SUFFIX "wcd9330"
 
@@ -1083,6 +1083,28 @@
             strdup("USB_AUDIO_RX Channels");
 }
 
+// Treblized config files will be located in /odm/etc or /vendor/etc.
+static const char *kConfigLocationList[] =
+        {"/odm/etc", "/vendor/etc", "/system/etc"};
+static const int kConfigLocationListSize =
+        (sizeof(kConfigLocationList) / sizeof(kConfigLocationList[0]));
+
+bool resolveConfigFile(char file_name[MIXER_PATH_MAX_LENGTH]) {
+    char full_config_path[MIXER_PATH_MAX_LENGTH];
+    for (int i = 0; i < kConfigLocationListSize; i++) {
+        snprintf(full_config_path,
+                 MIXER_PATH_MAX_LENGTH,
+                 "%s/%s",
+                 kConfigLocationList[i],
+                 file_name);
+        if (F_OK == access(full_config_path, 0)) {
+            strcpy(file_name, full_config_path);
+            return true;
+        }
+    }
+    return false;
+}
+
 void *platform_init(struct audio_device *adev)
 {
     char value[PROPERTY_VALUE_MAX];
@@ -1166,15 +1188,15 @@
             snprintf(mixer_xml_file, sizeof(mixer_xml_file), "%s_%s_%s.xml",
                              MIXER_XML_BASE_STRING, snd_split_handle->snd_card,
                              snd_split_handle->form_factor);
-
-            if (F_OK != access(mixer_xml_file, 0)) {
+            if (!resolveConfigFile(mixer_xml_file)) {
                 memset(mixer_xml_file, 0, sizeof(mixer_xml_file));
                 snprintf(mixer_xml_file, sizeof(mixer_xml_file), "%s_%s.xml",
                              MIXER_XML_BASE_STRING, snd_split_handle->snd_card);
 
-                if (F_OK != access(mixer_xml_file, 0)) {
+                if (!resolveConfigFile(mixer_xml_file)) {
                     memset(mixer_xml_file, 0, sizeof(mixer_xml_file));
                     strlcpy(mixer_xml_file, MIXER_XML_DEFAULT_PATH, MIXER_PATH_MAX_LENGTH);
+                    resolveConfigFile(mixer_xml_file);
                 }
             }
 
@@ -1182,14 +1204,15 @@
                              PLATFORM_INFO_XML_BASE_STRING, snd_split_handle->snd_card,
                              snd_split_handle->form_factor);
 
-            if (F_OK != access(platform_info_file, 0)) {
+            if (!resolveConfigFile(platform_info_file)) {
                 memset(platform_info_file, 0, sizeof(platform_info_file));
                 snprintf(platform_info_file, sizeof(platform_info_file), "%s_%s.xml",
                              PLATFORM_INFO_XML_BASE_STRING, snd_split_handle->snd_card);
 
-                if (F_OK != access(platform_info_file, 0)) {
+                if (!resolveConfigFile(platform_info_file)) {
                     memset(platform_info_file, 0, sizeof(platform_info_file));
                     strlcpy(platform_info_file, PLATFORM_INFO_XML_PATH, MIXER_PATH_MAX_LENGTH);
+                    resolveConfigFile(platform_info_file);
                 }
             }
         }
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index cc75384..d892813 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -364,6 +364,6 @@
     char     *channels_mixer_ctl;
 } codec_backend_cfg_t;
 
-#define PLATFORM_INFO_XML_PATH          "/system/etc/audio_platform_info.xml"
-#define PLATFORM_INFO_XML_BASE_STRING   "/system/etc/audio_platform_info"
+#define PLATFORM_INFO_XML_PATH          "audio_platform_info.xml"
+#define PLATFORM_INFO_XML_BASE_STRING   "audio_platform_info"
 #endif // QCOM_AUDIO_PLATFORM_H