hal: Support Multichannel Speaker playback
Until now speaker playback only supports stereo
and is limited to default sample rate.
Update code to support QCS405 configurations with
CSRA soundcards that can have up to 16 or 32 speaker
output channels and allow sample rates up to 384kHz.
Change-Id: Ib4ed5edafca6f8b15134ca66db4bf1ef719ec15d
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index bd3fa7c..198d871 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -990,7 +990,14 @@
if (usecase->id == USECASE_AUDIO_PLAYBACK_VOIP) {
usecase->stream.out->app_type_cfg.sample_rate = usecase->stream.out->sample_rate;
} else if (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER) {
- usecase->stream.out->app_type_cfg.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
+ if (platform_spkr_use_default_sample_rate(adev->platform)) {
+ usecase->stream.out->app_type_cfg.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
+ } else {
+ platform_check_and_update_copp_sample_rate(adev->platform, snd_device,
+ usecase->stream.out->sample_rate,
+ &usecase->stream.out->app_type_cfg.sample_rate);
+ }
+
} else if ((snd_device == SND_DEVICE_OUT_HDMI ||
snd_device == SND_DEVICE_OUT_USB_HEADSET ||
snd_device == SND_DEVICE_OUT_DISPLAY_PORT) &&
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index cb2d786..dcc75de 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -4502,6 +4502,15 @@
audio_format_t dst_format = out->hal_op_format;
audio_format_t src_format = out->hal_ip_format;
+ /* prevent division-by-zero */
+ uint32_t bitwidth_src = format_to_bitwidth_table[src_format];
+ uint32_t bitwidth_dst = format_to_bitwidth_table[dst_format];
+ if ((bitwidth_src == 0) || (bitwidth_dst == 0)) {
+ ALOGE("%s: Error bitwidth == 0", __func__);
+ ATRACE_END();
+ return -EINVAL;
+ }
+
uint32_t frames = bytes / format_to_bitwidth_table[src_format];
uint32_t bytes_to_write = frames * format_to_bitwidth_table[dst_format];
@@ -4642,10 +4651,18 @@
out->standby = true;
}
out_on_error(&out->stream.common);
- if (!(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD))
- usleep((uint64_t)bytes * 1000000 / audio_stream_out_frame_size(stream) /
- out_get_sample_rate(&out->stream.common));
+ if (!(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
+ /* prevent division-by-zero */
+ uint32_t stream_size = audio_stream_out_frame_size(stream);
+ uint32_t srate = out_get_sample_rate(&out->stream.common);
+ if ((stream_size == 0) || (srate == 0)) {
+ ALOGE("%s: stream_size= %d, srate = %d", __func__, stream_size, srate);
+ ATRACE_END();
+ return -EINVAL;
+ }
+ usleep((uint64_t)bytes * 1000000 / stream_size / srate);
+ }
if (audio_extn_passthru_is_passthrough_stream(out)) {
ALOGE("%s: write error, ret = %zd", __func__, ret);
ATRACE_END();
@@ -7079,6 +7096,13 @@
config->format,
channel_count,
is_low_latency);
+ /* prevent division-by-zero */
+ if (frame_size == 0) {
+ ALOGE("%s: Error frame_size==0", __func__);
+ ret = -EINVAL;
+ goto err_open;
+ }
+
in->config.period_size = buffer_size / frame_size;
if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
diff --git a/hal/edid.h b/hal/edid.h
index da5c592..f920a82 100644
--- a/hal/edid.h
+++ b/hal/edid.h
@@ -57,6 +57,27 @@
#define PCM_CHANNEL_FRC 14 /* Front right of center. */
#define PCM_CHANNEL_RLC 15 /* Rear left of center. */
#define PCM_CHANNEL_RRC 16 /* Rear right of center. */
+#define PCM_CHANNEL_LFE2 17 /* Second low frequency channel. */
+#define PCM_CHANNEL_SL 18 /* Side left channel. */
+#define PCM_CHANNEL_SR 19 /* Side right channel. */
+#define PCM_CHANNEL_TFL 20 /* Top front left channel. */
+#define PCM_CHANNEL_LVH 20 /* Left vertical height channel. */
+#define PCM_CHANNEL_TFR 21 /* Top front right channel. */
+#define PCM_CHANNEL_RVH 21 /* Right vertical height channel. */
+#define PCM_CHANNEL_TC 22 /* Top center channel. */
+#define PCM_CHANNEL_TBL 23 /* Top back left channel. */
+#define PCM_CHANNEL_TBR 24 /* Top back right channel. */
+#define PCM_CHANNEL_TSL 25 /* Top side left channel. */
+#define PCM_CHANNEL_TSR 26 /* Top side right channel. */
+#define PCM_CHANNEL_TBC 27 /* Top back center channel. */
+#define PCM_CHANNEL_BFC 28 /* Bottom front center channel. */
+#define PCM_CHANNEL_BFL 29 /* Bottom front left channel. */
+#define PCM_CHANNEL_BFR 30 /* Bottom front right channel. */
+#define PCM_CHANNEL_LW 31 /* Left wide channel. */
+#define PCM_CHANNEL_RW 32 /* Right wide channel. */
+#define PCM_CHANNEL_LSD 33 /* Left side direct channel. */
+#define PCM_CHANNEL_RSD 34 /* Right side direct channel. */
+
#define MAX_HDMI_CHANNEL_CNT 8
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
old mode 100755
new mode 100644
index 82fafc7..76b339b
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -298,6 +298,7 @@
struct acdb_init_data_v4 acdb_init_data;
bool use_generic_handset;
struct spkr_device_chmap *spkr_ch_map;
+ bool use_sprk_default_sample_rate;
};
struct spkr_device_chmap {
@@ -2290,6 +2291,7 @@
my_data->hw_dep_fd = -1;
my_data->mono_speaker = SPKR_1;
my_data->spkr_ch_map = NULL;
+ my_data->use_sprk_default_sample_rate = true;
be_dai_name_table = NULL;
@@ -7385,6 +7387,11 @@
platform_get_edid_info(platform);
}
+bool platform_spkr_use_default_sample_rate(void *platform) {
+ struct platform_data *my_data = (struct platform_data *)platform;
+ return my_data->use_sprk_default_sample_rate;
+}
+
void platform_invalidate_backend_config(void * platform,snd_device_t snd_device)
{
struct platform_data *my_data = (struct platform_data *)platform;
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 128a458..0eb3ca0 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -276,6 +276,7 @@
struct acdb_init_data_v4 acdb_init_data;
bool use_generic_handset;
struct spkr_device_chmap *spkr_ch_map;
+ bool use_sprk_default_sample_rate;
};
struct spkr_device_chmap {
@@ -2096,7 +2097,7 @@
my_data->mono_speaker = SPKR_1;
my_data->speaker_lr_swap = false;
my_data->spkr_ch_map = NULL;
-
+ my_data->use_sprk_default_sample_rate = true;
be_dai_name_table = NULL;
property_get("ro.vendor.audio.sdk.fluencetype", my_data->fluence_cap, "");
@@ -2182,6 +2183,15 @@
else
platform_info_init(PLATFORM_INFO_XML_PATH, my_data, PLATFORM);
+ /* CSRA devices support multiple sample rates via I2S at spkr out */
+ if (!strncmp(snd_card_name, "qcs405-csra", strlen("qcs405-csra"))) {
+ ALOGE("%s: soundcard: %s supports multiple sample rates", __func__, snd_card_name);
+ my_data->use_sprk_default_sample_rate = false;
+ } else {
+ my_data->use_sprk_default_sample_rate = true;
+ ALOGE("%s: soundcard: %s supports only default sample rate", __func__, snd_card_name);
+ }
+
my_data->voice_feature_set = VOICE_FEATURE_SET_DEFAULT;
my_data->acdb_handle = dlopen(LIB_ACDB_LOADER, RTLD_NOW);
if (my_data->acdb_handle == NULL) {
@@ -2437,11 +2447,18 @@
} else {
if (!strncmp(snd_card_name, "qcs405", strlen("qcs405"))) {
- my_data->current_backend_cfg[DEFAULT_CODEC_BACKEND].bitwidth_mixer_ctl =
- strdup("WSA_CDC_DMA_RX_0 Format");
- my_data->current_backend_cfg[DEFAULT_CODEC_BACKEND].samplerate_mixer_ctl =
- strdup("WSA_CDC_DMA_RX_0 SampleRate");
+ if (!strncmp(snd_card_name, "qcs405-csra", strlen("qcs405-csra"))) {
+ my_data->current_backend_cfg[DEFAULT_CODEC_BACKEND].bitwidth_mixer_ctl =
+ strdup("PRIM_MI2S_RX Format");
+ my_data->current_backend_cfg[DEFAULT_CODEC_BACKEND].samplerate_mixer_ctl =
+ strdup("PRIM_MI2S_RX SampleRate");
+ } else {
+ my_data->current_backend_cfg[DEFAULT_CODEC_BACKEND].bitwidth_mixer_ctl =
+ strdup("WSA_CDC_DMA_RX_0 Format");
+ my_data->current_backend_cfg[DEFAULT_CODEC_BACKEND].samplerate_mixer_ctl =
+ strdup("WSA_CDC_DMA_RX_0 SampleRate");
+ }
my_data->current_backend_cfg[DEFAULT_CODEC_TX_BACKEND].bitwidth_mixer_ctl =
strdup("VA_CDC_DMA_TX_0 Format");
my_data->current_backend_cfg[DEFAULT_CODEC_TX_BACKEND].samplerate_mixer_ctl =
@@ -6278,9 +6295,15 @@
bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
ALOGD("%s:becf: afe: reset to default bitwidth %d", __func__, bit_width);
}
- sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
- ALOGD("%s:becf: afe: playback on codec device not supporting native playback set "
+ /*
+ * In case of CSRA speaker out, all sample rates are supported, so
+ * check platform here
+ */
+ if (platform_spkr_use_default_sample_rate(adev->platform)) {
+ 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__);
+ }
}
if (backend_idx == USB_AUDIO_RX_BACKEND) {
@@ -6951,6 +6974,40 @@
channel_map[6] = PCM_CHANNEL_LS;
channel_map[7] = PCM_CHANNEL_RS;
break;
+ case 12:
+ /* AUDIO_CHANNEL_OUT_7POINT1POINT4 */
+ channel_map[0] = PCM_CHANNEL_FL;
+ channel_map[1] = PCM_CHANNEL_FR;
+ channel_map[2] = PCM_CHANNEL_FC;
+ channel_map[3] = PCM_CHANNEL_LFE;
+ channel_map[4] = PCM_CHANNEL_LB;
+ channel_map[5] = PCM_CHANNEL_RB;
+ channel_map[6] = PCM_CHANNEL_LS;
+ channel_map[7] = PCM_CHANNEL_RS;
+ channel_map[8] = PCM_CHANNEL_TFL;
+ channel_map[9] = PCM_CHANNEL_TFR;
+ channel_map[10] = PCM_CHANNEL_TSL;
+ channel_map[11] = PCM_CHANNEL_TSR;
+ break;
+ case 16:
+ /* 16 channels */
+ channel_map[0] = PCM_CHANNEL_FL;
+ channel_map[1] = PCM_CHANNEL_FR;
+ channel_map[2] = PCM_CHANNEL_FC;
+ channel_map[3] = PCM_CHANNEL_LFE;
+ channel_map[4] = PCM_CHANNEL_LB;
+ channel_map[5] = PCM_CHANNEL_RB;
+ channel_map[6] = PCM_CHANNEL_LS;
+ channel_map[7] = PCM_CHANNEL_RS;
+ channel_map[8] = PCM_CHANNEL_TFL;
+ channel_map[9] = PCM_CHANNEL_TFR;
+ channel_map[10] = PCM_CHANNEL_TSL;
+ channel_map[11] = PCM_CHANNEL_TSR;
+ channel_map[12] = PCM_CHANNEL_FLC;
+ channel_map[13] = PCM_CHANNEL_FRC;
+ channel_map[14] = PCM_CHANNEL_RLC;
+ channel_map[15] = PCM_CHANNEL_RRC;
+ break;
default:
ALOGE("unsupported channels %d for setting channel map", channels);
return -1;
@@ -7075,12 +7132,21 @@
struct mixer_ctl *ctl;
char mixer_ctl_name[44] = {0}; // max length of name is 44 as defined
int ret;
- unsigned int i;
- long set_values[FCC_8] = {0};
+ unsigned int i=0, n=0;
+ long set_values[AUDIO_MAX_DSP_CHANNELS];
struct platform_data *my_data = (struct platform_data *)platform;
struct audio_device *adev = my_data->adev;
ALOGV("%s channel_count:%d",__func__, ch_count);
- if (NULL == ch_map || (ch_count < 1) || (ch_count > FCC_8)) {
+
+ /*
+ * FIXME:
+ * Currently the channel mask in audio.h is limited to 30 channels,
+ * (=AUDIO_CHANNEL_COUNT_MAX), whereas the mixer controls already
+ * allow up to AUDIO_MAX_DSP_CHANNELS channels as per final requirement.
+ * Until channel mask definition is not changed from a uint32_t value
+ * to something else, a sanity check is needed here.
+ */
+ if (NULL == ch_map || (ch_count < 1) || (ch_count > AUDIO_CHANNEL_COUNT_MAX)) {
ALOGE("%s: Invalid channel mapping or channel count value", __func__);
return -EINVAL;
}
@@ -7098,12 +7164,34 @@
ALOGD("%s mixer_ctl_name:%s", __func__, mixer_ctl_name);
ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+
if (!ctl) {
ALOGE("%s: Could not get ctl for mixer cmd - %s",
__func__, mixer_ctl_name);
return -EINVAL;
}
- for (i = 0; i < (unsigned int)ch_count; i++) {
+
+ /* find out how many values the control can set */
+ n = mixer_ctl_get_num_values(ctl);
+
+ if (n != ch_count)
+ ALOGV("%s chcnt %d != mixerctl elem size %d",__func__, ch_count, n);
+
+ if (n < ch_count) {
+ ALOGE("%s chcnt %d > mixerctl elem size %d",__func__, ch_count, n);
+ return -EINVAL;
+ }
+
+ if (n > AUDIO_MAX_DSP_CHANNELS) {
+ ALOGE("%s mixerctl elem size %d > AUDIO_MAX_DSP_CHANNELS %d",__func__, n, AUDIO_MAX_DSP_CHANNELS);
+ return -EINVAL;
+ }
+
+ /* initialize all set_values to zero */
+ memset (set_values, 0, sizeof(set_values));
+
+ /* copy only as many values as corresponding mixer_ctrl allows */
+ for (i = 0; i < ch_count; i++) {
set_values[i] = ch_map[i];
}
@@ -7111,7 +7199,8 @@
set_values[0], set_values[1], set_values[2], set_values[3], set_values[4],
set_values[5], set_values[6], set_values[7], ch_count);
- ret = mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+ ret = mixer_ctl_set_array(ctl, set_values, n);
+
if (ret < 0) {
ALOGE("%s: Could not set ctl, error:%d ch_count:%d",
__func__, ret, ch_count);
@@ -7276,6 +7365,11 @@
return 0;
}
+bool platform_spkr_use_default_sample_rate(void *platform) {
+ struct platform_data *my_data = (struct platform_data *)platform;
+ return my_data->use_sprk_default_sample_rate;
+}
+
int platform_set_edid_channels_configuration(void *platform, int channels) {
struct platform_data *my_data = (struct platform_data *)platform;
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index c8ddaec..e1f433c 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -280,6 +280,8 @@
#define AUDIO_PARAMETER_KEY_TRUE_32_BIT "true_32_bit"
+#define AUDIO_MAX_DSP_CHANNELS 32
+
#define ALL_SESSION_VSID 0xFFFFFFFF
#define DEFAULT_MUTE_RAMP_DURATION_MS 20
#define DEFAULT_VOLUME_RAMP_DURATION_MS 20
diff --git a/hal/platform_api.h b/hal/platform_api.h
old mode 100755
new mode 100644
index 09c69de..1563673
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -218,6 +218,7 @@
snd_device_t snd_device,
struct mix_matrix_params mm_params);
int platform_set_edid_channels_configuration(void *platform, int channels);
+bool platform_spkr_use_default_sample_rate(void *platform);
unsigned char platform_map_to_edid_format(int format);
bool platform_is_edid_supported_format(void *platform, int format);
bool platform_is_edid_supported_sample_rate(void *platform, int sample_rate);