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;
+}
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 8b44cd5..14b3563 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -318,6 +318,15 @@
[USECASE_AUDIO_PLAYBACK_VOIP] = "audio-playback-voip",
[USECASE_AUDIO_RECORD_VOIP] = "audio-record-voip",
+ /* For Interactive Audio Streams */
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM1] = "audio-interactive-stream1",
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM2] = "audio-interactive-stream2",
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM3] = "audio-interactive-stream3",
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM4] = "audio-interactive-stream4",
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM5] = "audio-interactive-stream5",
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM6] = "audio-interactive-stream6",
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM7] = "audio-interactive-stream7",
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM8] = "audio-interactive-stream8",
};
static const audio_usecase_t offload_usecases[] = {
@@ -332,6 +341,17 @@
USECASE_AUDIO_PLAYBACK_OFFLOAD9,
};
+static const audio_usecase_t interactive_usecases[] = {
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM1,
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM2,
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM3,
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM4,
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM5,
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM6,
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM7,
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM8,
+};
+
#define STRING_TO_ENUM(string) { #string, string }
struct string_to_enum {
@@ -2149,6 +2169,50 @@
}
}
+bool is_interactive_usecase(audio_usecase_t uc_id)
+{
+ unsigned int i;
+ for (i = 0; i < sizeof(interactive_usecases)/sizeof(interactive_usecases[0]); i++) {
+ if (uc_id == interactive_usecases[i])
+ return true;
+ }
+ return false;
+}
+
+static audio_usecase_t get_interactive_usecase(struct audio_device *adev)
+{
+ audio_usecase_t ret_uc = USECASE_INVALID;
+ unsigned int intract_uc_index;
+ unsigned int num_usecase = sizeof(interactive_usecases)/sizeof(interactive_usecases[0]);
+
+ ALOGV("%s: num_usecase: %d", __func__, num_usecase);
+ for (intract_uc_index = 0; intract_uc_index < num_usecase; intract_uc_index++) {
+ if (!(adev->interactive_usecase_state & (0x1 << intract_uc_index))) {
+ adev->interactive_usecase_state |= 0x1 << intract_uc_index;
+ ret_uc = interactive_usecases[intract_uc_index];
+ break;
+ }
+ }
+
+ ALOGV("%s: Interactive usecase is %d", __func__, ret_uc);
+ return ret_uc;
+}
+
+static void free_interactive_usecase(struct audio_device *adev,
+ audio_usecase_t uc_id)
+{
+ unsigned int interact_uc_index;
+ unsigned int num_usecase = sizeof(interactive_usecases)/sizeof(interactive_usecases[0]);
+
+ for (interact_uc_index = 0; interact_uc_index < num_usecase; interact_uc_index++) {
+ if (interactive_usecases[interact_uc_index] == uc_id) {
+ adev->interactive_usecase_state &= ~(0x1 << interact_uc_index);
+ break;
+ }
+ }
+ ALOGV("%s: free Interactive usecase %d", __func__, uc_id);
+}
+
bool is_offload_usecase(audio_usecase_t uc_id)
{
unsigned int i;
@@ -2814,7 +2878,9 @@
{
struct stream_out *out = (struct stream_out *)stream;
- if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+ if (is_interactive_usecase(out->usecase)) {
+ return out->config.period_size;
+ } else if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
if (out->flags & AUDIO_OUTPUT_FLAG_TIMESTAMP)
return out->compr_config.fragment_size - sizeof(struct snd_codec_metadata);
else
@@ -5180,7 +5246,10 @@
channels = audio_channel_count_from_out_mask(out->channel_mask);
- if (out->flags & AUDIO_OUTPUT_FLAG_RAW) {
+ if (out->flags & AUDIO_OUTPUT_FLAG_INTERACTIVE) {
+ out->usecase = get_interactive_usecase(adev);
+ out->config = pcm_config_low_latency;
+ } else if (out->flags & AUDIO_OUTPUT_FLAG_RAW) {
out->usecase = USECASE_AUDIO_PLAYBACK_ULL;
out->realtime = may_use_noirq_mode(adev, USECASE_AUDIO_PLAYBACK_ULL,
out->flags);
@@ -5411,6 +5480,9 @@
out->a2dp_compress_mute = false;
+ if (is_interactive_usecase(out->usecase))
+ free_interactive_usecase(adev, out->usecase);
+
if (out->convert_buffer != NULL) {
free(out->convert_buffer);
out->convert_buffer = NULL;
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 8228f3b..fec2400 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -170,6 +170,15 @@
USECASE_AUDIO_PLAYBACK_EXT_DISP_SILENCE,
USECASE_AUDIO_TRANSCODE_LOOPBACK,
+
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM1,
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM2,
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM3,
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM4,
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM5,
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM6,
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM7,
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM8,
AUDIO_USECASE_MAX
};
@@ -312,6 +321,8 @@
char pm_qos_mixer_path[MAX_MIXER_PATH_LEN];
int dynamic_pm_qos_enabled;
+ mix_matrix_params_t pan_scale_params;
+ mix_matrix_params_t downmix_params;
};
struct stream_in {
@@ -484,6 +495,7 @@
bool vr_audio_mode_enabled;
bool bt_sco_on;
struct audio_device_config_param *device_cfg_params;
+ unsigned int interactive_usecase_state;
};
int select_devices(struct audio_device *adev,
@@ -526,6 +538,8 @@
void adev_close_output_stream(struct audio_hw_device *dev __unused,
struct audio_stream_out *stream);
+bool is_interactive_usecase(audio_usecase_t uc_id);
+
#define LITERAL_TO_STRING(x) #x
#define CHECK(condition) LOG_ALWAYS_FATAL_IF(!(condition), "%s",\
__FILE__ ":" LITERAL_TO_STRING(__LINE__)\
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 7778b2b..3e71527 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -377,6 +377,23 @@
[USECASE_AUDIO_PLAYBACK_VOIP] = {AUDIO_PLAYBACK_VOIP_PCM_DEVICE, AUDIO_PLAYBACK_VOIP_PCM_DEVICE},
[USECASE_AUDIO_RECORD_VOIP] = {AUDIO_RECORD_VOIP_PCM_DEVICE, AUDIO_RECORD_VOIP_PCM_DEVICE},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM1] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE1, PLAYBACK_INTERACTIVE_STRM_DEVICE1},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM2] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE2, PLAYBACK_INTERACTIVE_STRM_DEVICE2},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM3] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE3, PLAYBACK_INTERACTIVE_STRM_DEVICE3},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM4] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE4, PLAYBACK_INTERACTIVE_STRM_DEVICE4},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM5] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE5, PLAYBACK_INTERACTIVE_STRM_DEVICE5},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM6] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE6, PLAYBACK_INTERACTIVE_STRM_DEVICE6},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM7] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE7, PLAYBACK_INTERACTIVE_STRM_DEVICE7},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM8] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE8, PLAYBACK_INTERACTIVE_STRM_DEVICE8},
+
};
/* Array to store sound devices */
@@ -6174,6 +6191,147 @@
*length = msm_be_id_array_len;
}
+int platform_set_stream_pan_scale_params(void *platform,
+ int snd_id,
+ struct mix_matrix_params mm_params)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+ struct mixer_ctl *ctl = NULL;
+ char mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = {0};
+ int ret = 0;
+ int iter_i = 0;
+ int iter_j = 0;
+ int length = 0;
+ int pan_scale_data[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
+
+ if (sizeof(mm_params) > MAX_LENGTH_MIXER_CONTROL_IN_INT) {
+ ret = -EINVAL;
+ goto end;
+ }
+
+ snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
+ "Audio Stream %d Pan Scale Control", snd_id);
+ 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);
+ ret = -EINVAL;
+ goto end;
+ }
+ pan_scale_data[length++] = mm_params.num_output_channels;
+ pan_scale_data[length++] = mm_params.num_input_channels;
+
+ pan_scale_data[length++] = mm_params.has_output_channel_map;
+ if (mm_params.has_output_channel_map &&
+ mm_params.num_output_channels <= MAX_CHANNELS_SUPPORTED &&
+ mm_params.num_output_channels > 0)
+ for (iter_i = 0; iter_i < mm_params.num_output_channels; iter_i++)
+ pan_scale_data[length++] = mm_params.output_channel_map[iter_i];
+ else {
+ ret = -EINVAL;
+ goto end;
+ }
+
+ pan_scale_data[length++] = mm_params.has_input_channel_map;
+ if (mm_params.has_input_channel_map &&
+ mm_params.num_input_channels <= MAX_CHANNELS_SUPPORTED &&
+ mm_params.num_input_channels > 0)
+ for (iter_i = 0; iter_i < mm_params.num_input_channels; iter_i++)
+ pan_scale_data[length++] = mm_params.input_channel_map[iter_i];
+ else {
+ ret = -EINVAL;
+ goto end;
+ }
+
+ pan_scale_data[length++] = mm_params.has_mixer_coeffs;
+ if (mm_params.has_mixer_coeffs)
+ for (iter_i = 0; iter_i < mm_params.num_output_channels; iter_i++)
+ for (iter_j = 0; iter_j < mm_params.num_input_channels; iter_j++)
+ pan_scale_data[length++] =
+ mm_params.mixer_coeffs[iter_i][iter_j];
+
+ ret = mixer_ctl_set_array(ctl, pan_scale_data, length);
+end:
+ return ret;
+}
+
+int platform_set_stream_downmix_params(void *platform,
+ int snd_id,
+ snd_device_t snd_device,
+ struct mix_matrix_params mm_params)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+ struct mixer_ctl *ctl;
+ char mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = {0};
+ int downmix_param_data[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
+ int ret = 0;
+ int iter_i = 0;
+ int iter_j = 0;
+ int length = 0;
+ int be_idx = 0;
+
+ if ((sizeof(mm_params) +
+ sizeof(be_idx)) >
+ MAX_LENGTH_MIXER_CONTROL_IN_INT) {
+ ret = -EINVAL;
+ goto end;
+ }
+
+ snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
+ "Audio Device %d Downmix Control", snd_id);
+ 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);
+ ret = -EINVAL;
+ goto end;
+ }
+
+ be_idx = platform_get_snd_device_backend_index(snd_device);
+ downmix_param_data[length] = be_idx;
+ downmix_param_data[length++] = mm_params.num_output_channels;
+ downmix_param_data[length++] = mm_params.num_input_channels;
+
+ downmix_param_data[length++] = mm_params.has_output_channel_map;
+ if (mm_params.has_output_channel_map &&
+ mm_params.num_output_channels <= MAX_CHANNELS_SUPPORTED &&
+ mm_params.num_output_channels > 0)
+ for (iter_i = 0; iter_i < mm_params.num_output_channels; iter_i++)
+ downmix_param_data[length++] = mm_params.output_channel_map[iter_i];
+ else {
+ ret = -EINVAL;
+ goto end;
+ }
+
+ downmix_param_data[length++] = mm_params.has_input_channel_map;
+ if (mm_params.has_input_channel_map &&
+ mm_params.num_input_channels <= MAX_CHANNELS_SUPPORTED &&
+ mm_params.num_input_channels > 0)
+ for (iter_i = 0; iter_i < mm_params.num_input_channels; iter_i++)
+ downmix_param_data[length++] = mm_params.input_channel_map[iter_i];
+ else {
+ ret = -EINVAL;
+ goto end;
+ }
+
+ downmix_param_data[length++] = mm_params.has_mixer_coeffs;
+ if (mm_params.has_mixer_coeffs)
+ for (iter_i = 0; iter_i < mm_params.num_output_channels; iter_i++)
+ for (iter_j = 0; iter_j < mm_params.num_input_channels; iter_j++)
+ downmix_param_data[length++] =
+ mm_params.mixer_coeffs[iter_i][iter_j];
+
+ ret = mixer_ctl_set_array(ctl, downmix_param_data, length);
+end:
+ return ret;
+}
+
int platform_set_stream_channel_map(void *platform, audio_channel_mask_t channel_mask,
int snd_id, uint8_t *input_channel_map)
{
diff --git a/hal/msm8916/platform.h b/hal/msm8916/platform.h
index 7a950a8..30ae2c7 100644
--- a/hal/msm8916/platform.h
+++ b/hal/msm8916/platform.h
@@ -359,6 +359,15 @@
#define TRANSCODE_LOOPBACK_RX_DEV_ID 43
#define TRANSCODE_LOOPBACK_TX_DEV_ID 44
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE1 0
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE2 1
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE3 27
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE4 45
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE5 46
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE6 47
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE7 48
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE8 49
+
#define PLATFORM_MAX_MIC_COUNT "input_mic_max_count"
#define PLATFORM_DEFAULT_MIC_COUNT 2
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 1d787d0..6c1ab76 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -355,6 +355,22 @@
[USECASE_AUDIO_PLAYBACK_VOIP] = {AUDIO_PLAYBACK_VOIP_PCM_DEVICE, AUDIO_PLAYBACK_VOIP_PCM_DEVICE},
[USECASE_AUDIO_RECORD_VOIP] = {AUDIO_RECORD_VOIP_PCM_DEVICE, AUDIO_RECORD_VOIP_PCM_DEVICE},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM1] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE1, PLAYBACK_INTERACTIVE_STRM_DEVICE1},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM2] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE2, PLAYBACK_INTERACTIVE_STRM_DEVICE2},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM3] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE3, PLAYBACK_INTERACTIVE_STRM_DEVICE3},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM4] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE4, PLAYBACK_INTERACTIVE_STRM_DEVICE4},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM5] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE5, PLAYBACK_INTERACTIVE_STRM_DEVICE5},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM6] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE6, PLAYBACK_INTERACTIVE_STRM_DEVICE6},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM7] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE7, PLAYBACK_INTERACTIVE_STRM_DEVICE7},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM8] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE8, PLAYBACK_INTERACTIVE_STRM_DEVICE8},
};
@@ -6018,6 +6034,145 @@
*length = msm_be_id_array_len;
}
+int platform_set_stream_pan_scale_params(void *platform,
+ int snd_id,
+ struct mix_matrix_params mm_params)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+ struct mixer_ctl *ctl = NULL;
+ char mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = {0};
+ int ret = 0;
+ int iter_i = 0;
+ int iter_j = 0;
+ int length = 0;
+ int pan_scale_data[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
+
+ if (sizeof(mm_params) > MAX_LENGTH_MIXER_CONTROL_IN_INT) {
+ ret = -EINVAL;
+ goto end;
+ }
+
+ snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
+ "Audio Stream %d Pan Scale Control", snd_id);
+ 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);
+ ret = -EINVAL;
+ goto end;
+ }
+ pan_scale_data[length++] = mm_params.num_output_channels;
+ pan_scale_data[length++] = mm_params.num_input_channels;
+
+ pan_scale_data[length++] = mm_params.has_output_channel_map;
+ if (mm_params.has_output_channel_map &&
+ mm_params.num_output_channels <= MAX_CHANNELS_SUPPORTED &&
+ mm_params.num_output_channels > 0)
+ for (iter_i = 0; iter_i < mm_params.num_output_channels; iter_i++)
+ pan_scale_data[length++] = mm_params.output_channel_map[iter_i];
+ else {
+ ret = -EINVAL;
+ goto end;
+ }
+
+ pan_scale_data[length++] = mm_params.has_input_channel_map;
+ if (mm_params.has_input_channel_map &&
+ mm_params.num_input_channels <= MAX_CHANNELS_SUPPORTED &&
+ mm_params.num_input_channels > 0)
+ for (iter_i = 0; iter_i < mm_params.num_input_channels; iter_i++)
+ pan_scale_data[length++] = mm_params.input_channel_map[iter_i];
+ else {
+ ret = -EINVAL;
+ goto end;
+ }
+ pan_scale_data[length++] = mm_params.has_mixer_coeffs;
+ if (mm_params.has_mixer_coeffs)
+ for (iter_i = 0; iter_i < mm_params.num_output_channels; iter_i++)
+ for (iter_j = 0; iter_j < mm_params.num_input_channels; iter_j++)
+ pan_scale_data[length++] =
+ mm_params.mixer_coeffs[iter_i][iter_j];
+
+ ret = mixer_ctl_set_array(ctl, pan_scale_data, length);
+end:
+ return ret;
+}
+
+int platform_set_stream_downmix_params(void *platform,
+ int snd_id,
+ snd_device_t snd_device,
+ struct mix_matrix_params mm_params)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+ struct mixer_ctl *ctl;
+ char mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = {0};
+ int downmix_param_data[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
+ int ret = 0;
+ int iter_i = 0;
+ int iter_j = 0;
+ int length = 0;
+ int be_idx = 0;
+
+ if ((sizeof(mm_params) +
+ sizeof(be_idx)) >
+ MAX_LENGTH_MIXER_CONTROL_IN_INT) {
+ ret = -EINVAL;
+ goto end;
+ }
+
+ snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
+ "Audio Device %d Downmix Control", snd_id);
+ 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);
+ ret = -EINVAL;
+ }
+
+ be_idx = platform_get_snd_device_backend_index(snd_device);
+ downmix_param_data[length] = be_idx;
+ downmix_param_data[length++] = mm_params.num_output_channels;
+ downmix_param_data[length++] = mm_params.num_input_channels;
+
+ downmix_param_data[length++] = mm_params.has_output_channel_map;
+ if (mm_params.has_output_channel_map &&
+ mm_params.num_output_channels <= MAX_CHANNELS_SUPPORTED &&
+ mm_params.num_output_channels > 0)
+ for (iter_i = 0; iter_i < mm_params.num_output_channels; iter_i++)
+ downmix_param_data[length++] = mm_params.output_channel_map[iter_i];
+ else {
+ ret = -EINVAL;
+ goto end;
+ }
+
+ downmix_param_data[length++] = mm_params.has_input_channel_map;
+ if (mm_params.has_input_channel_map &&
+ mm_params.num_input_channels <= MAX_CHANNELS_SUPPORTED &&
+ mm_params.num_input_channels > 0)
+ for (iter_i = 0; iter_i < mm_params.num_input_channels; iter_i++)
+ downmix_param_data[length++] = mm_params.input_channel_map[iter_i];
+ else {
+ ret = -EINVAL;
+ goto end;
+ }
+
+ downmix_param_data[length++] = mm_params.has_mixer_coeffs;
+ if (mm_params.has_mixer_coeffs)
+ for (iter_i = 0; iter_i < mm_params.num_output_channels; iter_i++)
+ for (iter_j = 0; iter_j < mm_params.num_input_channels; iter_j++)
+ downmix_param_data[length++] =
+ mm_params.mixer_coeffs[iter_i][iter_j];
+
+ ret = mixer_ctl_set_array(ctl, downmix_param_data, length);
+end:
+ return ret;
+}
+
int platform_set_stream_channel_map(void *platform, audio_channel_mask_t channel_mask,
int snd_id, uint8_t *input_channel_map)
{
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 33edf75..f4d60c2 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -465,6 +465,15 @@
#define TRANSCODE_LOOPBACK_RX_DEV_ID 43
#define TRANSCODE_LOOPBACK_TX_DEV_ID 44
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE1 0
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE2 1
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE3 27
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE4 45
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE5 46
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE6 47
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE7 48
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE8 49
+
#ifdef PLATFORM_APQ8084
#define FM_RX_VOLUME "Quat MI2S FM RX Volume"
#elif PLATFORM_MSM8994
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 9a34582..6f8cf7e 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -169,6 +169,13 @@
int snd_id);
int platform_set_stream_channel_map(void *platform, audio_channel_mask_t channel_mask,
int snd_id, uint8_t *input_channel_map);
+int platform_set_stream_pan_scale_params(void *platform,
+ int snd_id,
+ struct mix_matrix_params mm_params);
+int platform_set_stream_downmix_params(void *platform,
+ int snd_id,
+ snd_device_t snd_device,
+ struct mix_matrix_params mm_params);
int platform_set_edid_channels_configuration(void *platform, int channels);
unsigned char platform_map_to_edid_format(int format);
bool platform_is_edid_supported_format(void *platform, int format);
diff --git a/qahw_api/inc/qahw_defs.h b/qahw_api/inc/qahw_defs.h
index 23e51cb..fa780bd 100644
--- a/qahw_api/inc/qahw_defs.h
+++ b/qahw_api/inc/qahw_defs.h
@@ -177,6 +177,9 @@
/* Query if a2dp is supported */
#define QAHW_PARAMETER_KEY_HANDLE_A2DP_DEVICE "isA2dpDeviceSupported"
+#define MAX_OUT_CHANNELS 8
+#define MAX_INP_CHANNELS 8
+
/* type of asynchronous write callback events. Mutually exclusive */
typedef enum {
QAHW_STREAM_CBK_EVENT_WRITE_READY, /* non blocking write completed */
@@ -323,6 +326,17 @@
uint16_t channel_allocation;
};
+typedef struct qahw_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];
+} qahw_mix_matrix_params_t;
+
typedef union {
struct qahw_source_tracking_param st_params;
struct qahw_sound_focus_param sf_params;
@@ -335,6 +349,7 @@
struct qahw_adsp_event adsp_event_params;
struct qahw_out_channel_map_param channel_map_params;
struct qahw_device_cfg_param device_cfg_params;
+ struct qahw_mix_matrix_params mix_matrix_params;
} qahw_param_payload;
typedef enum {
@@ -350,7 +365,9 @@
QAHW_PARAM_OUT_CORRECT_DRIFT,
QAHW_PARAM_ADSP_STREAM_CMD,
QAHW_PARAM_OUT_CHANNEL_MAP, /* PARAM to set i/p channel map */
- QAHW_PARAM_DEVICE_CONFIG /* PARAM to set device config */
+ QAHW_PARAM_DEVICE_CONFIG, /* PARAM to set device config */
+ QAHW_PARAM_OUT_MIX_MATRIX_PARAMS,
+ QAHW_PARAM_CH_MIX_MATRIX_PARAMS,
} qahw_param_id;
__END_DECLS
diff --git a/qahw_api/test/qahw_playback_test.c b/qahw_api/test/qahw_playback_test.c
index db189eb..3c986bd 100644
--- a/qahw_api/test/qahw_playback_test.c
+++ b/qahw_api/test/qahw_playback_test.c
@@ -22,6 +22,7 @@
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
+#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
@@ -52,7 +53,7 @@
#define FORMAT_PCM 1
#define WAV_HEADER_LENGTH_MAX 46
-#define MAX_PLAYBACK_STREAMS 3
+#define MAX_PLAYBACK_STREAMS 9
#define PRIMARY_STREAM_INDEX 0
#define KVPAIRS_MAX 100
@@ -194,6 +195,7 @@
pthread_mutex_t write_lock;
pthread_cond_t drain_cond;
pthread_mutex_t drain_lock;
+ bool interactive_strm;
}stream_config;
/* Lock for dual main usecase */
@@ -263,6 +265,9 @@
#define AUDIO_OUTPUT_FLAG_ASSOCIATED 0x8000
#endif
+#ifndef AUDIO_OUTPUT_FLAG_INTERACTIVE
+#define AUDIO_OUTPUT_FLAG_INTERACTIVE 0x40000
+#endif
static bool request_wake_lock(bool wakelock_acquired, bool enable)
{
@@ -683,6 +688,12 @@
fprintf(log_file, "stream %d: after the dual main signal\n", params->stream_index);
pthread_mutex_unlock(&dual_main_lock);
}
+
+ if (params->interactive_strm) {
+ params->flags = AUDIO_OUTPUT_FLAG_INTERACTIVE;
+ fprintf(stderr, "stream %s %d: Interactive stream\n", __func__, params->stream_index);
+ }
+
rc = qahw_open_output_stream(params->qahw_out_hal_handle,
params->handle,
params->output_device,
@@ -1066,7 +1077,10 @@
int rc = 0;
if (!(stream_info->flags_set)) {
- stream_info->flags = AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_NON_BLOCKING;
+ if (stream_info->interactive_strm)
+ stream_info->flags = AUDIO_OUTPUT_FLAG_INTERACTIVE;
+ else
+ stream_info->flags = AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_NON_BLOCKING;
stream_info->flags |= AUDIO_OUTPUT_FLAG_DIRECT;
}
@@ -1458,6 +1472,10 @@
else
direction = PCM_OUT;
+ if (direction == PCM_OUT && stream->interactive_strm) {
+ stream->flags = AUDIO_OUTPUT_FLAG_INTERACTIVE;
+ fprintf(stderr, "stream %d: Interactive stream\n", stream->stream_index);
+ }
fprintf(log_file, "%s: opening %s stream\n", __func__, ((direction == PCM_IN)? "input":"output"));
if (PCM_IN == direction)
@@ -1595,6 +1613,10 @@
printf(" -m --mode - usb operating mode(Device Mode is default)\n");
printf(" 0:Device Mode(host drives the stream and its params and so no need to give params as input)\n");
printf(" 1:Host Mode(user can give stream and stream params via a stream(SD card file) or setup loopback with given params\n");
+ printf(" -O --output-ch-map - output channel map");
+ printf(" -I --input-ch-map - input channel map");
+ printf(" -M --mixer-coeffs - mixer coefficient matrix");
+ printf(" -i --intr-strm - interactive stream indicator");
printf(" \n Examples \n");
printf(" hal_play_test -f /data/Anukoledenadu.wav -> plays Wav stream with default params\n\n");
printf(" hal_play_test -f /data/MateRani.mp3 -t 2 -d 2 -v 0.01 -r 44100 -c 2 \n");
@@ -1852,15 +1874,146 @@
return 1;
}
+audio_channel_mask_t get_channel_mask_for_name(char *name) {
+ audio_channel_mask_t channel_type = AUDIO_CHANNEL_INVALID;
+ if (NULL == name)
+ return channel_type;
+ else if (strncmp(name, "fl", 2) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_FRONT_LEFT;
+ else if (strncmp(name, "fr", 2) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_FRONT_RIGHT;
+ else if (strncmp(name, "fc", 2) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_FRONT_CENTER;
+ else if (strncmp(name, "lfe", 2) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_LOW_FREQUENCY;
+ else if (strncmp(name, "bl", 2) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_BACK_LEFT;
+ else if (strncmp(name, "br", 2) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_BACK_RIGHT;
+ else if (strncmp(name, "flc", 3) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER;
+ else if (strncmp(name, "frc", 3) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER;
+ else if (strncmp(name, "bc", 2) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_BACK_CENTER;
+ else if (strncmp(name, "sl", 2) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_SIDE_LEFT;
+ else if (strncmp(name, "sr", 2) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_SIDE_RIGHT;
+ else if (strncmp(name, "tc", 2) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_TOP_CENTER;
+ else if (strncmp(name, "tfl", 3) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT;
+ else if (strncmp(name, "tfc", 3) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER;
+ else if (strncmp(name, "tfr", 3) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT;
+ else if (strncmp(name, "tbl", 3) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_TOP_BACK_LEFT;
+ else if (strncmp(name, "tbc", 3) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_TOP_BACK_CENTER;
+ else if (strncmp(name, "tbr", 3) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT;
+
+ return channel_type;
+}
+
+int extract_channel_mapping(uint32_t *channel_map, const char * arg_string){
+
+ char *token_string = NULL;
+ char *init_ptr = NULL;
+ char *token = NULL;
+ char *saveptr = NULL;
+
+ if (NULL == channel_map)
+ return -EINVAL;
+
+ if (NULL == arg_string)
+ return EINVAL;
+
+ token_string = strdup(arg_string);
+
+ if(token_string != NULL) {
+ init_ptr = token_string;
+ token = strtok_r(token_string, ",", &saveptr);
+ int index = 0;
+ if (NULL == token)
+ return -EINVAL;
+ else
+ channel_map[index++] = get_channel_mask_for_name(token);
+
+ while(NULL !=(token = strtok_r(NULL,",",&saveptr)))
+ channel_map[index++] = get_channel_mask_for_name(token);
+
+ free(init_ptr);
+ init_ptr = NULL;
+ token_string = NULL;
+ } else
+ return -EINVAL;
+ return 0;
+}
+
+int extract_mixer_coeffs(qahw_mix_matrix_params_t * mm_params, const char * arg_string){
+
+ char *token_string = NULL;
+ char *init_ptr = NULL;
+ char *token = NULL;
+ char *saveptr = NULL;
+ int i = 0;
+ int j = 0;
+
+ if (NULL == mm_params)
+ return -EINVAL;
+
+ if (NULL == arg_string)
+ return -EINVAL;
+
+ token_string = strdup(arg_string);
+
+ if(token_string != NULL) {
+ init_ptr = token_string;
+ token = strtok_r(token_string, ",", &saveptr);
+ int index = 0;
+ if (NULL == token)
+ return -EINVAL;
+ else {
+ mm_params->mixer_coeffs[i][j] = atof(token);
+ j++;
+ }
+
+ while(NULL !=(token = strtok_r(NULL,",",&saveptr))) {
+ if(j == mm_params->num_input_channels) {
+ j=0;
+ i++;
+ }
+ if(i == mm_params->num_output_channels)
+ break;
+ mm_params->mixer_coeffs[i][j++] = atof(token);
+ }
+ free(init_ptr);
+ init_ptr = NULL;
+ token_string = NULL;
+ } else
+ return -EINVAL;
+ return 0;
+}
int main(int argc, char* argv[]) {
char *ba = NULL;
+ char *temp_input_channel_map = NULL;
+ char *temp_output_channel_map = NULL;
+ char *temp_mixer_coeffs = NULL;
qahw_param_payload payload;
qahw_param_id param_id;
struct qahw_aptx_dec_param aptx_params;
+ qahw_mix_matrix_params_t mm_params;
int rc = 0;
int i = 0;
+ int iter_i = 0;
+ int iter_j = 0;
kpi_mode = false;
+ char mixer_ctrl_name[64] = {0};
+ int mixer_ctrl_type = 0;
event_trigger = false;
bool wakelock_acquired = false;
@@ -1899,6 +2052,11 @@
{"effect-preset", required_argument, 0, 'p'},
{"effect-strength", required_argument, 0, 'S'},
{"help", no_argument, 0, 'h'},
+ {"output-ch-map", required_argument, 0, 'O'},
+ {"input-ch-map", required_argument, 0, 'I'},
+ {"mixer-coeffs", required_argument, 0, 'M'},
+ {"num-out-ch", required_argument, 0, 'o'},
+ {"intr-strm", required_argument, 0, 'i'},
{0, 0, 0, 0}
};
@@ -1921,7 +2079,7 @@
while ((opt = getopt_long(argc,
argv,
- "-f:r:c:b:d:s:v:l:t:a:w:k:PD:KF:Ee:A:u:m:S:p:qQh",
+ "-f:r:c:b:d:s:v:l:t:a:w:k:PD:KF:Ee:A:u:m:S:p:qQhI:O:M:o:i:",
long_options,
&option_index)) != -1) {
@@ -1938,6 +2096,7 @@
case 'c':
stream_param[i].channels = atoi(optarg);
stream_param[i].config.channel_mask = audio_channel_out_mask_from_count(atoi(optarg));
+ mm_params.num_input_channels = stream_param[i].channels;
break;
case 'b':
stream_param[i].config.offload_info.bit_width = atoi(optarg);
@@ -1962,6 +2121,9 @@
log_file = stdout;
}
break;
+ case 'i':
+ stream_param[i].interactive_strm = atoi(optarg);
+ break;
case 't':
stream_param[i].filetype = atoi(optarg);
break;
@@ -1972,7 +2134,15 @@
stream_param[i].wma_fmt_type = atoi(optarg);
break;
case 'k':
- stream_param[i].kvpair_values = optarg;
+ get_kvpairs_string(optarg, "mixer_ctrl", mixer_ctrl_name);
+ if(strncmp(mixer_ctrl_name, "downmix", 7) == 0) {
+ mixer_ctrl_type = QAHW_PARAM_CH_MIX_MATRIX_PARAMS;
+ } else if(strncmp(mixer_ctrl_name, "pan_scale", 9) == 0) {
+ mixer_ctrl_type = QAHW_PARAM_OUT_MIX_MATRIX_PARAMS;
+ } else {
+ mixer_ctrl_type = 0;
+ stream_param[i].kvpair_values = optarg;
+ }
break;
case 'D':
proxy_params.acp.file_name = optarg;
@@ -2033,6 +2203,18 @@
case 'm':
stream_param[i].usb_mode = atoi(optarg);
break;
+ case 'O':
+ temp_output_channel_map = strdup(optarg);
+ break;
+ case 'I':
+ temp_input_channel_map = strdup(optarg);
+ break;
+ case 'M':
+ temp_mixer_coeffs = strdup(optarg);
+ break;
+ case 'o':
+ mm_params.num_output_channels = atoi(optarg);
+ break;
case 'h':
usage();
return 0;
@@ -2041,6 +2223,49 @@
}
}
+ /*
+ * Process Input channel map's input
+ */
+ if (NULL != temp_input_channel_map) {
+ extract_channel_mapping(mm_params.input_channel_map, temp_input_channel_map);
+ mm_params.has_input_channel_map = 1;
+ fprintf(log_file, "\nInput channel mapping: ");
+ for (iter_i= 0; iter_i < mm_params.num_input_channels; iter_i++) {
+ fprintf(log_file, "0x%x, ", mm_params.input_channel_map[iter_i]);
+ }
+ free(temp_input_channel_map);
+ temp_input_channel_map = NULL;
+ }
+
+ /*
+ * Process Output channel map's input
+ */
+ if (NULL != temp_output_channel_map) {
+ extract_channel_mapping(mm_params.output_channel_map, temp_output_channel_map);
+ mm_params.has_output_channel_map = 1;
+ fprintf(log_file, "\nOutput channel mapping: ");
+ for (iter_i = 0; iter_i < mm_params.num_output_channels; iter_i++)
+ fprintf(log_file, "0x%x, ", mm_params.output_channel_map[iter_i]);
+
+ free(temp_output_channel_map);
+ temp_output_channel_map = NULL;
+ }
+
+ /*
+ * Process mixer-coeffs input
+ */
+ if (NULL != temp_mixer_coeffs) {
+ extract_mixer_coeffs(&mm_params, temp_mixer_coeffs);
+ mm_params.has_mixer_coeffs = 1;
+ fprintf(log_file, "\nmixer coeffs:\n");
+ for (iter_i = 0; iter_i < mm_params.num_output_channels; iter_i++){
+ for (iter_j = 0; iter_j < mm_params.num_input_channels; iter_j++){
+ fprintf(log_file, "%.2f ",mm_params.mixer_coeffs[iter_i][iter_j]);
+ }
+ fprintf(log_file, "\n");
+ }
+ }
+
wakelock_acquired = request_wake_lock(wakelock_acquired, true);
num_of_streams = i+1;
/* Caution: Below ADL log shouldnt be altered without notifying automation APT since it used
@@ -2085,7 +2310,7 @@
for (i = 0; i < num_of_streams; i++) {
stream = &stream_param[i];
- if ((kpi_mode == false) &&
+ if ((kpi_mode == false) &&
(AUDIO_DEVICE_NONE == stream->input_device)){
if (stream_param[PRIMARY_STREAM_INDEX].filename == nullptr) {
fprintf(log_file, "Primary file name is must for non kpi-mode\n");
@@ -2189,7 +2414,6 @@
fprintf(log_file, "stream %d: play_later = %d\n", i, stream_param[i].play_later);
}
-
rc = pthread_create(&playback_thread[i], NULL, start_stream_playback, (void *)&stream_param[i]);
if (rc) {
fprintf(log_file, "stream %d: failed to create thread\n", stream->stream_index);
@@ -2198,7 +2422,23 @@
}
thread_active[i] = true;
-
+ usleep(500000); //Wait until stream is created
+ if(mixer_ctrl_type == QAHW_PARAM_OUT_MIX_MATRIX_PARAMS) {
+ payload = (qahw_param_payload) mm_params;
+ param_id = QAHW_PARAM_OUT_MIX_MATRIX_PARAMS;
+ rc = qahw_out_set_param_data(stream->out_handle, param_id, &payload);
+ if (rc != 0) {
+ fprintf(log_file, "QAHW_PARAM_OUT_MIX_MATRIX_PARAMS could not be sent!\n");
+ }
+ }
+ if(mixer_ctrl_type == QAHW_PARAM_CH_MIX_MATRIX_PARAMS) {
+ payload = (qahw_param_payload) mm_params;
+ param_id = QAHW_PARAM_CH_MIX_MATRIX_PARAMS;
+ rc = qahw_out_set_param_data(stream->out_handle, param_id, &payload);
+ if (rc != 0) {
+ fprintf(log_file, "QAHW_PARAM_CH_MIX_MATRIX_PARAMS could not be sent!\n");
+ }
+ }
}
exit: