Merge "hal: Support Multichannel Speaker playback"
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 b265ce8..ca3dbd8 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 =
@@ -6281,9 +6298,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) {
@@ -6954,6 +6977,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;
@@ -7078,12 +7135,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;
     }
@@ -7101,12 +7167,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];
     }
 
@@ -7114,7 +7202,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);
@@ -7279,6 +7368,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);