audio: Update hal to handle 32bit/384kHz playback.

Update the mixer control string used to configure BE at 32bit format
with correct value.
For HDMI backend, as it does not support 32bit/384kHz, configure
BE to 24bit/192kHz if supported by the connected device.
Configure speaker device to bit width supported on the device
if stream bit width is greater than 24 bit.

Change-Id: Ic1c437d4cb15db709941eec065d40b2ae173ea9d
diff --git a/hal/audio_extn/usb.c b/hal/audio_extn/usb.c
index b3bd58f..f936f99 100644
--- a/hal/audio_extn/usb.c
+++ b/hal/audio_extn/usb.c
@@ -47,7 +47,7 @@
 #define SAMPLE_RATE_11025         11025
 // Supported sample rates for USB
 static uint32_t supported_sample_rates[] =
-    {44100, 48000, 64000, 88200, 96000, 176400, 192000};
+    {44100, 48000, 64000, 88200, 96000, 176400, 192000, 384000};
 
 #define  MAX_SAMPLE_RATE_SIZE  sizeof(supported_sample_rates)/sizeof(supported_sample_rates[0])
 
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index 18c55cf..9542fbd 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -495,7 +495,7 @@
     struct stream_format *sf_info;
     char value[PROPERTY_VALUE_MAX] = {0};
 
-    if ((24 == bit_width) &&
+    if ((bit_width >= 24) &&
         (devices & AUDIO_DEVICE_OUT_SPEAKER)) {
         int32_t bw = platform_get_snd_device_bit_width(SND_DEVICE_OUT_SPEAKER);
         if (-ENOSYS != bw)
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 09a5734..7888e5a 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -2228,6 +2228,35 @@
     return size;
 }
 
+static size_t get_output_period_size(uint32_t sample_rate,
+                                    audio_format_t format,
+                                    int channel_count,
+                                    int duration /*in millisecs*/)
+{
+    size_t size = 0;
+    uint32_t bytes_per_sample = audio_bytes_per_sample(format);
+
+    if ((duration == 0) || (sample_rate == 0) ||
+        (bytes_per_sample == 0) || (channel_count == 0)) {
+        ALOGW("Invalid config duration %d sr %d bps %d ch %d", duration, sample_rate,
+               bytes_per_sample, channel_count);
+        return -EINVAL;
+    }
+
+    size = (sample_rate *
+            duration *
+            bytes_per_sample *
+            channel_count) / 1000;
+    /*
+     * To have same PCM samples for all channels, the buffer size requires to
+     * be multiple of (number of channels * bytes per sample)
+     * For writes to succeed, the buffer must be written at address which is multiple of 32
+     */
+    size = ALIGN(size, (bytes_per_sample * channel_count * 32));
+
+    return (size/(channel_count * bytes_per_sample));
+}
+
 static uint64_t get_actual_pcm_frames_rendered(struct stream_out *out)
 {
     uint64_t actual_frames_rendered = 0;
@@ -3898,6 +3927,17 @@
         out->config = pcm_config_afe_proxy_playback;
         adev->voice_tx_output = out;
     } else {
+        unsigned int channels = 0;
+        /*Update config params to default if not set by the caller*/
+        if (config->sample_rate == 0)
+            config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
+        if (config->channel_mask == AUDIO_CHANNEL_NONE)
+            config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+        if (config->format == AUDIO_FORMAT_DEFAULT)
+            config->format = AUDIO_FORMAT_PCM_16_BIT;
+
+        channels = audio_channel_count_from_out_mask(out->channel_mask);
+
         if (out->flags & AUDIO_OUTPUT_FLAG_RAW) {
             out->usecase = USECASE_AUDIO_PLAYBACK_ULL;
             out->realtime = may_use_noirq_mode(adev, USECASE_AUDIO_PLAYBACK_ULL,
@@ -3909,6 +3949,13 @@
         } else if (out->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) {
             out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER;
             out->config = pcm_config_deep_buffer;
+            out->config.period_size = get_output_period_size(config->sample_rate, out->format,
+                                                 channels, DEEP_BUFFER_OUTPUT_PERIOD_DURATION);
+            if (out->config.period_size <= 0) {
+                ALOGE("Invalid configuration period size is not valid");
+                ret = -EINVAL;
+                goto error_open;
+            }
         } else {
             /* primary path is the default path selected if no other outputs are available/suitable */
             out->usecase = USECASE_AUDIO_PLAYBACK_PRIMARY;
@@ -3920,7 +3967,7 @@
         out->bit_width = format_to_bitwidth_table[out->hal_op_format] << 3;
         out->config.rate = config->sample_rate;
         out->sample_rate = out->config.rate;
-        out->config.channels = audio_channel_count_from_out_mask(out->channel_mask);
+        out->config.channels = channels;
         if (out->hal_ip_format != out->hal_op_format) {
             uint32_t buffer_size = out->config.period_size *
                                    format_to_bitwidth_table[out->hal_op_format] *
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index fa5d0e4..a5cc804 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -4304,7 +4304,7 @@
             else
                 mixer_ctl_set_enum_by_string(ctl, "S24_LE");
         } else if (bit_width == 32) {
-            mixer_ctl_set_enum_by_string(ctl, "S24_LE");
+            mixer_ctl_set_enum_by_string(ctl, "S32_LE");
         } else {
             mixer_ctl_set_enum_by_string(ctl, "S16_LE");
         }
@@ -4640,6 +4640,13 @@
     } else if ((usecase->devices & AUDIO_DEVICE_OUT_SPEAKER) ||
                (usecase->devices & AUDIO_DEVICE_OUT_EARPIECE) ) {
         sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+
+        if (bit_width >= 24) {
+            bit_width = platform_get_snd_device_bit_width(SND_DEVICE_OUT_SPEAKER);
+            ALOGD("%s:becf: afe: reset bitwidth to %d (based on supported"
+                  " value for this platform)", __func__, bit_width);
+        }
+
         ALOGD("%s:becf: afe: playback on codec device not supporting native playback set "
             "default Sample Rate(48k)", __func__);
     }
@@ -4660,6 +4667,13 @@
         hdmi_backend_cfg.channels = channels;
         hdmi_backend_cfg.passthrough_enabled = false;
 
+        /*HDMI does not support 384Khz/32bit playback hence configure BE to 24b/192Khz*/
+        /* TODO: Instead have the validation against edid return the next best match*/
+        if (bit_width > 24)
+            hdmi_backend_cfg.bit_width = 24;
+        if (sample_rate > 192000)
+            hdmi_backend_cfg.sample_rate = 192000;
+
         platform_check_hdmi_backend_cfg(adev, usecase, backend_idx, &hdmi_backend_cfg);
 
         bit_width = hdmi_backend_cfg.bit_width;
diff --git a/hal/msm8916/platform.h b/hal/msm8916/platform.h
index 33be141..cba9068 100644
--- a/hal/msm8916/platform.h
+++ b/hal/msm8916/platform.h
@@ -267,6 +267,7 @@
  * the buffer size of an input/output stream
  */
 #define DEEP_BUFFER_OUTPUT_PERIOD_SIZE 1920
+#define DEEP_BUFFER_OUTPUT_PERIOD_DURATION 40 /* 40 millisecs */
 #define DEEP_BUFFER_OUTPUT_PERIOD_COUNT 2
 #define LOW_LATENCY_OUTPUT_PERIOD_SIZE 240
 #define LOW_LATENCY_OUTPUT_PERIOD_COUNT 2
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index a175d40..fa67342 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -2165,7 +2165,7 @@
 {
     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 CODEC_BACKEND_DEFAULT_BIT_WIDTH;
     }
     return backend_bit_width_table[snd_device];
 }
@@ -4363,7 +4363,7 @@
             else
                  ret = mixer_ctl_set_enum_by_string(ctl, "S24_LE");
         } else if (bit_width == 32) {
-            ret = mixer_ctl_set_enum_by_string(ctl, "S24_LE");
+            ret = mixer_ctl_set_enum_by_string(ctl, "S32_LE");
         } else {
             ret = mixer_ctl_set_enum_by_string(ctl, "S16_LE");
         }
@@ -4705,6 +4705,12 @@
         }
     } else if ((usecase->devices & AUDIO_DEVICE_OUT_SPEAKER) ||
                (usecase->devices & AUDIO_DEVICE_OUT_EARPIECE) ) {
+
+        if (bit_width >= 24) {
+            bit_width = platform_get_snd_device_bit_width(SND_DEVICE_OUT_SPEAKER);
+            ALOGD("%s:becf: afe: reset bitwidth to %d (based on supported"
+                   " value for this platform)", __func__, bit_width);
+        }
         sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
         ALOGD("%s:becf: afe: playback on codec device not supporting native playback set "
             "default Sample Rate(48k)", __func__);
@@ -4725,6 +4731,15 @@
         hdmi_backend_cfg.channels = channels;
         hdmi_backend_cfg.passthrough_enabled = false;
 
+        /*
+         * HDMI does not support 384Khz/32bit playback hence configure BE to 24b/192Khz
+         * TODO: Instead have the validation against edid return the next best match
+         */
+        if (bit_width > 24)
+            hdmi_backend_cfg.bit_width = 24;
+        if (sample_rate > 192000)
+            hdmi_backend_cfg.sample_rate = 192000;
+
         platform_check_hdmi_backend_cfg(adev, usecase, backend_idx, &hdmi_backend_cfg);
 
         bit_width = hdmi_backend_cfg.bit_width;
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 2b65950..c231843 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -257,7 +257,14 @@
  * We should take care of returning proper size when AudioFlinger queries for
  * the buffer size of an input/output stream
  */
+
+/* for 384Khz output below period size corresponds to 20ms worth duration of buffer,
+ * current implementation can support buffer size of 40ms duration
+ * for 32b/384Khz/stereo output.
+ */
 #define DEEP_BUFFER_OUTPUT_PERIOD_SIZE 1920
+#define DEEP_BUFFER_OUTPUT_PERIOD_DURATION 40 /* 40 milisecs */
+
 #define DEEP_BUFFER_OUTPUT_PERIOD_COUNT 2
 #define LOW_LATENCY_OUTPUT_PERIOD_SIZE 240
 #define LOW_LATENCY_OUTPUT_PERIOD_COUNT 2