hal: Support config selection for playback on speaker

Support bit width selection for playback on speakers based on
platform info.

Change-Id: I8dd2cc7049186e7468615a43db550d7d580a81d1
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index 6818161..8bd98a0 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -436,6 +436,9 @@
 
     if ((24 == bit_width) &&
         (devices & AUDIO_DEVICE_OUT_SPEAKER)) {
+        int32_t bw = platform_get_snd_device_bit_width(SND_DEVICE_OUT_SPEAKER);
+        if (-ENOSYS != bw)
+            bit_width = (uint32_t)bw;
         sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
         ALOGI("%s Allowing 24-bit playback on speaker ONLY at default sampling rate", __func__);
     }
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 7b945cf..b4476f5 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -1035,6 +1035,18 @@
     return acdb_device_table[snd_device];
 }
 
+int platform_set_snd_device_bit_width(snd_device_t snd_device, unsigned int bit_width)
+{
+    ALOGE("%s: Not implemented", __func__);
+    return -ENOSYS;
+}
+
+int platform_get_snd_device_bit_width(snd_device_t snd_device)
+{
+    ALOGE("%s: Not implemented", __func__);
+    return -ENOSYS;
+}
+
 int platform_send_audio_calibration(void *platform, snd_device_t snd_device,
                                     int app_type, int sample_rate)
 {
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index e2c30f4..87ce2cd 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -421,6 +421,18 @@
     return -ENOSYS;
 }
 
+int platform_set_snd_device_bit_width(snd_device_t snd_device, unsigned int bit_width)
+{
+    ALOGE("%s: Not implemented", __func__);
+    return -ENOSYS;
+}
+
+int platform_get_snd_device_bit_width(snd_device_t snd_device)
+{
+    ALOGE("%s: Not implemented", __func__);
+    return -ENOSYS;
+}
+
 int platform_switch_voice_call_enable_device_config(void *platform __unused,
                                                     snd_device_t out_snd_device __unused,
                                                     snd_device_t in_snd_device __unused)
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index ff1f9b8..66c7731 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -298,6 +298,9 @@
     [SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE] = "speaker-dmic-broadside",
 };
 
+// Platform specific backend bit width table
+static int backend_bit_width_table[SND_DEVICE_MAX] = {0};
+
 /* ACDB IDs (audio DSP path configuration IDs) for each sound device */
 static int acdb_device_table[SND_DEVICE_MAX] = {
     [SND_DEVICE_NONE] = -1,
@@ -693,6 +696,9 @@
     for (dev = 0; dev < SND_DEVICE_MAX; dev++) {
         backend_table[dev] = NULL;
     }
+    for (dev = 0; dev < SND_DEVICE_MAX; dev++) {
+        backend_bit_width_table[dev] = 16;
+    }
 
     // TBD - do these go to the platform-info.xml file.
     // will help in avoiding strdups here
@@ -1164,6 +1170,31 @@
     return acdb_device_table[snd_device];
 }
 
+int platform_set_snd_device_bit_width(snd_device_t snd_device, unsigned int bit_width)
+{
+    int ret = 0;
+
+    if ((snd_device < SND_DEVICE_MIN) || (snd_device >= SND_DEVICE_MAX)) {
+        ALOGE("%s: Invalid snd_device = %d",
+            __func__, snd_device);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    backend_bit_width_table[snd_device] = bit_width;
+done:
+    return ret;
+}
+
+int platform_get_snd_device_bit_width(snd_device_t snd_device)
+{
+    if ((snd_device < SND_DEVICE_MIN) || (snd_device >= SND_DEVICE_MAX)) {
+        ALOGE("%s: Invalid snd_device = %d", __func__, snd_device);
+        return DEFAULT_OUTPUT_SAMPLING_RATE;
+    }
+    return backend_bit_width_table[snd_device];
+}
+
 int platform_send_audio_calibration(void *platform, snd_device_t snd_device,
                                     int app_type, int sample_rate)
 {
@@ -2559,11 +2590,15 @@
         }
     }
 
-    // 24 bit playback on speakers and all 16 bit playbacks is allowed through
-    // 16 bit/48 khz backend only
-    if ((16 == bit_width) ||
-        ((24 == bit_width) &&
-         (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER))) {
+    // 16 bit playback on speakers is allowed through 48 khz backend only
+    if (16 == bit_width) {
+        sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+    }
+    // 24 bit playback on speakers is allowed through 48 khz backend only
+    // bit width re-configured based on platform info
+    if ((24 == bit_width) &&
+        (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER)) {
+        bit_width = (uint32_t)platform_get_snd_device_bit_width(SND_DEVICE_OUT_SPEAKER);
         sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
     }
     // Force routing if the expected bitwdith or samplerate
diff --git a/hal/platform_api.h b/hal/platform_api.h
index b11a0c7..534630c 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -36,6 +36,8 @@
 int platform_get_fluence_type(void *platform, char *value, uint32_t len);
 int platform_set_snd_device_acdb_id(snd_device_t snd_device, unsigned int acdb_id);
 int platform_get_snd_device_acdb_id(snd_device_t snd_device);
+int platform_set_snd_device_bit_width(snd_device_t snd_device, unsigned int bit_width);
+int platform_get_snd_device_bit_width(snd_device_t snd_device);
 int platform_send_audio_calibration(void *platform, snd_device_t snd_device,
                                     int app_type, int sample_rate);
 int platform_get_default_app_type(void *platform);
diff --git a/hal/platform_info.c b/hal/platform_info.c
index 615b9f3..a176177 100644
--- a/hal/platform_info.c
+++ b/hal/platform_info.c
@@ -43,6 +43,7 @@
 typedef enum {
     ROOT,
     ACDB,
+    BITWIDTH,
     PCM_ID,
     BACKEND_NAME,
 } section_t;
@@ -50,6 +51,7 @@
 typedef void (* section_process_fn)(const XML_Char **attr);
 
 static void process_acdb_id(const XML_Char **attr);
+static void process_bit_width(const XML_Char **attr);
 static void process_pcm_id(const XML_Char **attr);
 static void process_backend_name(const XML_Char **attr);
 static void process_root(const XML_Char **attr);
@@ -57,6 +59,7 @@
 static section_process_fn section_table[] = {
     [ROOT] = process_root,
     [ACDB] = process_acdb_id,
+    [BITWIDTH] = process_bit_width,
     [PCM_ID] = process_pcm_id,
     [BACKEND_NAME] = process_backend_name,
 };
@@ -202,6 +205,38 @@
     return;
 }
 
+static void process_bit_width(const XML_Char **attr)
+{
+    int index;
+
+    if (strcmp(attr[0], "name") != 0) {
+        ALOGE("%s: 'name' not found, no ACDB ID set!", __func__);
+        goto done;
+    }
+
+    index = platform_get_snd_device_index((char *)attr[1]);
+    if (index < 0) {
+        ALOGE("%s: Device %s in platform info xml not found, no ACDB ID set!",
+              __func__, attr[1]);
+        goto done;
+    }
+
+    if (strcmp(attr[2], "bit_width") != 0) {
+        ALOGE("%s: Device %s in platform info xml has no bit_width, no ACDB ID set!",
+              __func__, attr[1]);
+        goto done;
+    }
+
+    if (platform_set_snd_device_bit_width(index, atoi((char *)attr[3])) < 0) {
+        ALOGE("%s: Device %s, ACDB ID %d was not set!",
+              __func__, attr[1], atoi((char *)attr[3]));
+        goto done;
+    }
+
+done:
+    return;
+}
+
 static void start_tag(void *userdata __unused, const XML_Char *tag_name,
                       const XML_Char **attr)
 {
@@ -209,14 +244,16 @@
     const XML_Char              *attr_value = NULL;
     unsigned int                i;
 
-    if (strcmp(tag_name, "acdb_ids") == 0) {
+    if (strcmp(tag_name, "bit_width_configs") == 0) {
+        section = BITWIDTH;
+    } else if (strcmp(tag_name, "acdb_ids") == 0) {
         section = ACDB;
     } else if (strcmp(tag_name, "pcm_ids") == 0) {
         section = PCM_ID;
     } else if (strcmp(tag_name, "backend_names") == 0) {
         section = BACKEND_NAME;
     } else if (strcmp(tag_name, "device") == 0) {
-        if ((section != ACDB) && (section != BACKEND_NAME)) {
+        if ((section != ACDB) && (section != BACKEND_NAME) && (section != BITWIDTH)) {
             ALOGE("device tag only supported for acdb/backend names");
             return;
         }
@@ -239,7 +276,9 @@
 
 static void end_tag(void *userdata __unused, const XML_Char *tag_name)
 {
-    if (strcmp(tag_name, "acdb_ids") == 0) {
+    if (strcmp(tag_name, "bit_width_configs") == 0) {
+        section = ROOT;
+    } else if (strcmp(tag_name, "acdb_ids") == 0) {
         section = ROOT;
     } else if (strcmp(tag_name, "pcm_ids") == 0) {
         section = ROOT;