hal: Fix policy conf parser for FLAC playback on multiple sample rate
-Apptype update for FLAC format fails as it is not listed as
supported format. By adding AUDIO_FORMAT_FLAC, corresponding apptype
is selected which enables correct audio_output profile.
-During config structure population, add logic to identify output
profile according to sampling rate in addition to format and flag.
-Currently, output policy parser sends mixer command containing
acdb id and app type only. As a result, adm opens at only one fixed
sampling rate. By sending sample rate, it enables adm open at
appropriate sample rate obtained from audio output policy conf file.
Change-Id: I014e1c139f7905d799003add43e1b74715c4367d
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 7ce1c3a..351a651 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -271,6 +271,8 @@
struct listnode *streams_output_cfg_list,
audio_output_flags_t flags,
audio_format_t format,
+ uint32_t sample_rate,
+ uint32_t bit_width,
struct stream_app_type_cfg *app_type_cfg);
int audio_extn_utils_send_app_type_cfg(struct audio_usecase *usecase);
void audio_extn_utils_send_audio_calibration(struct audio_device *adev,
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index e7a57c8..0f35f87 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -93,6 +93,7 @@
STRING_TO_ENUM(AUDIO_FORMAT_EVRCNW),
STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT_OFFLOAD),
STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_OFFLOAD),
+ STRING_TO_ENUM(AUDIO_FORMAT_FLAC),
#endif
};
@@ -151,16 +152,26 @@
}
}
-static int parse_sample_rate_names(char *name)
+static void parse_sample_rate_names(char *name, struct streams_output_cfg *so_info)
{
- int sample_rate = 48000;
+ struct stream_sample_rate *ss_info = NULL;
+ uint32_t sample_rate = 48000;
char *str = strtok(name, "|");
- if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG))
- sample_rate = (int)strtol(str, (char **)NULL, 10);
+ if (str != NULL && 0 == strcmp(str, DYNAMIC_VALUE_TAG))
+ return;
- ALOGV("%s: sample_rate - %d", __func__, sample_rate);
- return sample_rate;
+ list_init(&so_info->sample_rate_list);
+ while (str != NULL) {
+ sample_rate = (uint32_t)strtol(str, (char **)NULL, 10);
+ ALOGV("%s: sample_rate - %d", __func__, sample_rate);
+ if (0 != sample_rate) {
+ ss_info = (struct stream_sample_rate *)calloc(1, sizeof(struct stream_sample_rate));
+ ss_info->sample_rate = sample_rate;
+ list_add_tail(&so_info->sample_rate_list, &ss_info->list);
+ }
+ str = strtok(NULL, "|");
+ }
}
static int parse_bit_width_names(char *name)
@@ -207,7 +218,8 @@
} else if (strcmp(node->name, FORMATS_TAG) == 0) {
parse_format_names((char *)node->value, so_info);
} else if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
- so_info->app_type_cfg.sample_rate = parse_sample_rate_names((char *)node->value);
+ so_info->app_type_cfg.sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+ parse_sample_rate_names((char *)node->value, so_info);
} else if (strcmp(node->name, BIT_WIDTH_TAG) == 0) {
so_info->app_type_cfg.bit_width = parse_bit_width_names((char *)node->value);
} else if (strcmp(node->name, APP_TYPE_TAG) == 0) {
@@ -325,16 +337,21 @@
struct listnode *node_i, *node_j;
struct streams_output_cfg *so_info;
struct stream_format *sf_info;
+ struct stream_sample_rate *ss_info;
ALOGV("%s", __func__);
list_for_each(node_i, streams_output_cfg_list) {
so_info = node_to_item(node_i, struct streams_output_cfg, list);
- ALOGV("%d: flags-%d, output_sample_rate-%d, output_bit_width-%d, app_type-%d",
- i++, so_info->flags, so_info->app_type_cfg.sample_rate,
+ ALOGV("%s: flags-%d, output_sample_rate-%d, output_bit_width-%d, app_type-%d",
+ __func__, so_info->flags, so_info->app_type_cfg.sample_rate,
so_info->app_type_cfg.bit_width, so_info->app_type_cfg.app_type);
list_for_each(node_j, &so_info->format_list) {
sf_info = node_to_item(node_j, struct stream_format, list);
ALOGV("format-%x", sf_info->format);
}
+ list_for_each(node_j, &so_info->sample_rate_list) {
+ ss_info = node_to_item(node_j, struct stream_sample_rate, list);
+ ALOGV("sample rate-%d", ss_info->sample_rate);
+ }
}
}
@@ -354,20 +371,67 @@
list_remove(node_j);
free(node_to_item(node_j, struct stream_format, list));
}
+ while (!list_empty(&so_info->sample_rate_list)) {
+ node_j = list_head(&so_info->sample_rate_list);
+ list_remove(node_j);
+ free(node_to_item(node_j, struct stream_sample_rate, list));
+ }
list_remove(node_i);
free(node_to_item(node_i, struct streams_output_cfg, list));
}
}
+static bool set_output_cfg(struct streams_output_cfg *so_info,
+ struct stream_app_type_cfg *app_type_cfg,
+ uint32_t sample_rate, uint32_t bit_width)
+ {
+ struct listnode *node_i;
+ struct stream_sample_rate *ss_info;
+ list_for_each(node_i, &so_info->sample_rate_list) {
+ ss_info = node_to_item(node_i, struct stream_sample_rate, list);
+ if ((sample_rate <= ss_info->sample_rate) &&
+ (bit_width == so_info->app_type_cfg.bit_width)) {
+ app_type_cfg->app_type = so_info->app_type_cfg.app_type;
+ app_type_cfg->sample_rate = ss_info->sample_rate;
+ app_type_cfg->bit_width = so_info->app_type_cfg.bit_width;
+ ALOGV("%s app_type_cfg->app_type %d, app_type_cfg->sample_rate %d, app_type_cfg->bit_width %d",
+ __func__, app_type_cfg->app_type, app_type_cfg->sample_rate, app_type_cfg->bit_width);
+ return true;
+ }
+ }
+ /*
+ * Reiterate through the list assuming dafault sample rate.
+ * Handles scenario where input sample rate is higher
+ * than all sample rates in list for the input bit width.
+ */
+ sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+ list_for_each(node_i, &so_info->sample_rate_list) {
+ ss_info = node_to_item(node_i, struct stream_sample_rate, list);
+ if ((sample_rate <= ss_info->sample_rate) &&
+ (bit_width == so_info->app_type_cfg.bit_width)) {
+ app_type_cfg->app_type = so_info->app_type_cfg.app_type;
+ app_type_cfg->sample_rate = sample_rate;
+ app_type_cfg->bit_width = so_info->app_type_cfg.bit_width;
+ ALOGV("%s Assuming default sample rate. app_type_cfg->app_type %d, app_type_cfg->sample_rate %d, app_type_cfg->bit_width %d",
+ __func__, app_type_cfg->app_type, app_type_cfg->sample_rate, app_type_cfg->bit_width);
+ return true;
+ }
+ }
+ return false;
+}
+
void audio_extn_utils_update_stream_app_type_cfg(void *platform,
struct listnode *streams_output_cfg_list,
audio_output_flags_t flags,
audio_format_t format,
+ uint32_t sample_rate,
+ uint32_t bit_width,
struct stream_app_type_cfg *app_type_cfg)
{
- struct listnode *node_i, *node_j;
+ struct listnode *node_i, *node_j, *node_k;
struct streams_output_cfg *so_info;
struct stream_format *sf_info;
+ struct stream_sample_rate *ss_info;
ALOGV("%s: flags: %x, format: %x", __func__, flags, format);
list_for_each(node_i, streams_output_cfg_list) {
@@ -376,11 +440,8 @@
list_for_each(node_j, &so_info->format_list) {
sf_info = node_to_item(node_j, struct stream_format, list);
if (sf_info->format == format) {
- ALOGV("App type: %d", so_info->app_type_cfg.app_type);
- app_type_cfg->app_type = so_info->app_type_cfg.app_type;
- app_type_cfg->sample_rate = so_info->app_type_cfg.sample_rate;
- app_type_cfg->bit_width = so_info->app_type_cfg.bit_width;
- return;
+ if (set_output_cfg(so_info, app_type_cfg, sample_rate, bit_width))
+ return;
}
}
}
@@ -389,16 +450,17 @@
so_info = node_to_item(node_i, struct streams_output_cfg, list);
if (so_info->flags == AUDIO_OUTPUT_FLAG_PRIMARY) {
ALOGV("Compatible output profile not found.");
- ALOGV("App type default to primary output: %d", so_info->app_type_cfg.app_type);
app_type_cfg->app_type = so_info->app_type_cfg.app_type;
app_type_cfg->sample_rate = so_info->app_type_cfg.sample_rate;
app_type_cfg->bit_width = so_info->app_type_cfg.bit_width;
+ ALOGV("%s Default to primary output: App type: %d sample_rate %d",
+ __func__, so_info->app_type_cfg.app_type, app_type_cfg->sample_rate);
return;
}
}
ALOGW("%s: App type could not be selected. Falling back to default", __func__);
app_type_cfg->app_type = platform_get_default_app_type(platform);
- app_type_cfg->sample_rate = 48000;
+ app_type_cfg->sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
app_type_cfg->bit_width = 16;
}
@@ -453,6 +515,7 @@
}
app_type_cfg[len++] = out->app_type_cfg.app_type;
app_type_cfg[len++] = acdb_dev_id;
+ app_type_cfg[len++] = out->app_type_cfg.sample_rate;
mixer_ctl_set_array(ctl, app_type_cfg, len);