hal: Add support for 24 bit through deep buffer
Enable support for 24 bit through deep buffer
path. Remove hardcoding of 16 bit and honor
the format and sample rate set by flinger.
24 bit support includes support for 8_24 and
24 bit packed pcm format.
Change-Id: I2cbc2005b188c3bc21b4e7a7275e9ee21c7b820d
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 357f036..fe3fe95 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -532,7 +532,10 @@
int read_line_from_file(const char *path, char *buf, size_t count);
int audio_extn_utils_get_codec_version(const char *snd_card_name, int card_num, char *codec_version);
audio_format_t alsa_format_to_hal(uint32_t alsa_format);
-uint32_t hal_format_to_alsa(audio_format_t pcm_format);
+uint32_t hal_format_to_alsa(audio_format_t hal_format);
+audio_format_t pcm_format_to_hal(uint32_t pcm_format);
+uint32_t hal_format_to_pcm(audio_format_t hal_format);
+
void audio_extn_utils_update_direct_pcm_fragment_size(struct stream_out *out);
#ifndef KPI_OPTIMIZE_ENABLED
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index df20120..e3f1b6c 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -96,11 +96,11 @@
};
const struct string_to_enum s_format_name_to_enum_table[] = {
+ STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_BIT),
STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT),
STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_PACKED),
STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_24_BIT),
STRING_TO_ENUM(AUDIO_FORMAT_PCM_32_BIT),
- STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_BIT),
STRING_TO_ENUM(AUDIO_FORMAT_MP3),
STRING_TO_ENUM(AUDIO_FORMAT_AAC),
STRING_TO_ENUM(AUDIO_FORMAT_VORBIS),
@@ -765,6 +765,60 @@
return alsa_format;
}
+/*Translates PCM formats to AOSP formats*/
+audio_format_t pcm_format_to_hal(uint32_t pcm_format)
+{
+ audio_format_t format = AUDIO_FORMAT_INVALID;
+
+ switch(pcm_format) {
+ case PCM_FORMAT_S16_LE:
+ format = AUDIO_FORMAT_PCM_16_BIT;
+ break;
+ case PCM_FORMAT_S24_3LE:
+ format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
+ break;
+ case PCM_FORMAT_S24_LE:
+ format = AUDIO_FORMAT_PCM_8_24_BIT;
+ break;
+ case PCM_FORMAT_S32_LE:
+ format = AUDIO_FORMAT_PCM_32_BIT;
+ break;
+ default:
+ ALOGW("Incorrect PCM format");
+ format = AUDIO_FORMAT_INVALID;
+ }
+ return format;
+}
+
+/*Translates hal format (AOSP) to alsa formats*/
+uint32_t hal_format_to_pcm(audio_format_t hal_format)
+{
+ uint32_t pcm_format;
+
+ switch (hal_format) {
+ case AUDIO_FORMAT_PCM_32_BIT:
+ case AUDIO_FORMAT_PCM_8_24_BIT:
+ case AUDIO_FORMAT_PCM_FLOAT: {
+ if (platform_supports_true_32bit())
+ pcm_format = PCM_FORMAT_S32_LE;
+ else
+ pcm_format = PCM_FORMAT_S24_3LE;
+ }
+ break;
+ case AUDIO_FORMAT_PCM_8_BIT:
+ pcm_format = PCM_FORMAT_S8;
+ break;
+ case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+ pcm_format = PCM_FORMAT_S24_3LE;
+ break;
+ default:
+ case AUDIO_FORMAT_PCM_16_BIT:
+ pcm_format = PCM_FORMAT_S16_LE;
+ break;
+ }
+ return pcm_format;
+}
+
uint32_t get_alsa_fragment_size(uint32_t bytes_per_sample,
uint32_t sample_rate,
uint32_t noOfChannels)
@@ -798,8 +852,8 @@
*/
void audio_extn_utils_update_direct_pcm_fragment_size(struct stream_out *out)
{
- audio_format_t dst_format = out->compr_pcm_config.hal_op_format;
- audio_format_t src_format = out->compr_pcm_config.hal_ip_format;
+ audio_format_t dst_format = out->hal_op_format;
+ audio_format_t src_format = out->hal_ip_format;
uint32_t hal_op_bytes_per_sample = audio_bytes_per_sample(dst_format);
uint32_t hal_ip_bytes_per_sample = audio_bytes_per_sample(src_format);
@@ -811,13 +865,13 @@
if ((src_format != dst_format) &&
hal_op_bytes_per_sample != hal_ip_bytes_per_sample) {
- out->compr_pcm_config.hal_fragment_size =
+ out->hal_fragment_size =
((out->compr_config.fragment_size * hal_ip_bytes_per_sample) /
hal_op_bytes_per_sample);
ALOGI("enable conversion hal_input_fragment_size is %d src_format %x dst_format %x",
- out->compr_pcm_config.hal_fragment_size, src_format, dst_format);
+ out->hal_fragment_size, src_format, dst_format);
} else {
- out->compr_pcm_config.hal_fragment_size = out->compr_config.fragment_size;
+ out->hal_fragment_size = out->compr_config.fragment_size;
}
}
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 048e5b2..a8ebb6b 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -2139,7 +2139,7 @@
else if(out->usecase == USECASE_COMPRESS_VOIP_CALL)
return voice_extn_compress_voip_out_get_buffer_size(out);
else if (out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM)
- return out->compr_pcm_config.hal_fragment_size;
+ return out->hal_fragment_size;
return out->config.period_size *
audio_stream_out_frame_size((const struct audio_stream_out *)stream);
@@ -2556,7 +2556,8 @@
/* increase written size during SSR to avoid mismatch
* with the written frames count in AF
*/
- out->written += bytes / (out->config.channels * sizeof(short));
+ if (audio_bytes_per_sample(out->format) != 0)
+ out->written += bytes / (out->config.channels * audio_bytes_per_sample(out->format));
ALOGD(" %s: sound card is not active/SSR state", __func__);
ret= -EIO;
goto exit;
@@ -2612,27 +2613,27 @@
}
}
if ((out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM) &&
- (out->compr_pcm_config.convert_buffer) != NULL) {
+ (out->convert_buffer) != NULL) {
- if ((bytes > out->compr_pcm_config.hal_fragment_size)) {
+ if ((bytes > out->hal_fragment_size)) {
ALOGW("Error written bytes %zu > %d (fragment_size)",
- bytes, out->compr_pcm_config.hal_fragment_size);
+ bytes, out->hal_fragment_size);
pthread_mutex_unlock(&out->lock);
return -EINVAL;
} else {
- audio_format_t dst_format = out->compr_pcm_config.hal_op_format;
- audio_format_t src_format = out->compr_pcm_config.hal_ip_format;
+ audio_format_t dst_format = out->hal_op_format;
+ audio_format_t src_format = out->hal_ip_format;
uint32_t frames = bytes / format_to_bitwidth_table[src_format];
uint32_t bytes_to_write = frames * format_to_bitwidth_table[dst_format];
- memcpy_by_audio_format(out->compr_pcm_config.convert_buffer,
+ memcpy_by_audio_format(out->convert_buffer,
dst_format,
buffer,
src_format,
frames);
- ret = compress_write(out->compr, out->compr_pcm_config.convert_buffer,
+ ret = compress_write(out->compr, out->convert_buffer,
bytes_to_write);
/*Convert written bytes in audio flinger format*/
@@ -2681,15 +2682,31 @@
if (adev->adm_request_focus)
adev->adm_request_focus(adev->adm_data, out->handle);
- if (out->usecase == USECASE_AUDIO_PLAYBACK_AFE_PROXY)
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_AFE_PROXY) {
ret = pcm_mmap_write(out->pcm, (void *)buffer, bytes);
- else
+ } else if (out->hal_op_format != out->hal_ip_format &&
+ out->convert_buffer != NULL) {
+
+ memcpy_by_audio_format(out->convert_buffer,
+ out->hal_op_format,
+ buffer,
+ out->hal_ip_format,
+ out->config.period_size * out->config.channels);
+
+ ret = pcm_write(out->pcm, out->convert_buffer,
+ (out->config.period_size *
+ out->config.channels *
+ format_to_bitwidth_table[out->hal_op_format]));
+ } else {
ret = pcm_write(out->pcm, (void *)buffer, bytes);
+ }
if (ret < 0)
ret = -errno;
- else if (ret == 0)
- out->written += bytes / (out->config.channels * sizeof(short));
+ else if (ret == 0 && (audio_bytes_per_sample(out->format) != 0))
+ out->written += bytes / (out->config.channels * audio_bytes_per_sample(out->format));
+ else
+ ret = -EINVAL;
if (adev->adm_abandon_focus)
adev->adm_abandon_focus(adev->adm_data, out->handle);
@@ -3365,7 +3382,7 @@
out->handle = handle;
out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
out->non_blocking = 0;
- out->compr_pcm_config.convert_buffer = NULL;
+ out->convert_buffer = NULL;
if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL &&
(flags & AUDIO_OUTPUT_FLAG_DIRECT)) {
@@ -3534,15 +3551,15 @@
out->compr_config.codec->format = hal_format_to_alsa(
config->offload_info.format);
- out->compr_pcm_config.hal_op_format = alsa_format_to_hal(
+ out->hal_op_format = alsa_format_to_hal(
out->compr_config.codec->format);
- out->compr_pcm_config.hal_ip_format = out->format;
+ out->hal_ip_format = out->format;
/*for direct PCM playback populate bit_width based on selected alsa format as
*hal input format and alsa format might differ based on platform support.
*/
out->bit_width = audio_bytes_per_sample(
- out->compr_pcm_config.hal_op_format) << 3;
+ out->hal_op_format) << 3;
out->compr_config.fragments = DIRECT_PCM_NUM_FRAGMENTS;
@@ -3555,13 +3572,13 @@
/*if hal input and output fragment size is different this indicates HAL input format is
*not same as the alsa format
*/
- if (out->compr_pcm_config.hal_fragment_size != out->compr_config.fragment_size) {
+ if (out->hal_fragment_size != out->compr_config.fragment_size) {
/*Allocate a buffer to convert input data to the alsa configured format.
*size of convert buffer is equal to the size required to hold one fragment size
*worth of pcm data, this is because flinger does not write more than fragment_size
*/
- out->compr_pcm_config.convert_buffer = calloc(1,out->compr_config.fragment_size);
- if (out->compr_pcm_config.convert_buffer == NULL){
+ out->convert_buffer = calloc(1,out->compr_config.fragment_size);
+ if (out->convert_buffer == NULL){
ALOGE("Allocation failed for convert buffer for size %d", out->compr_config.fragment_size);
ret = -ENOMEM;
goto error_open;
@@ -3641,30 +3658,46 @@
out->usecase = USECASE_AUDIO_PLAYBACK_AFE_PROXY;
out->config = pcm_config_afe_proxy_playback;
adev->voice_tx_output = out;
- } else if (out->flags & AUDIO_OUTPUT_FLAG_RAW) {
- out->usecase = USECASE_AUDIO_PLAYBACK_ULL;
- out->config = pcm_config_low_latency;
- out->sample_rate = out->config.rate;
- } else if (out->flags & AUDIO_OUTPUT_FLAG_FAST) {
- format = AUDIO_FORMAT_PCM_16_BIT;
- out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY;
- out->config = pcm_config_low_latency;
- out->sample_rate = out->config.rate;
- } else if (out->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) {
- format = AUDIO_FORMAT_PCM_16_BIT;
- out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER;
- out->config = pcm_config_deep_buffer;
- out->sample_rate = out->config.rate;
} else {
- /* primary path is the default path selected if no other outputs are available/suitable */
- format = AUDIO_FORMAT_PCM_16_BIT;
- out->usecase = USECASE_AUDIO_PLAYBACK_PRIMARY;
- out->config = PCM_CONFIG_AUDIO_PLAYBACK_PRIMARY;
+ if (out->flags & AUDIO_OUTPUT_FLAG_RAW) {
+ out->usecase = USECASE_AUDIO_PLAYBACK_ULL;
+ out->config = pcm_config_low_latency;
+ } else if (out->flags & AUDIO_OUTPUT_FLAG_FAST) {
+ out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY;
+ out->config = pcm_config_low_latency;
+ } else if (out->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) {
+ out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER;
+ out->config = pcm_config_deep_buffer;
+ } else {
+ /* primary path is the default path selected if no other outputs are available/suitable */
+ out->usecase = USECASE_AUDIO_PLAYBACK_PRIMARY;
+ out->config = PCM_CONFIG_AUDIO_PLAYBACK_PRIMARY;
+ }
+ out->hal_ip_format = format = out->format;
+ out->config.format = hal_format_to_pcm(out->hal_ip_format);
+ out->hal_op_format = pcm_format_to_hal(out->config.format);
+ 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);
+ 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] *
+ out->config.channels;
+ out->convert_buffer = calloc(1, buffer_size);
+ if (out->convert_buffer == NULL){
+ ALOGE("Allocation failed for convert buffer for size %d",
+ out->compr_config.fragment_size);
+ ret = -ENOMEM;
+ goto error_open;
+ }
+ ALOGD("Convert buffer allocated of size %d", buffer_size);
+ }
}
- ALOGV("%s devices %d,flags %x, format %x, out->sample_rate %d, out->bit_width %d out->flags:%x, flags:%x",
- __func__, devices, flags, format, out->sample_rate, out->bit_width, out->flags, flags);
+ ALOGV("%s devices:%d, format:%x, out->sample_rate:%d,out->bit_width:%d out->format:%d out->flags:%x, flags:%x",
+ __func__, devices, format, out->sample_rate, out->bit_width, out->format, out->flags, flags);
+
/* TODO remove this hardcoding and check why width is zero*/
if (out->bit_width == 0)
out->bit_width = 16;
@@ -3735,8 +3768,8 @@
return 0;
error_open:
- if (out->compr_pcm_config.convert_buffer)
- free(out->compr_pcm_config.convert_buffer);
+ if (out->convert_buffer)
+ free(out->convert_buffer);
free(out);
*stream_out = NULL;
ALOGD("%s: exit: ret %d", __func__, ret);
@@ -3763,8 +3796,6 @@
out_standby(&stream->common);
if (is_offload_usecase(out->usecase)) {
- if (out->compr_pcm_config.convert_buffer != NULL)
- free(out->compr_pcm_config.convert_buffer);
audio_extn_dts_remove_state_notifier_node(out->usecase);
destroy_offload_callback_thread(out);
free_offload_usecase(adev, out->usecase);
@@ -3772,6 +3803,11 @@
free(out->compr_config.codec);
}
+ if (out->convert_buffer != NULL) {
+ free(out->convert_buffer);
+ out->convert_buffer = NULL;
+ }
+
if (adev->voice_tx_output == out)
adev->voice_tx_output = NULL;
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 5bd1216..8197fec 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -182,13 +182,6 @@
int app_type;
};
-struct compr_pcm_config {
- uint32_t hal_fragment_size;
- audio_format_t hal_ip_format;
- audio_format_t hal_op_format;
- void *convert_buffer;
-};
-
struct stream_out {
struct audio_stream_out stream;
pthread_mutex_t lock; /* see note below on mutex acquisition order */
@@ -230,7 +223,10 @@
bool send_next_track_params;
bool is_compr_metadata_avail;
unsigned int bit_width;
- struct compr_pcm_config compr_pcm_config;
+ uint32_t hal_fragment_size;
+ audio_format_t hal_ip_format;
+ audio_format_t hal_op_format;
+ void *convert_buffer;
struct audio_device *dev;
};