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