hal: Adding Pan-Scale, downmix mixer control support.

Add support in HAL to send mix matrix params using downmix,
Pan-Scale mixer controls. Add new interactive usecases and
also add support to open and teardown for interactive streams.
Add support in test app for supporting up to 9 concurrent
streams. Add support for mixer matrix params handling.

Change-Id: I0dc5b908ee779b2b2c526a67609c057f591f26e7
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index 9f78a0c..fb1362c 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -102,6 +102,10 @@
 /* ToDo: Check and update a proper value in msec */
 #define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 50
 
+#ifndef MAX_CHANNELS_SUPPORTED
+#define MAX_CHANNELS_SUPPORTED 8
+#endif
+
 struct string_to_enum {
     const char *name;
     uint32_t value;
@@ -122,6 +126,7 @@
     STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH),
     STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_TIMESTAMP),
     STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_VOIP_RX),
+    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_INTERACTIVE),
     STRING_TO_ENUM(AUDIO_INPUT_FLAG_NONE),
     STRING_TO_ENUM(AUDIO_INPUT_FLAG_FAST),
     STRING_TO_ENUM(AUDIO_INPUT_FLAG_HW_HOTWORD),
@@ -821,6 +826,9 @@
     int snd_device = split_snd_device, snd_device_be_idx = -1;
     int32_t sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
     char value[PROPERTY_VALUE_MAX] = {0};
+    struct streams_io_cfg *s_info = NULL;
+    struct listnode *node = NULL;
+    int direct_app_type = 0;
 
     ALOGV("%s: usecase->out_snd_device %s, usecase->in_snd_device %s, split_snd_device %s",
           __func__, platform_get_snd_device_name(usecase->out_snd_device),
@@ -837,6 +845,7 @@
         (usecase->id != USECASE_AUDIO_PLAYBACK_MULTI_CH) &&
         (usecase->id != USECASE_AUDIO_PLAYBACK_ULL) &&
         (usecase->id != USECASE_AUDIO_PLAYBACK_VOIP) &&
+        (!is_interactive_usecase(usecase->id)) &&
         (!is_offload_usecase(usecase->id)) &&
         (usecase->type != PCM_CAPTURE)) {
         ALOGV("%s: a rx/tx/loopback path where app type cfg is not required %d", __func__, usecase->id);
@@ -917,7 +926,18 @@
         }
         sample_rate = usecase->stream.out->app_type_cfg.sample_rate;
 
-        app_type = usecase->stream.out->app_type_cfg.app_type;
+        /* Interactive streams are supported with only direct app type id.
+         * Get Direct profile app type and use it for interactive streams
+         */
+        list_for_each(node, &adev->streams_output_cfg_list) {
+            s_info = node_to_item(node, struct streams_io_cfg, list);
+            if (s_info->flags.out_flags == AUDIO_OUTPUT_FLAG_DIRECT)
+                direct_app_type = s_info->app_type_cfg.app_type;
+        }
+        if (usecase->stream.out->flags == AUDIO_OUTPUT_FLAG_INTERACTIVE)
+            app_type = direct_app_type;
+        else
+            app_type = usecase->stream.out->app_type_cfg.app_type;
         app_type_cfg[len++] = app_type;
         app_type_cfg[len++] = acdb_dev_id;
         if (((usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
@@ -2160,3 +2180,100 @@
 exit:
     return ret;
 }
+
+int audio_extn_utils_set_pan_scale_params(
+            struct stream_out *out,
+            struct mix_matrix_params *mm_params)
+{
+    int ret = -EINVAL, i = 0, j = 0;
+
+    if (mm_params == NULL && out != NULL) {
+        ALOGE("%s:: Invalid mix matrix params", __func__);
+        goto exit;
+    }
+
+    if (mm_params->num_output_channels > MAX_CHANNELS_SUPPORTED ||
+        mm_params->num_output_channels <= 0 ||
+        mm_params->num_input_channels > MAX_CHANNELS_SUPPORTED ||
+        mm_params->num_input_channels <= 0)
+        goto exit;
+
+    out->pan_scale_params.num_output_channels = mm_params->num_output_channels;
+    out->pan_scale_params.num_input_channels = mm_params->num_input_channels;
+    out->pan_scale_params.has_output_channel_map =
+                                        mm_params->has_output_channel_map;
+    for (i = 0; i < mm_params->num_output_channels; i++)
+        out->pan_scale_params.output_channel_map[i] =
+                                         mm_params->output_channel_map[i];
+
+    out->pan_scale_params.has_input_channel_map =
+                                         mm_params->has_input_channel_map;
+    for (i = 0; i < mm_params->num_input_channels; i++)
+        out->pan_scale_params.input_channel_map[i] =
+                                         mm_params->input_channel_map[i];
+
+    out->pan_scale_params.has_mixer_coeffs = mm_params->has_mixer_coeffs;
+    for (i = 0; i < mm_params->num_output_channels; i++)
+        for (j = 0; j < mm_params->num_input_channels; j++) {
+            //Convert the channel coefficient gains in Q14 format
+            out->pan_scale_params.mixer_coeffs[i][j] =
+                               mm_params->mixer_coeffs[i][j] * (2 << 13);
+        }
+
+    ret = platform_set_stream_pan_scale_params(out->dev->platform,
+                                               out->pcm_device_id,
+                                               out->pan_scale_params);
+
+exit:
+    return ret;
+}
+
+int audio_extn_utils_set_downmix_params(
+            struct stream_out *out,
+            struct mix_matrix_params *mm_params)
+{
+    int ret = -EINVAL, i = 0, j = 0;
+    struct audio_usecase *usecase = NULL;
+
+    if (mm_params == NULL && out != NULL) {
+        ALOGE("%s:: Invalid mix matrix params", __func__);
+        goto exit;
+    }
+
+    if (mm_params->num_output_channels > MAX_CHANNELS_SUPPORTED ||
+        mm_params->num_output_channels <= 0 ||
+        mm_params->num_input_channels > MAX_CHANNELS_SUPPORTED ||
+        mm_params->num_input_channels <= 0)
+        goto exit;
+
+    usecase = get_usecase_from_list(out->dev, out->usecase);
+    out->downmix_params.num_output_channels = mm_params->num_output_channels;
+    out->downmix_params.num_input_channels = mm_params->num_input_channels;
+
+    out->downmix_params.has_output_channel_map =
+                                        mm_params->has_output_channel_map;
+    for (i = 0; i < mm_params->num_output_channels; i++) {
+        out->downmix_params.output_channel_map[i] =
+                                          mm_params->output_channel_map[i];
+    }
+
+    out->downmix_params.has_input_channel_map =
+                                        mm_params->has_input_channel_map;
+    for (i = 0; i < mm_params->num_input_channels; i++)
+        out->downmix_params.input_channel_map[i] =
+                                          mm_params->input_channel_map[i];
+
+    out->downmix_params.has_mixer_coeffs = mm_params->has_mixer_coeffs;
+    for (i = 0; i < mm_params->num_output_channels; i++)
+        for (j = 0; j < mm_params->num_input_channels; j++)
+            out->downmix_params.mixer_coeffs[i][j] =
+                               mm_params->mixer_coeffs[i][j];
+
+    ret = platform_set_stream_downmix_params(out->dev->platform,
+                                             out->pcm_device_id,
+                                             usecase->out_snd_device,
+                                             out->downmix_params);
+
+exit:
+    return ret;
+}