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/audio_defs.h b/hal/audio_extn/audio_defs.h
index dfe8c61..4e5f4d8 100644
--- a/hal/audio_extn/audio_defs.h
+++ b/hal/audio_extn/audio_defs.h
@@ -236,6 +236,17 @@
    struct audio_device_cfg_param dev_cfg_params;
 };
 
+typedef struct mix_matrix_params {
+    uint16_t num_output_channels;
+    uint16_t num_input_channels;
+    uint8_t has_output_channel_map;
+    uint32_t output_channel_map[AUDIO_CHANNEL_COUNT_MAX];
+    uint8_t has_input_channel_map;
+    uint32_t input_channel_map[AUDIO_CHANNEL_COUNT_MAX];
+    uint8_t has_mixer_coeffs;
+    float mixer_coeffs[AUDIO_CHANNEL_COUNT_MAX][AUDIO_CHANNEL_COUNT_MAX];
+} mix_matrix_params_t;
+
 typedef union {
     struct source_tracking_param st_params;
     struct sound_focus_param sf_params;
@@ -248,6 +259,7 @@
     struct audio_adsp_event adsp_event_params;
     struct audio_out_channel_map_param channel_map_param;
     struct audio_device_cfg_param device_cfg;
+    struct mix_matrix_params mm_params;
 } audio_extn_param_payload;
 
 typedef enum {
@@ -264,7 +276,11 @@
     AUDIO_EXTN_PARAM_ADSP_STREAM_CMD,
     /* param to set input channel map for playback stream */
     AUDIO_EXTN_PARAM_OUT_CHANNEL_MAP,
-    AUDIO_EXTN_PARAM_DEVICE_CONFIG
+    AUDIO_EXTN_PARAM_DEVICE_CONFIG,
+    /* Pan/scale params to be set on ASM */
+    AUDIO_EXTN_PARAM_OUT_MIX_MATRIX_PARAMS,
+    /* Downmix params to be set on ADM */
+    AUDIO_EXTN_PARAM_CH_MIX_MATRIX_PARAMS
 } audio_extn_param_id;
 
 #endif /* AUDIO_DEFS_H */
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index 072444e..84de66f 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -1379,6 +1379,14 @@
             ret = audio_extn_utils_set_channel_map(out,
                     (struct audio_out_channel_map_param *)(payload));
             break;
+        case AUDIO_EXTN_PARAM_OUT_MIX_MATRIX_PARAMS:
+            ret = audio_extn_utils_set_pan_scale_params(out,
+                    (struct mix_matrix_params *)(payload));
+            break;
+        case AUDIO_EXTN_PARAM_CH_MIX_MATRIX_PARAMS:
+            ret = audio_extn_utils_set_downmix_params(out,
+                    (struct mix_matrix_params *)(payload));
+            break;
         default:
             ALOGE("%s:: unsupported param_id %d", __func__, param_id);
             break;
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index c2a5484..8360703 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -103,6 +103,10 @@
 #define AUDIO_OUTPUT_FLAG_TIMESTAMP 0x10000
 #endif
 
+#ifndef AUDIO_OUTPUT_FLAG_INTERACTIVE
+#define AUDIO_OUTPUT_FLAG_INTERACTIVE 0x40000
+#endif
+
 #ifndef COMPRESS_METADATA_NEEDED
 #define audio_extn_parse_compress_metadata(out, parms) (0)
 #else
@@ -892,6 +896,12 @@
 int audio_extn_utils_set_channel_map(
             struct stream_out *out,
             struct audio_out_channel_map_param *channel_map_param);
+int audio_extn_utils_set_pan_scale_params(
+            struct stream_out *out,
+            struct mix_matrix_params *mm_params);
+int audio_extn_utils_set_downmix_params(
+            struct stream_out *out,
+            struct mix_matrix_params *mm_params);
 #ifdef AUDIO_HW_LOOPBACK_ENABLED
 /* API to create audio patch */
 int audio_extn_hw_loopback_create_audio_patch(struct audio_hw_device *dev,
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;
+}