audio: hal: Add support for registering adsp events
Add support for AHAL clients to register for adsp events
and receive event callbacks when an event is triggered by adsp.
CRs-Fixed: 2023812
Change-Id: Ie22efee6e859c3d819ed3939e164cb7baebab71b
diff --git a/configure.ac b/configure.ac
index 16544a3..6695b7e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -107,6 +107,7 @@
AM_CONDITIONAL([KEEP_ALIVE], [test x$AUDIO_FEATURE_ENABLED_KEEP_ALIVE = xtrue])
AM_CONDITIONAL([GEF], [test x$AUDIO_FEATURE_ENABLED_GEF_SUPPORT = xtrue])
AM_CONDITIONAL([APTX_DECODER], [test x$AUDIO_FEATURE_ENABLED_APTX_DECODER = xtrue])
+AM_CONDITIONAL([ADSP_HDLR], [test x$AUDIO_FEATURE_ADSP_HDLR_ENABLED = xtrue])
AC_CONFIG_FILES([ \
Makefile \
diff --git a/hal/Android.mk b/hal/Android.mk
index 5dbada0..9a8d27c 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -346,6 +346,11 @@
LOCAL_SRC_FILES += audio_extn/gef.c
endif
+ifeq ($(strip $($AUDIO_FEATURE_ADSP_HDLR_ENABLED)),true)
+ LOCAL_CFLAGS += -DAUDIO_EXTN_ADSP_HDLR_ENABLED
+ LOCAL_SRC_FILES += audio_extn/adsp_hdlr.c
+endif
+
LOCAL_CFLAGS += -Wall -Werror
LOCAL_COPY_HEADERS_TO := mm-audio
diff --git a/hal/Makefile.am b/hal/Makefile.am
index 0c5c65f..cbce291 100644
--- a/hal/Makefile.am
+++ b/hal/Makefile.am
@@ -156,6 +156,11 @@
AM_CFLAGS += -DAFE_PROXY_ENABLED
endif
+if ADSP_HDLR
+AM_CFLAGS += -DAUDIO_EXTN_ADSP_HDLR_ENABLED
+c_sources += audio_extn/adsp_hdlr.c
+endif
+
h_sources = audio_extn/audio_defs.h \
audio_extn/audio_extn.h \
audio_hw.h \
diff --git a/hal/audio_extn/adsp_hdlr.c b/hal/audio_extn/adsp_hdlr.c
new file mode 100644
index 0000000..08313a6
--- /dev/null
+++ b/hal/audio_extn/adsp_hdlr.c
@@ -0,0 +1,637 @@
+/*
+* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define LOG_TAG "audio_adsp_hdlr_event"
+
+/*#define LOG_NDEBUG 0*/
+/*#define VERY_VERY_VERBOSE_LOGGING*/
+#ifdef VERY_VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+#include <pthread.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/resource.h>
+#include <sys/prctl.h>
+#include <cutils/log.h>
+#include <cutils/sched_policy.h>
+#include <system/thread_defs.h>
+
+#include "audio_hw.h"
+#include "audio_defs.h"
+#include "platform.h"
+#include "platform_api.h"
+#include "adsp_hdlr.h"
+
+#define MAX_EVENT_PAYLOAD 512
+#define WAIT_EVENT_POLL_TIMEOUT 50
+
+#define MIXER_MAX_BYTE_LENGTH 512
+
+struct adsp_hdlr_inst {
+ bool binit;
+ struct mixer *mixer;
+};
+
+enum {
+ EVENT_CMD_EXIT, /* event thread exit command loop*/
+ EVENT_CMD_WAIT, /* event thread wait on mixer control */
+ EVENT_CMD_GET /* event thread get param data from mixer */
+};
+
+struct event_cmd {
+ struct listnode list;
+ int opcode;
+};
+
+enum {
+ ADSP_HDLR_STREAM_STATE_OPENED = 0,
+ ADSP_HDLR_STREAM_STATE_EVENT_REGISTERED,
+ ADSP_HDLR_STREAM_STATE_EVENT_DEREGISTERED,
+ ADSP_HDLR_STREAM_STATE_CLOSED
+};
+
+static struct adsp_hdlr_inst *adsp_hdlr_inst = NULL;
+
+static void *event_wait_thread_loop(void *context);
+static void *event_callback_thread_loop(void *context);
+
+struct adsp_hdlr_stream_data {
+ struct adsp_hdlr_stream_cfg config;
+ stream_callback_t client_callback;
+ void *client_cookie;
+ int state;
+
+ pthread_cond_t event_wait_cond;
+ pthread_t event_wait_thread;
+ struct listnode event_wait_cmd_list;
+ pthread_mutex_t event_wait_lock;
+ bool event_wait_thread_active;
+
+ pthread_cond_t event_callback_cond;
+ pthread_t event_callback_thread;
+ struct listnode event_callback_cmd_list;
+ pthread_mutex_t event_callback_lock;
+ bool event_callback_thread_active;
+};
+
+static int send_cmd_event_wait_thread(struct adsp_hdlr_stream_data *stream_data, int opcode)
+{
+ struct event_cmd *cmd = calloc(1, sizeof(*cmd));
+
+ if (!cmd) {
+ ALOGE("Failed to allocate mem for command 0x%x", opcode);
+ return -ENOMEM;
+ }
+
+ ALOGVV("%s %d", __func__, opcode);
+
+ cmd->opcode = opcode;
+
+ pthread_mutex_lock(&stream_data->event_wait_lock);
+ list_add_tail(&stream_data->event_wait_cmd_list, &cmd->list);
+ pthread_cond_signal(&stream_data->event_wait_cond);
+ pthread_mutex_unlock(&stream_data->event_wait_lock);
+
+ return 0;
+}
+
+static int send_cmd_event_callback_thread(struct adsp_hdlr_stream_data *stream_data,
+ int opcode)
+{
+ struct event_cmd *cmd = calloc(1, sizeof(*cmd));
+
+ if (!cmd) {
+ ALOGE("Failed to allocate mem for command 0x%x", opcode);
+ return -ENOMEM;
+ }
+
+ ALOGVV("%s %d", __func__, opcode);
+
+ cmd->opcode = opcode;
+
+ pthread_mutex_lock(&stream_data->event_callback_lock);
+ list_add_tail(&stream_data->event_callback_cmd_list, &cmd->list);
+ pthread_cond_signal(&stream_data->event_callback_cond);
+ pthread_mutex_unlock(&stream_data->event_callback_lock);
+
+ return 0;
+}
+
+static void create_event_wait_thread(struct adsp_hdlr_stream_data *stream_data)
+{
+ pthread_cond_init(&stream_data->event_wait_cond,
+ (const pthread_condattr_t *) NULL);
+ list_init(&stream_data->event_wait_cmd_list);
+ pthread_create(&stream_data->event_wait_thread, (const pthread_attr_t *) NULL,
+ event_wait_thread_loop, stream_data);
+ stream_data->event_wait_thread_active = true;
+}
+
+static void create_event_callback_thread(struct adsp_hdlr_stream_data *stream_data)
+{
+ pthread_cond_init(&stream_data->event_callback_cond,
+ (const pthread_condattr_t *) NULL);
+ list_init(&stream_data->event_callback_cmd_list);
+ pthread_create(&stream_data->event_callback_thread, (const pthread_attr_t *) NULL,
+ event_callback_thread_loop, stream_data);
+ stream_data->event_callback_thread_active = true;
+}
+
+static void destroy_event_wait_thread(struct adsp_hdlr_stream_data *stream_data)
+{
+ send_cmd_event_wait_thread(stream_data, EVENT_CMD_EXIT);
+ pthread_join(stream_data->event_wait_thread, (void **) NULL);
+
+ pthread_mutex_lock(&stream_data->event_wait_lock);
+ pthread_cond_destroy(&stream_data->event_wait_cond);
+ stream_data->event_wait_thread_active = false;
+ pthread_mutex_unlock(&stream_data->event_wait_lock);
+}
+
+static void destroy_event_callback_thread(struct adsp_hdlr_stream_data *stream_data)
+{
+ send_cmd_event_callback_thread(stream_data, EVENT_CMD_EXIT);
+ pthread_join(stream_data->event_callback_thread, (void **) NULL);
+
+ pthread_mutex_lock(&stream_data->event_callback_lock);
+ pthread_cond_destroy(&stream_data->event_callback_cond);
+ stream_data->event_callback_thread_active = false;
+ pthread_mutex_unlock(&stream_data->event_callback_lock);
+}
+
+static void destroy_event_threads(struct adsp_hdlr_stream_data *stream_data)
+{
+ if (stream_data->event_wait_thread_active)
+ destroy_event_wait_thread(stream_data);
+ if (stream_data->event_callback_thread_active)
+ destroy_event_callback_thread(stream_data);
+}
+
+static void *event_wait_thread_loop(void *context)
+{
+ int ret = 0;
+ int opcode = 0;
+ bool wait = false;
+ struct adsp_hdlr_stream_data *stream_data =
+ (struct adsp_hdlr_stream_data *) context;
+ struct adsp_hdlr_stream_cfg *config = &stream_data->config;
+ char mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = {0};
+ struct mixer_ctl *ctl = NULL;
+ struct event_cmd *cmd;
+ struct listnode *node;
+
+ setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
+ set_sched_policy(0, SP_BACKGROUND);
+ prctl(PR_SET_NAME, (unsigned long)"Event Wait", 0, 0, 0);
+
+ ret = snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
+ "ADSP Stream Callback Event %d", config->pcm_device_id);
+ if (ret < 0) {
+ ALOGE("%s: snprintf failed",__func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ctl = mixer_get_ctl_by_name(adsp_hdlr_inst->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s", __func__,
+ mixer_ctl_name);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = mixer_subscribe_events(adsp_hdlr_inst->mixer, 1);
+ if (ret < 0) {
+ ALOGE("%s: Could not subscribe for mixer cmd - %s, ret %d",
+ __func__, mixer_ctl_name, ret);
+ goto done;
+ }
+
+ pthread_mutex_lock(&stream_data->event_wait_lock);
+ while (1) {
+ if (list_empty(&stream_data->event_wait_cmd_list) && !wait) {
+ ALOGVV("%s SLEEPING", __func__);
+ pthread_cond_wait(&stream_data->event_wait_cond, &stream_data->event_wait_lock);
+ ALOGVV("%s RUNNING", __func__);
+ }
+ /* execute command if available */
+ if (!list_empty(&stream_data->event_wait_cmd_list)) {
+ node = list_head(&stream_data->event_wait_cmd_list);
+ list_remove(node);
+ pthread_mutex_unlock(&stream_data->event_wait_lock);
+ cmd = node_to_item(node, struct event_cmd, list);
+ opcode = cmd->opcode;
+ /* wait if no command avialable */
+ } else if (wait)
+ opcode = EVENT_CMD_WAIT;
+ /* check que again and sleep if needed */
+ else
+ continue;
+
+ ALOGVV("%s command received: %d", __func__, opcode);
+ switch(opcode) {
+ case EVENT_CMD_EXIT:
+ free(cmd);
+ goto thread_exit;
+ case EVENT_CMD_WAIT:
+ ret = mixer_wait_event(adsp_hdlr_inst->mixer, WAIT_EVENT_POLL_TIMEOUT);
+ if (ret < 0)
+ ALOGE("%s: mixer_wait_event err! mixer %s, ret = %d",
+ __func__, mixer_ctl_name, ret);
+ else if (ret > 0) {
+ send_cmd_event_callback_thread(stream_data, EVENT_CMD_GET);
+
+ /* Resubscribe to clear flag checked by mixer_wait_event */
+ ret = mixer_subscribe_events(adsp_hdlr_inst->mixer, 0);
+ if (ret < 0) {
+ ALOGE("%s: Could not unsubscribe for mixer cmd - %s, ret %d",
+ __func__, mixer_ctl_name, ret);
+ goto done;
+ }
+ ret = mixer_subscribe_events(adsp_hdlr_inst->mixer, 1);
+ if (ret < 0) {
+ ALOGE("%s: Could not unsubscribe for mixer cmd - %s, ret %d",
+ __func__, mixer_ctl_name, ret);
+ goto done;
+ }
+ }
+ /* Once wait command has been sent continue to wait for
+ events unless something else is in the command que */
+ wait = true;
+ break;
+ default:
+ ALOGE("%s unknown command received: %d", __func__, opcode);
+ break;
+ }
+
+ if (cmd != NULL) {
+ free(cmd);
+ cmd = NULL;
+ }
+ }
+thread_exit:
+ pthread_mutex_lock(&stream_data->event_wait_lock);
+ list_for_each(node, &stream_data->event_wait_cmd_list) {
+ list_remove(node);
+ free(node);
+ }
+ pthread_mutex_unlock(&stream_data->event_wait_lock);
+done:
+ return NULL;
+}
+
+static void *event_callback_thread_loop(void *context)
+{
+ int ret = 0;
+ size_t count = 0;
+ struct adsp_hdlr_stream_data *stream_data =
+ (struct adsp_hdlr_stream_data *)context;
+ struct adsp_hdlr_stream_cfg *config = &stream_data->config;
+ char mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = {0};
+ struct mixer_ctl *ctl = NULL;
+ uint8_t param[MAX_EVENT_PAYLOAD] = {0};
+ struct event_cmd *cmd;
+ struct listnode *node;
+
+ setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
+ set_sched_policy(0, SP_BACKGROUND);
+ prctl(PR_SET_NAME, (unsigned long)"Event Callback", 0, 0, 0);
+
+ ret = snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
+ "ADSP Stream Callback Event %d", config->pcm_device_id);
+ if (ret < 0) {
+ ALOGE("%s: snprintf failed",__func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ctl = mixer_get_ctl_by_name(adsp_hdlr_inst->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s", __func__,
+ mixer_ctl_name);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ pthread_mutex_lock(&stream_data->event_callback_lock);
+ while (1) {
+ if (list_empty(&stream_data->event_callback_cmd_list)) {
+ ALOGVV("%s SLEEPING", __func__);
+ pthread_cond_wait(&stream_data->event_callback_cond,
+ &stream_data->event_callback_lock);
+ ALOGVV("%s RUNNING", __func__);
+ continue;
+ }
+ node = list_head(&stream_data->event_callback_cmd_list);
+ list_remove(node);
+ pthread_mutex_unlock(&stream_data->event_callback_lock);
+ cmd = node_to_item(node, struct event_cmd, list);
+
+ ALOGVV("%s command received: %d", __func__, cmd->opcode);
+ switch(cmd->opcode) {
+ case EVENT_CMD_EXIT:
+ free(cmd);
+ goto thread_exit;
+ case EVENT_CMD_GET:
+ mixer_ctl_update(ctl);
+
+ count = mixer_ctl_get_num_values(ctl);
+ if ((count > MAX_EVENT_PAYLOAD) || (count <= 0)) {
+ ALOGE("%s mixer - %s, count is %d",
+ __func__, mixer_ctl_name, count);
+ break;
+ }
+
+ ret = mixer_ctl_get_array(ctl, param, count);
+ if (ret < 0) {
+ ALOGE("%s: mixer_ctl_get_array failed! mixer - %s, ret = %d",
+ __func__, mixer_ctl_name, ret);
+ break;
+ }
+
+ if (stream_data->client_callback != NULL) {
+ ALOGVV("%s: sending client callback event %d", __func__,
+ AUDIO_EXTN_STREAM_CBK_EVENT_ADSP);
+ stream_data->client_callback((stream_callback_event_t)
+ AUDIO_EXTN_STREAM_CBK_EVENT_ADSP,
+ param,
+ stream_data->client_cookie);
+ }
+ break;
+ default:
+ ALOGE("%s unknown command received: %d", __func__, cmd->opcode);
+ break;
+ }
+ free(cmd);
+ }
+thread_exit:
+ pthread_mutex_lock(&stream_data->event_callback_lock);
+ list_for_each(node, &stream_data->event_callback_cmd_list) {
+ list_remove(node);
+ free(node);
+ }
+ pthread_mutex_unlock(&stream_data->event_callback_lock);
+done:
+ return NULL;
+}
+
+static int adsp_hdlr_stream_deregister_event(
+ struct adsp_hdlr_stream_data *stream_data)
+{
+ destroy_event_threads((struct adsp_hdlr_stream_data *)stream_data);
+ stream_data->state = ADSP_HDLR_STREAM_STATE_EVENT_DEREGISTERED;
+ return 0;
+}
+
+static int adsp_hdlr_stream_register_event(
+ struct adsp_hdlr_stream_data *stream_data,
+ struct audio_adsp_event *param)
+{
+ int ret = 0;
+ char mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = {0};
+ struct mixer_ctl *ctl = NULL;
+ uint8_t payload[AUDIO_MAX_ADSP_STREAM_CMD_PAYLOAD_LEN] = {0};
+ struct adsp_hdlr_stream_cfg *config = &stream_data->config;
+
+ /* check if param size exceeds max size supported by mixer */
+ if (param->payload_length > AUDIO_MAX_ADSP_STREAM_CMD_PAYLOAD_LEN) {
+ ALOGE("%s: Invalid payload_length %d",__func__, param->payload_length);
+ return -EINVAL;
+ }
+
+ ret = snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
+ "ADSP Stream Cmd %d", config->pcm_device_id);
+ if (ret < 0) {
+ ALOGE("%s: snprintf failed",__func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ctl = mixer_get_ctl_by_name(adsp_hdlr_inst->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s", __func__,
+ mixer_ctl_name);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ALOGD("%s: payload_length %d",__func__, param->payload_length);
+
+ /*copy payload size and param */
+ memcpy(payload, ¶m->payload_length,
+ sizeof(param->payload_length));
+ memcpy(payload + sizeof(param->payload_length),
+ param->payload, param->payload_length);
+ ret = mixer_ctl_set_array(ctl, payload,
+ sizeof(param->payload_length) + param->payload_length);
+ if (ret < 0) {
+ ALOGE("%s: Could not set ctl for mixer cmd - %s, ret %d", __func__,
+ mixer_ctl_name, ret);
+ goto done;
+ }
+
+ pthread_mutex_lock(&stream_data->event_wait_lock);
+ if (!stream_data->event_wait_thread_active)
+ create_event_wait_thread(stream_data);
+ pthread_mutex_unlock(&stream_data->event_wait_lock);
+
+ pthread_mutex_lock(&stream_data->event_callback_lock);
+ if (!stream_data->event_callback_thread_active)
+ create_event_callback_thread(stream_data);
+ pthread_mutex_unlock(&stream_data->event_callback_lock);
+
+ send_cmd_event_wait_thread(stream_data, EVENT_CMD_WAIT);
+ stream_data->state = ADSP_HDLR_STREAM_STATE_EVENT_REGISTERED;
+done:
+ return ret;
+}
+
+int audio_extn_adsp_hdlr_stream_set_param(void *handle,
+ adsp_hdlr_cmd_t cmd,
+ void *param)
+{
+ int ret = 0;
+ struct adsp_hdlr_stream_data *stream_data;
+
+ if (handle == NULL) {
+ ALOGE("%s: Invalid handle",__func__);
+ return -EINVAL;
+ }
+
+ stream_data = (struct adsp_hdlr_stream_data *)handle;
+ switch (cmd) {
+ case ADSP_HDLR_STREAM_CMD_REGISTER_EVENT :
+ if (!param) {
+ ret = -EINVAL;
+ ALOGE("%s: Invalid handle",__func__);
+ break;
+ }
+ ret = adsp_hdlr_stream_register_event(stream_data, param);
+ if (ret)
+ ALOGE("%s:adsp_hdlr_stream_register_event failed error %d",
+ __func__, ret);
+ break;
+ case ADSP_HDLR_STREAM_CMD_DEREGISTER_EVENT:
+ ret = adsp_hdlr_stream_deregister_event(stream_data);
+ if (ret)
+ ALOGE("%s:adsp_hdlr_stream_deregister_event failed error %d",
+ __func__, ret);
+ break;
+ default:
+ ret = -EINVAL;
+ ALOGE("%s: Unsupported command %d",__func__, cmd);
+ }
+ return ret;
+}
+
+int audio_extn_adsp_hdlr_stream_set_callback(void *handle,
+ stream_callback_t callback,
+ void *cookie)
+{
+ int ret = 0;
+ struct adsp_hdlr_stream_data *stream_data;
+
+ ALOGV("%s:: handle %p", __func__, handle);
+
+ if (!handle) {
+ ALOGE("%s:Invalid handle", __func__);
+ ret = -EINVAL;
+ } else {
+ stream_data = (struct adsp_hdlr_stream_data *)handle;
+ stream_data->client_callback = callback;
+ stream_data->client_cookie = cookie;
+ }
+ return ret;
+}
+
+int audio_extn_adsp_hdlr_stream_close(void *handle)
+{
+ int ret = 0;
+ struct adsp_hdlr_stream_data *stream_data;
+
+ ALOGV("%s:: handle %p", __func__, handle);
+
+ if (!handle) {
+ ALOGE("%s:Invalid handle", __func__);
+ ret = -EINVAL;
+ } else {
+ stream_data = (struct adsp_hdlr_stream_data *)handle;
+ if (stream_data->state == ADSP_HDLR_STREAM_STATE_EVENT_REGISTERED) {
+ ret = adsp_hdlr_stream_deregister_event(stream_data);
+ if (ret)
+ ALOGE("%s:adsp_hdlr_stream_deregister_event failed error %d",
+ __func__, ret);
+ }
+ stream_data->state = ADSP_HDLR_STREAM_STATE_CLOSED;
+ pthread_mutex_destroy(&stream_data->event_wait_lock);
+ pthread_mutex_destroy(&stream_data->event_wait_lock);
+ free(stream_data);
+ stream_data = NULL;
+ }
+ return ret;
+}
+
+int audio_extn_adsp_hdlr_stream_open(void **handle,
+ struct adsp_hdlr_stream_cfg *config)
+{
+
+ int ret = 0;
+ struct adsp_hdlr_stream_data *stream_data;
+
+ if (!adsp_hdlr_inst) {
+ ALOGE("%s: Not Inited", __func__);
+ return -ENODEV;;
+ }
+
+ if ((!config) || (config->type != PCM_PLAYBACK)) {
+ ALOGE("%s: Invalid config param", __func__);
+ return -EINVAL;
+ }
+
+ ALOGV("%s::pcm_device_id %d, flags %x type %d ", __func__,
+ config->pcm_device_id, config->flags, config->type);
+
+ *handle = NULL;
+
+ stream_data = (struct adsp_hdlr_stream_data *) calloc(1,
+ sizeof(struct adsp_hdlr_stream_data));
+ if (stream_data == NULL) {
+ ret = -ENOMEM;
+ }
+
+ stream_data->config = *config;
+ pthread_mutex_init(&stream_data->event_wait_lock,
+ (const pthread_mutexattr_t *) NULL);
+ pthread_mutex_init(&stream_data->event_callback_lock,
+ (const pthread_mutexattr_t *) NULL);
+ stream_data->state = ADSP_HDLR_STREAM_STATE_OPENED;
+
+ *handle = (void **)stream_data;
+ return ret;
+}
+
+int audio_extn_adsp_hdlr_init(struct mixer *mixer)
+{
+ ALOGV("%s", __func__);
+
+ if (!mixer) {
+ ALOGE("%s: invalid mixer", __func__);
+ return -EINVAL;
+ }
+
+ if (adsp_hdlr_inst) {
+ ALOGD("%s: Already initialized", __func__);
+ return 0;
+ }
+ adsp_hdlr_inst = (struct adsp_hdlr_inst *)calloc(1,
+ sizeof(struct adsp_hdlr_inst *));
+ if (!adsp_hdlr_inst) {
+ ALOGE("%s: calloc failed for adsp_hdlr_inst", __func__);
+ return -EINVAL;
+ }
+ adsp_hdlr_inst->mixer = mixer;
+
+ return 0;
+}
+
+int audio_extn_adsp_hdlr_deinit(void)
+{
+ if (adsp_hdlr_inst) {
+ free(adsp_hdlr_inst);
+ adsp_hdlr_inst = NULL;
+ } else {
+ ALOGD("%s: Already Deinitialized", __func__);
+ }
+ return 0;
+}
+
diff --git a/hal/audio_extn/adsp_hdlr.h b/hal/audio_extn/adsp_hdlr.h
new file mode 100644
index 0000000..7499917
--- /dev/null
+++ b/hal/audio_extn/adsp_hdlr.h
@@ -0,0 +1,65 @@
+/*
+* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef AUDIO_HW_EXTN_ADSP_HDLR_H
+#define AUDIO_HW_EXTN_ADSP_HDLR_H
+
+typedef enum adsp_hdlr_command {
+ ADSP_HDLR_CMD_INVALID = 0,
+ ADSP_HDLR_STREAM_CMD_REGISTER_EVENT,
+ ADSP_HDLR_STREAM_CMD_DEREGISTER_EVENT,
+} adsp_hdlr_cmd_t;
+
+struct adsp_hdlr_stream_cfg {
+ int pcm_device_id;
+ uint32_t flags;
+ usecase_type_t type;
+};
+
+#ifdef AUDIO_EXTN_ADSP_HDLR_ENABLED
+int audio_extn_adsp_hdlr_init(struct mixer *mixer);
+int audio_extn_adsp_hdlr_deinit(void);
+int audio_extn_adsp_hdlr_stream_open(void **handle,
+ struct adsp_hdlr_stream_cfg *config);
+int audio_extn_adsp_hdlr_stream_close(void *handle);
+int audio_extn_adsp_hdlr_stream_set_callback(void *handle,
+ stream_callback_t callback,
+ void *cookie);
+int audio_extn_adsp_hdlr_stream_set_param(void *handle,
+ adsp_hdlr_cmd_t cmd,
+ void *param);
+#else
+#define audio_extn_adsp_hdlr_init(mixer) (0)
+#define audio_extn_adsp_hdlr_deinit() (0)
+#define audio_extn_adsp_hdlr_stream_open(handle,config) (0)
+#define audio_extn_adsp_hdlr_stream_close(handle) (0)
+#define audio_extn_adsp_hdlr_stream_set_callback(handle, callback, cookie) (0)
+#define audio_extn_adsp_hdlr_stream_set_param(handle, cmd, param) (0)
+#endif
+
+#endif
diff --git a/hal/audio_extn/audio_defs.h b/hal/audio_extn/audio_defs.h
index eaf9b06..06b4fb9 100644
--- a/hal/audio_extn/audio_defs.h
+++ b/hal/audio_extn/audio_defs.h
@@ -177,6 +177,25 @@
uint64_t start_delay; /* session start delay in microseconds*/
};
+/* type of asynchronous write callback events. Mutually exclusive
+ * event enums append those defined for stream_callback_event_t in audio.h */
+typedef enum {
+ AUDIO_EXTN_STREAM_CBK_EVENT_ADSP = 0x100 /* callback event from ADSP PP,
+ * corresponding payload will be
+ * sent as is to the client
+ */
+} audio_extn_callback_id;
+
+#define AUDIO_MAX_ADSP_STREAM_CMD_PAYLOAD_LEN 508
+
+/* payload format for HAL parameter
+ * AUDIO_EXTN_PARAM_ADSP_STREAM_CMD
+ */
+struct audio_adsp_event {
+ uint32_t payload_length; /* length in bytes of the payload */
+ void *payload; /* the actual payload */
+};
+
typedef union {
struct source_tracking_param st_params;
struct sound_focus_param sf_params;
@@ -184,6 +203,7 @@
struct audio_avt_device_drift_param drift_params;
struct audio_out_render_window_param render_window_param;
struct audio_out_start_delay_param start_delay;
+ struct audio_adsp_event adsp_event_params;
} audio_extn_param_payload;
typedef enum {
@@ -192,7 +212,8 @@
AUDIO_EXTN_PARAM_APTX_DEC,
AUDIO_EXTN_PARAM_AVT_DEVICE_DRIFT,
AUDIO_EXTN_PARAM_OUT_RENDER_WINDOW, /* PARAM to set render window */
- AUDIO_EXTN_PARAM_OUT_START_DELAY
+ AUDIO_EXTN_PARAM_OUT_START_DELAY,
+ AUDIO_EXTN_PARAM_ADSP_STREAM_CMD
} 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 bc722f8..64c8424 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -48,6 +48,7 @@
#include "audio_hw.h"
#include "audio_extn.h"
+#include "audio_defs.h"
#include "platform.h"
#include "platform_api.h"
#include "edid.h"
@@ -1335,3 +1336,72 @@
}
#endif //APTX_DECODER_ENABLED
+
+int audio_extn_out_set_param_data(struct stream_out *out,
+ audio_extn_param_id param_id,
+ audio_extn_param_payload *payload) {
+ int ret = -EINVAL;
+
+ if (!out || !payload) {
+ ALOGE("%s:: Invalid Param",__func__);
+ return ret;
+ }
+
+ ALOGD("%s: enter: stream (%p) usecase(%d: %s) param_id %d", __func__,
+ out, out->usecase, use_case_table[out->usecase], param_id);
+
+ switch (param_id) {
+ case AUDIO_EXTN_PARAM_OUT_RENDER_WINDOW:
+ ret = audio_extn_utils_compress_set_render_window(out,
+ (struct audio_out_render_window_param *)(payload));
+ break;
+ case AUDIO_EXTN_PARAM_OUT_START_DELAY:
+ ret = audio_extn_utils_compress_set_start_delay(out,
+ (struct audio_out_start_delay_param *)(payload));
+ break;
+ case AUDIO_EXTN_PARAM_ADSP_STREAM_CMD:
+ ret = audio_extn_adsp_hdlr_stream_set_param(out->adsp_hdlr_stream_handle,
+ ADSP_HDLR_STREAM_CMD_REGISTER_EVENT,
+ (void *)&payload->adsp_event_params);
+ break;
+ default:
+ ALOGE("%s:: unsupported param_id %d", __func__, param_id);
+ break;
+ }
+ return ret;
+}
+
+/* API to get playback stream specific config parameters */
+int audio_extn_out_get_param_data(struct stream_out *out,
+ audio_extn_param_id param_id,
+ audio_extn_param_payload *payload)
+{
+ int ret = -EINVAL;
+ struct audio_usecase *uc_info;
+
+ if (!out || !payload) {
+ ALOGE("%s:: Invalid Param",__func__);
+ return ret;
+ }
+
+ switch (param_id) {
+ case AUDIO_EXTN_PARAM_AVT_DEVICE_DRIFT:
+ uc_info = get_usecase_from_list(out->dev, out->usecase);
+ if (uc_info == NULL) {
+ ALOGE("%s: Could not find the usecase (%d) in the list",
+ __func__, out->usecase);
+ ret = -EINVAL;
+ } else {
+ ret = audio_extn_utils_get_avt_device_drift(uc_info,
+ (struct audio_avt_device_drift_param *)payload);
+ if(ret)
+ ALOGE("%s:: avdrift query failed error %d", __func__, ret);
+ }
+ break;
+ default:
+ ALOGE("%s:: unsupported param_id %d", __func__, param_id);
+ break;
+ }
+
+ return ret;
+}
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index ed7f479..bdb039f 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -39,6 +39,7 @@
#define AUDIO_EXTN_H
#include <cutils/str_parms.h>
+#include "adsp_hdlr.h"
#ifndef AFE_PROXY_ENABLED
#define AUDIO_DEVICE_OUT_PROXY 0x40000
@@ -93,6 +94,10 @@
AUDIO_FORMAT_AAC_SUB_HE_V2)
#endif
+#ifndef AUDIO_FORMAT_AC4
+#define AUDIO_FORMAT_AC4 0x23000000UL
+#endif
+
#ifndef AUDIO_OUTPUT_FLAG_TIMESTAMP
#define AUDIO_OUTPUT_FLAG_TIMESTAMP 0x10000
#endif
@@ -673,6 +678,13 @@
const char *address __unused);
int audio_extn_qaf_init(struct audio_device *adev);
int audio_extn_qaf_set_parameters(struct audio_device *adev, struct str_parms *parms);
+int audio_extn_qaf_out_set_param_data(struct stream_out *out,
+ audio_extn_param_id param_id,
+ audio_extn_param_payload *payload);
+int audio_extn_qaf_out_get_param_data(struct stream_out *out,
+ audio_extn_param_id param_id,
+ audio_extn_param_payload *payload);
+bool audio_extn_is_qaf_stream(struct stream_out *out);
#else
#define audio_extn_qaf_is_enabled() (0)
#define audio_extn_qaf_deinit() (0)
@@ -680,6 +692,9 @@
#define audio_extn_qaf_open_output_stream adev_open_output_stream
#define audio_extn_qaf_init(adev) (0)
#define audio_extn_qaf_set_parameters(adev, parms) (0)
+#define audio_extn_qaf_out_set_param_data(out, param_id, payload) (0)
+#define audio_extn_qaf_out_get_param_data(out, param_id, payload) (0)
+#define audio_extn_is_qaf_stream(out) (0)
#endif
#ifdef AUDIO_EXTN_BT_HAL_ENABLED
@@ -828,6 +843,12 @@
static void audio_extn_parse_aptx_dec_bt_addr(char *value);
int audio_extn_set_aptx_dec_params(struct aptx_dec_param *payload);
#endif
+int audio_extn_out_set_param_data(struct stream_out *out,
+ audio_extn_param_id param_id,
+ audio_extn_param_payload *payload);
+int audio_extn_out_get_param_data(struct stream_out *out,
+ audio_extn_param_id param_id,
+ audio_extn_param_payload *payload);
int audio_extn_utils_get_avt_device_drift(
struct audio_usecase *usecase,
diff --git a/hal/audio_extn/qaf.c b/hal/audio_extn/qaf.c
index 5b88274..58b6e08 100644
--- a/hal/audio_extn/qaf.c
+++ b/hal/audio_extn/qaf.c
@@ -42,6 +42,20 @@
#define QAF_DEFAULT_COMPR_AUDIO_HANDLE 1001
#define QAF_DEFAULT_COMPR_PASSTHROUGH_HANDLE 1002
#define QAF_DEFAULT_PASSTHROUGH_HANDLE 1003
+
+#define MAX_QAF_OUT 4
+
+#define QAF_OUT_TRANSCODE_PASSTHROUGH 0 /* transcode passthrough via MS12 */
+#define QAF_DEFAULT_PASSTHROUGH 1 /* passthrough without MS12 */
+#define QAF_OUT_OFFLOAD_MCH 2
+#define QAF_OUT_OFFLOAD 3
+
+#define MAX_QAF_IN 3
+
+#define QAF_IN_MAIN 0
+#define QAF_IN_ASSOC 1
+#define QAF_IN_PCM 2
+
/*
* MS12 Latency (Input Buffer Processing latency)+
* Kernel Latency (Calculated based on the available offload buffer size) +
@@ -134,6 +148,13 @@
FILE *fp_output_writer_hdmi = NULL;
#endif
+struct qaf_adsp_hdlr_config_state {
+ struct audio_adsp_event event_params;
+ /* For holding client audio_adsp_event payload */
+ uint8_t event_payload[AUDIO_MAX_ADSP_STREAM_CMD_PAYLOAD_LEN];
+ bool adsp_hdlr_config_valid;
+};
+
struct qaf {
struct audio_device *adev;
audio_session_handle_t session_handle;
@@ -155,12 +176,12 @@
void (*qaf_register_event_callback)(audio_session_handle_t session_handle, void *priv_data,
notify_event_callback_t event_callback, audio_event_id_t event_id);
pthread_mutex_t lock;
- struct stream_out *stream_drain_main;
- struct stream_out *stream_drain_assoc;
- struct stream_out *qaf_compr_offload_out;
- struct stream_out *qaf_compr_offload_out_mch;
- struct stream_out *qaf_compr_passthrough_out;
- struct stream_out *qaf_passthrough_out;
+
+ struct stream_out *stream[MAX_QAF_IN];
+ struct stream_out *qaf_out[MAX_QAF_OUT];
+
+ struct qaf_adsp_hdlr_config_state adsp_hdlr_config[MAX_QAF_IN];
+
void *bt_hdl;
bool hdmi_connect;
int passthrough_enabled;
@@ -175,6 +196,16 @@
static struct qaf *qaf_mod = NULL;
static int qaf_stream_set_param(struct stream_out *out, const char *kv_pair) __attribute__ ((unused));
+/* find index of input stream */
+static int get_input_stream_index(struct stream_out *out)
+{ int count = -1;
+ for (count = 0; count < MAX_QAF_IN; count++) {
+ if (out == qaf_mod->stream[count])
+ break;
+ }
+ return count;
+}
+
static bool is_ms12_format(audio_format_t format)
{
if((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AC3)
@@ -225,7 +256,7 @@
{
struct stream_out *out = (struct stream_out *)cookie;
- out->offload_callback(event, NULL, out->offload_cookie);
+ out->client_callback(event, NULL, out->client_cookie);
return 0;
}
@@ -235,18 +266,18 @@
ALOGV("%s %d", __func__, __LINE__);
if ((handle_id == QAF_DEFAULT_PASSTHROUGH_HANDLE) &&
- (NULL == qaf_mod->qaf_passthrough_out)) {
+ (NULL == qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH])) {
pthread_mutex_lock(&qaf_mod->lock);
lock_output_stream(out);
ret = adev_open_output_stream((struct audio_hw_device *) qaf_mod->adev, handle_id, devices,
- flags, config, (struct audio_stream_out **) &(qaf_mod->qaf_passthrough_out), NULL);
+ flags, config, (struct audio_stream_out **) &(qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]), NULL);
if (ret < 0) {
pthread_mutex_unlock(&out->lock);
pthread_mutex_unlock(&qaf_mod->lock);
ALOGE("%s: adev_open_output_stream failed with ret = %d!", __func__, ret);
return -EINVAL;
}
- qaf_mod->qaf_passthrough_out->stream.set_callback((struct audio_stream_out *)qaf_mod->qaf_passthrough_out, (stream_callback_t) qaf_out_callback, out);
+ qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]->stream.set_callback((struct audio_stream_out *)qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH], (stream_callback_t) qaf_out_callback, out);
pthread_mutex_unlock(&out->lock);
pthread_mutex_unlock(&qaf_mod->lock);
}
@@ -288,12 +319,12 @@
stream, out->usecase, use_case_table[out->usecase]);
lock_output_stream(out);
- if (qaf_mod->qaf_passthrough_out && qaf_mod->hdmi_connect) {
+ if (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] && qaf_mod->hdmi_connect) {
if ((out->format == AUDIO_FORMAT_PCM_16_BIT) && (popcount(out->channel_mask) <= 2)) {
pthread_mutex_unlock(&out->lock);
return status;
}
- status = qaf_mod->qaf_passthrough_out->stream.common.standby((struct audio_stream *) qaf_mod->qaf_passthrough_out);
+ status = qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]->stream.common.standby((struct audio_stream *) qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]);
if (!out->standby) {
out->standby = true;
}
@@ -333,15 +364,15 @@
static int qaf_out_set_volume(struct audio_stream_out *stream __unused, float left,
float right)
{
- /* For ms12 formats, qaf_mod->qaf_compr_offload_out is allocated during the first
+ /* For ms12 formats, qaf_mod->qaf_out[QAF_OUT_OFFLOAD] is allocated during the first
* call of notify_event_callback(). Therefore, the volume levels set during session
* open have to be cached and applied later */
qaf_mod->vol_left = left;
qaf_mod->vol_right = right;
- if (qaf_mod->qaf_compr_offload_out != NULL) {
- return qaf_mod->qaf_compr_offload_out->stream.set_volume(
- (struct audio_stream_out *)qaf_mod->qaf_compr_offload_out, left, right);
+ if (qaf_mod->qaf_out[QAF_OUT_OFFLOAD] != NULL) {
+ return qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->stream.set_volume(
+ (struct audio_stream_out *)qaf_mod->qaf_out[QAF_OUT_OFFLOAD], left, right);
}
return -ENOSYS;
}
@@ -390,14 +421,14 @@
ALOGV("qaf_out_write bytes = %d, usecase[%d] and flags[%x] for handle[%p]",(int)bytes, out->usecase, out->flags, out);
lock_output_stream(out);
- if (qaf_mod->qaf_passthrough_out && qaf_mod->hdmi_connect) {
+ if (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] && qaf_mod->hdmi_connect) {
if ((out->format == AUDIO_FORMAT_PCM_16_BIT) && (popcount(out->channel_mask) <= 2)) {
ALOGD(" %s : Drop data as compress passthrough session is going on", __func__);
usleep(bytes * 1000000 / audio_stream_out_frame_size(stream) /
out->stream.common.get_sample_rate(&out->stream.common));
goto exit;
}
- ret = qaf_mod->qaf_passthrough_out->stream.write((struct audio_stream_out *)(qaf_mod->qaf_passthrough_out), buffer, bytes);
+ ret = qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]->stream.write((struct audio_stream_out *)(qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]), buffer, bytes);
pthread_mutex_unlock(&out->lock);
return ret;
}
@@ -498,15 +529,15 @@
kvpairs = NULL;
}
// MS12 Latency + Kernel Latency + Dsp Latency
- if (qaf_mod->qaf_compr_offload_out != NULL) {
- out->platform_latency = latency + (COMPRESS_OFFLOAD_NUM_FRAGMENTS * qaf_get_pcm_offload_buffer_size(&qaf_mod->qaf_compr_offload_out->info) \
- /(popcount(qaf_mod->qaf_compr_offload_out->channel_mask) * sizeof(short))) \
- +((platform_render_latency(qaf_mod->qaf_compr_offload_out->usecase) * qaf_mod->qaf_compr_offload_out->sample_rate) / 1000000LL);
+ if (qaf_mod->qaf_out[QAF_OUT_OFFLOAD] != NULL) {
+ out->platform_latency = latency + (COMPRESS_OFFLOAD_NUM_FRAGMENTS * qaf_get_pcm_offload_buffer_size(&qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->info) \
+ /(popcount(qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->channel_mask) * sizeof(short))) \
+ +((platform_render_latency(qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->usecase) * qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->sample_rate) / 1000000LL);
} else if (audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl) != NULL) {
out->platform_latency = latency + audio_extn_bt_hal_get_latency(qaf_mod->bt_hdl);
- } else if (NULL != qaf_mod->qaf_compr_passthrough_out) {
- out->platform_latency = latency + ((qaf_mod->qaf_compr_passthrough_out->format == AUDIO_FORMAT_AC3) ? TRANSCODE_LATENCY(COMPRESS_PASSTHROUGH_BUFFER_SIZE, DD_FRAME_SIZE, DD_ENCODER_OUTPUT_SIZE) : TRANSCODE_LATENCY(COMPRESS_PASSTHROUGH_BUFFER_SIZE, DD_FRAME_SIZE, DDP_ENCODER_OUTPUT_SIZE)) \
- + (COMPRESS_OFFLOAD_PLAYBACK_LATENCY * qaf_mod->qaf_compr_passthrough_out->sample_rate/1000);
+ } else if (NULL != qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH]) {
+ out->platform_latency = latency + ((qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH]->format == AUDIO_FORMAT_AC3) ? TRANSCODE_LATENCY(COMPRESS_PASSTHROUGH_BUFFER_SIZE, DD_FRAME_SIZE, DD_ENCODER_OUTPUT_SIZE) : TRANSCODE_LATENCY(COMPRESS_PASSTHROUGH_BUFFER_SIZE, DD_FRAME_SIZE, DDP_ENCODER_OUTPUT_SIZE)) \
+ + (COMPRESS_OFFLOAD_PLAYBACK_LATENCY * qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH]->sample_rate/1000);
}
if(out->format & AUDIO_FORMAT_PCM_16_BIT) {
@@ -546,8 +577,8 @@
int ret = -1;
lock_output_stream(out);
- if (qaf_mod->qaf_passthrough_out && qaf_mod->hdmi_connect) {
- ret = qaf_mod->qaf_passthrough_out->stream.get_presentation_position((struct audio_stream_out *)qaf_mod->qaf_passthrough_out, frames, timestamp);
+ if (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] && qaf_mod->hdmi_connect) {
+ ret = qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]->stream.get_presentation_position((struct audio_stream_out *)qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH], frames, timestamp);
pthread_mutex_unlock(&out->lock);
return ret;
}
@@ -574,8 +605,8 @@
ALOGE("%s", __func__);
lock_output_stream(out);
- if (qaf_mod->qaf_passthrough_out && qaf_mod->hdmi_connect) {
- status = qaf_mod->qaf_passthrough_out->stream.pause((struct audio_stream_out *) qaf_mod->qaf_passthrough_out);
+ if (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] && qaf_mod->hdmi_connect) {
+ status = qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]->stream.pause((struct audio_stream_out *) qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]);
out->offload_state = OFFLOAD_STATE_PAUSED;
pthread_mutex_unlock(&out->lock);
return status;
@@ -595,26 +626,18 @@
out->qaf_stream_handle, out->format);
lock_output_stream(out);
- if (qaf_mod->qaf_passthrough_out && qaf_mod->hdmi_connect) {
- status = qaf_mod->qaf_passthrough_out->stream.drain(
- (struct audio_stream_out*)(qaf_mod->qaf_passthrough_out), type);
+ if (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] && qaf_mod->hdmi_connect) {
+ status = qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]->stream.drain(
+ (struct audio_stream_out*)(qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]), type);
pthread_mutex_unlock(&out->lock);
return status;
}
- if (out->offload_callback && out->qaf_stream_handle) {
+ if (out->client_callback && out->qaf_stream_handle)
/* Stream stop will trigger EOS and on EOS_EVENT received
from callback DRAIN_READY command is sent */
status = audio_extn_qaf_stream_stop(out);
- if (out->format != AUDIO_FORMAT_PCM_16_BIT) {
- if (out->flags & AUDIO_OUTPUT_FLAG_ASSOCIATED) {
- qaf_mod->stream_drain_assoc = out;
- } else {
- qaf_mod->stream_drain_main = out;
- }
- }
- }
pthread_mutex_unlock(&out->lock);
return status;
}
@@ -635,8 +658,8 @@
int status = -ENOSYS;
lock_output_stream(out);
- if (qaf_mod->qaf_passthrough_out && qaf_mod->hdmi_connect) {
- status = qaf_mod->qaf_passthrough_out->stream.flush((struct audio_stream_out *)qaf_mod->qaf_passthrough_out);
+ if (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] && qaf_mod->hdmi_connect) {
+ status = qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]->stream.flush((struct audio_stream_out *)qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]);
out->offload_state = OFFLOAD_STATE_IDLE;
pthread_mutex_unlock(&out->lock);
return status;
@@ -655,8 +678,8 @@
lock_output_stream(out);
- if (qaf_mod->qaf_passthrough_out && qaf_mod->hdmi_connect) {
- latency = qaf_mod->qaf_passthrough_out->stream.get_latency((struct audio_stream_out *)qaf_mod->qaf_passthrough_out);
+ if (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] && qaf_mod->hdmi_connect) {
+ latency = qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]->stream.get_latency((struct audio_stream_out *)qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]);
ALOGV("%s: latency = %u", __FUNCTION__, latency);
pthread_mutex_unlock(&out->lock);
return latency;
@@ -709,31 +732,31 @@
ALOGVV("Device id %x %s %d, bytes to written %d",
device, __func__,__LINE__, size);
- if ((qaf_mod->qaf_passthrough_out != NULL) && qaf_mod->hdmi_connect) {
+ if ((qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] != NULL) && qaf_mod->hdmi_connect) {
pthread_mutex_lock(&qaf_module->lock);
- if (qaf_mod->qaf_compr_offload_out != NULL) {
+ if (qaf_mod->qaf_out[QAF_OUT_OFFLOAD] != NULL) {
adev_close_output_stream(
(struct audio_hw_device *) qaf_mod->adev,
- (struct audio_stream_out *) (qaf_mod->qaf_compr_offload_out));
- qaf_mod->qaf_compr_offload_out = NULL;
+ (struct audio_stream_out *) (qaf_mod->qaf_out[QAF_OUT_OFFLOAD]));
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD] = NULL;
}
- if (qaf_mod->qaf_compr_offload_out_mch) {
+ if (qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]) {
adev_close_output_stream(
(struct audio_hw_device *) qaf_mod->adev,
(struct audio_stream_out *)
- (qaf_mod->qaf_compr_offload_out_mch));
- qaf_mod->qaf_compr_offload_out_mch = NULL;
+ (qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]));
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH] = NULL;
}
pthread_mutex_unlock(&qaf_module->lock);
ALOGV("%s %d DROPPING DATA", __func__, __LINE__);
return;
} else {
- if (qaf_mod->qaf_passthrough_out != NULL) {
+ if (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] != NULL) {
pthread_mutex_lock(&qaf_module->lock);
adev_close_output_stream(
(struct audio_hw_device *) qaf_mod->adev,
- (struct audio_stream_out *) qaf_mod->qaf_passthrough_out);
- qaf_mod->qaf_passthrough_out = NULL;
+ (struct audio_stream_out *) qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]);
+ qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] = NULL;
qaf_mod->main_output_active = false;
pthread_mutex_unlock(&qaf_module->lock);
}
@@ -744,17 +767,17 @@
(device ==
(AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_COMPRESSED_OUT_DDP))) {
- if (NULL == qaf_mod->qaf_compr_passthrough_out &&
+ if (NULL == qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH] &&
qaf_mod->hdmi_connect) {
struct audio_config config;
audio_devices_t devices;
- if (qaf_mod->qaf_compr_offload_out_mch) {
+ if (qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]) {
adev_close_output_stream(
(struct audio_hw_device *) qaf_mod->adev,
(struct audio_stream_out *)
- (qaf_mod->qaf_compr_offload_out_mch));
- qaf_mod->qaf_compr_offload_out_mch = NULL;
+ (qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]));
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH] = NULL;
}
config.sample_rate = config.offload_info.sample_rate =
@@ -783,30 +806,30 @@
QAF_DEFAULT_COMPR_PASSTHROUGH_HANDLE, devices,
flags, &config,
(struct audio_stream_out **)
- &(qaf_mod->qaf_compr_passthrough_out), NULL);
+ &(qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH]), NULL);
if (ret < 0) {
ALOGE("%s: adev_open_output_stream failed with ret = %d!",
__func__, ret);
pthread_mutex_unlock(&qaf_module->lock);
return;
}
- qaf_mod->qaf_compr_passthrough_out->compr_config.fragments =
+ qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH]->compr_config.fragments =
COMPRESS_OFFLOAD_NUM_FRAGMENTS;
}
if (!qaf_mod->passthrough_enabled)
qaf_mod->passthrough_enabled = 1;
- if (qaf_mod->qaf_compr_passthrough_out) {
- ret = qaf_mod->qaf_compr_passthrough_out->stream.write(
+ if (qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH]) {
+ ret = qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH]->stream.write(
(struct audio_stream_out *)
- qaf_mod->qaf_compr_passthrough_out, buf, size);
+ qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH], buf, size);
}
} else if ((device & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
((qaf_mod->hdmi_connect) &&
- (qaf_mod->qaf_passthrough_out == NULL) &&
+ (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] == NULL) &&
(qaf_mod->hdmi_sink_channels > 2))) {
- if (NULL == qaf_mod->qaf_compr_offload_out_mch) {
+ if (NULL == qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]) {
struct audio_config config;
audio_devices_t devices;
@@ -831,47 +854,78 @@
}
devices = AUDIO_DEVICE_OUT_AUX_DIGITAL;
flags = (AUDIO_OUTPUT_FLAG_DIRECT|
- AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|
AUDIO_OUTPUT_FLAG_DIRECT_PCM);
ret = adev_open_output_stream(
(struct audio_hw_device *) qaf_mod->adev,
QAF_DEFAULT_COMPR_AUDIO_HANDLE, devices, flags,
&config, (struct audio_stream_out **)
- &(qaf_mod->qaf_compr_offload_out_mch), NULL);
+ &(qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]), NULL);
if (ret < 0) {
ALOGE("%s: adev_open_output_stream failed with ret = %d!",
__func__, ret);
pthread_mutex_unlock(&qaf_module->lock);
return;
}
- qaf_mod->qaf_compr_offload_out_mch->compr_config.fragments =
+ if (qaf_mod->stream[QAF_IN_MAIN] && qaf_mod->stream[QAF_IN_MAIN]->client_callback != NULL)
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]->stream.set_callback((struct audio_stream_out *)
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH],
+ qaf_mod->stream[QAF_IN_MAIN]->client_callback,
+ qaf_mod->stream[QAF_IN_MAIN]->client_cookie);
+ else if (qaf_mod->stream[QAF_IN_PCM] && qaf_mod->stream[QAF_IN_PCM]->client_callback != NULL)
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]->stream.set_callback((struct audio_stream_out *)
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH],
+ qaf_mod->stream[QAF_IN_PCM]->client_callback,
+ qaf_mod->stream[QAF_IN_PCM]->client_cookie);
+
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]->compr_config.fragments =
COMPRESS_OFFLOAD_NUM_FRAGMENTS;
- qaf_mod->qaf_compr_offload_out_mch->compr_config.fragment_size =
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]->compr_config.fragment_size =
qaf_get_pcm_offload_buffer_size(&config.offload_info);
+
+ int index = -1;
+ if (qaf_mod->adsp_hdlr_config[QAF_IN_MAIN].adsp_hdlr_config_valid)
+ index = (int)QAF_IN_MAIN;
+ else if (qaf_mod->adsp_hdlr_config[QAF_IN_PCM].adsp_hdlr_config_valid)
+ index = (int)QAF_IN_PCM;
+ if (index >= 0) {
+ if(qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]->standby)
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]->stream.write(
+ (struct audio_stream_out *)
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH], NULL, 0);
+
+ lock_output_stream(qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]);
+ ret = audio_extn_out_set_param_data(
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH],
+ AUDIO_EXTN_PARAM_ADSP_STREAM_CMD,
+ (audio_extn_param_payload *)
+ &qaf_mod->adsp_hdlr_config[index].event_params);
+ pthread_mutex_unlock(&qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]->lock);
+
+ }
}
- if (qaf_mod->qaf_compr_offload_out_mch) {
- ret = qaf_mod->qaf_compr_offload_out_mch->stream.write(
+ if (qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]) {
+ ret = qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]->stream.write(
(struct audio_stream_out *)
- qaf_mod->qaf_compr_offload_out_mch, buf, size);
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH], buf, size);
}
} else {
bt_stream = audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl);
if (bt_stream != NULL) {
- if (qaf_mod->qaf_compr_offload_out) {
+ if (qaf_mod->qaf_out[QAF_OUT_OFFLOAD]) {
adev_close_output_stream(
(struct audio_hw_device *) qaf_mod->adev,
(struct audio_stream_out *)
- (qaf_mod->qaf_compr_offload_out));
- qaf_mod->qaf_compr_offload_out = NULL;
+ (qaf_mod->qaf_out[QAF_OUT_OFFLOAD]));
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD] = NULL;
}
audio_extn_bt_hal_out_write(qaf_mod->bt_hdl, buf, size);
}
- if (NULL == qaf_mod->qaf_compr_offload_out && bt_stream == NULL &&
- qaf_mod->qaf_passthrough_out == NULL) {
+ if (NULL == qaf_mod->qaf_out[QAF_OUT_OFFLOAD] && bt_stream == NULL &&
+ qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] == NULL) {
struct audio_config config;
audio_devices_t devices;
@@ -884,57 +938,91 @@
config.format = AUDIO_FORMAT_PCM_16_BIT;
config.offload_info.channel_mask = config.channel_mask =
AUDIO_CHANNEL_OUT_STEREO;
- devices = AUDIO_DEVICE_OUT_SPEAKER;
+ if(qaf_mod->stream[QAF_IN_MAIN])
+ devices = qaf_mod->stream[QAF_IN_MAIN]->devices;
+ else
+ devices = qaf_mod->stream[QAF_IN_PCM]->devices;
flags = (AUDIO_OUTPUT_FLAG_DIRECT|
- AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|
AUDIO_OUTPUT_FLAG_DIRECT_PCM);
+
/* TODO:: Need to Propagate errors to framework */
ret = adev_open_output_stream(
(struct audio_hw_device *) qaf_mod->adev,
QAF_DEFAULT_COMPR_AUDIO_HANDLE, devices,
flags, &config,
(struct audio_stream_out **)
- &(qaf_mod->qaf_compr_offload_out), NULL);
+ &(qaf_mod->qaf_out[QAF_OUT_OFFLOAD]), NULL);
if (ret < 0) {
ALOGE("%s: adev_open_output_stream failed with ret = %d!",
__func__, ret);
pthread_mutex_unlock(&qaf_module->lock);
return;
}
+ if (qaf_mod->stream[QAF_IN_MAIN] && qaf_mod->stream[QAF_IN_MAIN]->client_callback != NULL)
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->stream.set_callback((struct audio_stream_out *)
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD],
+ qaf_mod->stream[QAF_IN_MAIN]->client_callback,
+ qaf_mod->stream[QAF_IN_MAIN]->client_cookie);
+ else if (qaf_mod->stream[QAF_IN_PCM] && qaf_mod->stream[QAF_IN_PCM]->client_callback != NULL)
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->stream.set_callback((struct audio_stream_out *)
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD],
+ qaf_mod->stream[QAF_IN_PCM]->client_callback,
+ qaf_mod->stream[QAF_IN_PCM]->client_cookie);
- qaf_mod->qaf_compr_offload_out->compr_config.fragments =
+
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->compr_config.fragments =
COMPRESS_OFFLOAD_NUM_FRAGMENTS;
- qaf_mod->qaf_compr_offload_out->compr_config.fragment_size =
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->compr_config.fragment_size =
qaf_get_pcm_offload_buffer_size(&config.offload_info);
- qaf_mod->qaf_compr_offload_out->info.channel_mask =
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->info.channel_mask =
config.offload_info.channel_mask;
- qaf_mod->qaf_compr_offload_out->info.format =
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->info.format =
config.offload_info.format;
- qaf_mod->qaf_compr_offload_out->info.sample_rate =
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->info.sample_rate =
config.offload_info.sample_rate;
- qaf_mod->qaf_compr_offload_out->stream.set_volume(
- (struct audio_stream_out *)qaf_mod->qaf_compr_offload_out,
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->stream.set_volume(
+ (struct audio_stream_out *)qaf_mod->qaf_out[QAF_OUT_OFFLOAD],
qaf_mod->vol_left, qaf_mod->vol_right);
+
+ int index = -1;
+ if (qaf_mod->adsp_hdlr_config[QAF_IN_MAIN].adsp_hdlr_config_valid)
+ index = (int)QAF_IN_MAIN;
+ else if (qaf_mod->adsp_hdlr_config[QAF_IN_PCM].adsp_hdlr_config_valid)
+ index = (int)QAF_IN_PCM;
+ if (index >= 0) {
+ if(qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->standby)
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->stream.write(
+ (struct audio_stream_out *)
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD], NULL, 0);
+
+ lock_output_stream(qaf_mod->qaf_out[QAF_OUT_OFFLOAD]);
+ ret = audio_extn_out_set_param_data(
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD],
+ AUDIO_EXTN_PARAM_ADSP_STREAM_CMD,
+ (audio_extn_param_payload *)
+ &qaf_mod->adsp_hdlr_config[index].event_params);
+ pthread_mutex_unlock(&qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->lock);
+ }
}
if (!qaf_mod->hdmi_connect &&
- (qaf_mod->qaf_compr_passthrough_out ||
- qaf_mod->qaf_compr_offload_out_mch)) {
+ (qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH] ||
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH])) {
qaf_mod->passthrough_enabled = 0;
- if (qaf_mod->qaf_compr_passthrough_out) {
+ if (qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH]) {
adev_close_output_stream(
(struct audio_hw_device *) qaf_mod->adev,
(struct audio_stream_out *)
- (qaf_mod->qaf_compr_passthrough_out));
- qaf_mod->qaf_compr_passthrough_out = NULL;
+ (qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH]));
+ qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH] = NULL;
}
- if (qaf_mod->qaf_compr_offload_out_mch) {
+ if (qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]) {
adev_close_output_stream(
(struct audio_hw_device *) qaf_mod->adev,
(struct audio_stream_out *)
- (qaf_mod->qaf_compr_offload_out_mch));
- qaf_mod->qaf_compr_offload_out_mch = NULL;
+ (qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]));
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH] = NULL;
}
}
@@ -942,10 +1030,10 @@
* TODO:: Since this is mixed data,
* need to identify to which stream the error should be sent
*/
- if (bt_stream == NULL && qaf_mod->qaf_compr_offload_out) {
- ret = qaf_mod->qaf_compr_offload_out->stream.write(
+ if (bt_stream == NULL && qaf_mod->qaf_out[QAF_OUT_OFFLOAD]) {
+ ret = qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->stream.write(
(struct audio_stream_out *)
- qaf_mod->qaf_compr_offload_out, buf, size);
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD], buf, size);
}
}
@@ -955,8 +1043,8 @@
|| event_id == AUDIO_EOS_MAIN_AAC_EVENT
|| event_id == AUDIO_EOS_MAIN_AC4_EVENT
|| event_id == AUDIO_EOS_ASSOC_DD_DDP_EVENT) {
- struct stream_out *out = qaf_module->stream_drain_main;
- struct stream_out *out_assoc = qaf_module->stream_drain_assoc;
+ struct stream_out *out = qaf_module->stream[QAF_IN_MAIN];
+ struct stream_out *out_assoc = qaf_module->stream[QAF_IN_ASSOC];
/**
* TODO:: Only DD/DDP Associate Eos is handled, need to add support
@@ -964,16 +1052,15 @@
*/
if (event_id == AUDIO_EOS_ASSOC_DD_DDP_EVENT && out_assoc != NULL) {
lock_output_stream(out_assoc);
- out_assoc->offload_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL,
- out_assoc->offload_cookie);
+ out_assoc->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL,
+ out_assoc->client_cookie);
pthread_mutex_unlock(&out_assoc->lock);
- qaf_module->stream_drain_assoc = NULL;
+ qaf_module->stream[QAF_IN_ASSOC] = NULL;
} else if (out != NULL) {
lock_output_stream(out);
- out->offload_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL,
- out->offload_cookie);
+ out->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out->client_cookie);
pthread_mutex_unlock(&out->lock);
- qaf_module->stream_drain_main = NULL;
+ qaf_module->stream[QAF_IN_MAIN] = NULL;
ALOGV("%s %d sent DRAIN_READY", __func__, __LINE__);
}
}
@@ -1055,6 +1142,7 @@
/* TODO to send appropriated flags when support for system tones is added */
if (input_config.format == AUDIO_FORMAT_PCM_16_BIT) {
status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle, &out->qaf_stream_handle, input_config, devices, /*flags*/AUDIO_STREAM_SYSTEM_TONE);
+ qaf_mod->stream[QAF_IN_PCM] = out;
} else if (input_config.format == AUDIO_FORMAT_AC3 ||
input_config.format == AUDIO_FORMAT_E_AC3 ||
input_config.format == AUDIO_FORMAT_AC4 ||
@@ -1067,12 +1155,14 @@
ALOGV("%s %d Open stream for Input with both Main and Associated stream contents with flag [%x] and stream handle [%p]", __func__, __LINE__, flags, out->qaf_stream_handle);
qaf_mod->main_output_active = true;
qaf_mod->assoc_output_active = true;
+ qaf_mod->stream[QAF_IN_MAIN] = out;
}
} else if (flags & AUDIO_OUTPUT_FLAG_MAIN) {
status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle, &out->qaf_stream_handle, input_config, devices, /*flags*/AUDIO_STREAM_MAIN);
if (status == 0) {
ALOGV("%s %d Open stream for Input with only Main flag [%x] stream handle [%p]", __func__, __LINE__, flags, out->qaf_stream_handle);
qaf_mod->main_output_active = true;
+ qaf_mod->stream[QAF_IN_MAIN] = out;
}
} else if (flags & AUDIO_OUTPUT_FLAG_ASSOCIATED) {
ALOGE("%s %d Error main input is not active", __func__, __LINE__);
@@ -1082,6 +1172,7 @@
if (status == 0) {
ALOGV("%s %d Open stream for Local playback with flag [%x] stream handle [%p] ", __func__, __LINE__, flags, out->qaf_stream_handle);
qaf_mod->main_output_active = true;
+ qaf_mod->stream[QAF_IN_MAIN] = out;
}
}
} else {
@@ -1097,6 +1188,7 @@
if (status == 0) {
ALOGV("%s %d Open stream for Input with only Associated flag [%x] stream handle [%p]", __func__, __LINE__, flags, out->qaf_stream_handle);
qaf_mod->assoc_output_active = true;
+ qaf_mod->stream[QAF_IN_ASSOC] = out;
}
}
} else {
@@ -1138,10 +1230,10 @@
if ((!property_get_bool("audio.qaf.reencode", false)) &&
property_get_bool("audio.qaf.passthrough", false)) {
if (property_get_bool("audio.offload.passthrough", false)) {
- if (qaf_mod->qaf_passthrough_out && qaf_mod->hdmi_connect &&
+ if (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] && qaf_mod->hdmi_connect &&
(((out->format == AUDIO_FORMAT_E_AC3) && platform_is_edid_supported_format(qaf_mod->adev->platform, AUDIO_FORMAT_E_AC3)) ||
((out->format == AUDIO_FORMAT_AC3) && platform_is_edid_supported_format(qaf_mod->adev->platform, AUDIO_FORMAT_AC3)))) {
- status = qaf_mod->qaf_passthrough_out->stream.resume((struct audio_stream_out*) qaf_mod->qaf_passthrough_out);
+ status = qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]->stream.resume((struct audio_stream_out*) qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]);
if (!status)
out->offload_state = OFFLOAD_STATE_PLAYING;
pthread_mutex_unlock(&out->lock);
@@ -1151,13 +1243,13 @@
status = audio_extn_qaf_stream_open(out);
if (!status)
out->offload_state = OFFLOAD_STATE_PLAYING;
- out->offload_callback(STREAM_CBK_EVENT_WRITE_READY, NULL, out->offload_cookie);
+ out->client_callback(STREAM_CBK_EVENT_WRITE_READY, NULL, out->client_cookie);
}
}
} else {
if ((out->format == AUDIO_FORMAT_PCM_16_BIT) && (popcount(out->channel_mask) > 2)) {
- if (qaf_mod->qaf_passthrough_out && qaf_mod->hdmi_connect) {
- status = qaf_mod->qaf_passthrough_out->stream.resume((struct audio_stream_out*) qaf_mod->qaf_passthrough_out);
+ if (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] && qaf_mod->hdmi_connect) {
+ status = qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]->stream.resume((struct audio_stream_out*) qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]);
if (!status)
out->offload_state = OFFLOAD_STATE_PLAYING;
pthread_mutex_unlock(&out->lock);
@@ -1177,20 +1269,16 @@
{
ALOGV("%s %d", __func__, __LINE__);
if (qaf_mod != NULL) {
- if (qaf_mod->qaf_compr_offload_out != NULL)
- adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev, (struct audio_stream_out *) (qaf_mod->qaf_compr_offload_out));
- if (qaf_mod->qaf_compr_passthrough_out != NULL)
- adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev, (struct audio_stream_out *) (qaf_mod->qaf_compr_passthrough_out));
+ if (qaf_mod->qaf_out[QAF_OUT_OFFLOAD] != NULL)
+ adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev, (struct audio_stream_out *) (qaf_mod->qaf_out[QAF_OUT_OFFLOAD]));
+ if (qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH] != NULL)
+ adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev, (struct audio_stream_out *) (qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH]));
- if (qaf_mod->qaf_passthrough_out) {
- adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev, (struct audio_stream_out *) (qaf_mod->qaf_passthrough_out));
- qaf_mod->qaf_passthrough_out = NULL;
+ if (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]) {
+ adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev, (struct audio_stream_out *) (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]));
+ qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] = NULL;
}
- if (qaf_mod->qaf_lib != NULL) {
- dlclose(qaf_mod->qaf_lib);
- qaf_mod->qaf_lib = NULL;
- }
free(qaf_mod);
qaf_mod = NULL;
}
@@ -1270,8 +1358,8 @@
break;
}
lock_output_stream(out);
- if (send_callback && out->offload_callback) {
- out->offload_callback(event, NULL, out->offload_cookie);
+ if (send_callback && out->client_callback) {
+ out->client_callback(event, NULL, out->client_cookie);
}
free(cmd);
}
@@ -1321,7 +1409,7 @@
ALOGV("%s: enter: usecase(%d: %s) kvpairs: %s",
__func__, out->usecase, use_case_table[out->usecase], kvpairs);
- if ((NULL != qaf_mod->qaf_compr_offload_out)) {
+ if ((NULL != qaf_mod->qaf_out[QAF_OUT_OFFLOAD])) {
if (qaf_mod->qaf_msmd_enabled) {
if (qaf_mod->passthrough_enabled && qaf_mod->hdmi_connect)
return 1;
@@ -1338,7 +1426,7 @@
val |= AUDIO_DEVICE_OUT_SPEAKER;
str_parms_add_int(new_parms, AUDIO_PARAMETER_STREAM_ROUTING, val);
new_kv_pairs = str_parms_to_str(new_parms);
- qaf_mod->qaf_compr_offload_out->stream.common.set_parameters((struct audio_stream *) qaf_mod->qaf_compr_offload_out, new_kv_pairs);
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->stream.common.set_parameters((struct audio_stream *) qaf_mod->qaf_out[QAF_OUT_OFFLOAD], new_kv_pairs);
free(new_kv_pairs);
str_parms_destroy(new_parms);
}
@@ -1346,7 +1434,7 @@
str_parms_destroy(parms);
} else {
if (!(qaf_mod->passthrough_enabled && qaf_mod->hdmi_connect))
- qaf_mod->qaf_compr_offload_out->stream.common.set_parameters((struct audio_stream *) qaf_mod->qaf_compr_offload_out, kvpairs);
+ qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->stream.common.set_parameters((struct audio_stream *) qaf_mod->qaf_out[QAF_OUT_OFFLOAD], kvpairs);
parms = str_parms_create_str(kvpairs);
if (!parms) {
@@ -1385,7 +1473,7 @@
if (err >= 0) {
val = atoi(value);
if ((val & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
- (qaf_mod->qaf_passthrough_out == NULL)) {
+ (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] == NULL)) {
audio_output_flags_t flags;
struct audio_config config;
audio_devices_t devices;
@@ -1414,7 +1502,120 @@
str_parms_destroy(parms);
}
}
+ return ret;
+}
+bool audio_extn_is_qaf_stream(struct stream_out *out)
+{
+
+ return (audio_extn_qaf_is_enabled() && out && is_ms12_format(out->format));
+}
+
+/* API to send playback stream specific config parameters */
+int audio_extn_qaf_out_set_param_data(struct stream_out *out,
+ audio_extn_param_id param_id,
+ audio_extn_param_payload *payload)
+{
+ int ret = -EINVAL;
+ int count;
+ struct stream_out *new_out = NULL;
+ struct audio_adsp_event *adsp_event;
+
+ if (!out || !payload) {
+ ALOGE("%s:: Invalid Param",__func__);
+ return ret;
+ }
+
+ /* In qaf output render session may not be opened at this time.
+ to handle it store adsp_hdlr param info so that it can be
+ applied later after opening render session from ms12 callback
+ */
+ if (param_id == AUDIO_EXTN_PARAM_ADSP_STREAM_CMD) {
+ count = get_input_stream_index(out);
+ if (count < 0) {
+ ALOGE("%s:: Invalid stream", __func__);
+ return ret;
+ }
+ adsp_event = (struct audio_adsp_event *)payload;
+
+ if (payload->adsp_event_params.payload_length
+ <= AUDIO_MAX_ADSP_STREAM_CMD_PAYLOAD_LEN) {
+ memcpy(qaf_mod->adsp_hdlr_config[count].event_payload,
+ adsp_event->payload, adsp_event->payload_length);
+ qaf_mod->adsp_hdlr_config[count].event_params.payload =
+ qaf_mod->adsp_hdlr_config[count].event_payload;
+ qaf_mod->adsp_hdlr_config[count].event_params.payload_length
+ = adsp_event->payload_length;
+ qaf_mod->adsp_hdlr_config[count].adsp_hdlr_config_valid = true;
+ } else {
+ ALOGE("%s:: Invalid adsp event length %d", __func__,
+ adsp_event->payload_length);
+ return ret;
+ }
+ ret = 0;
+ }
+
+ /* apply param for all active out sessions */
+ for (count = 0; count < MAX_QAF_OUT; count++) {
+ new_out = qaf_mod->qaf_out[count];
+ if (!new_out)
+ continue;
+
+ /*ADSP event is not supported for passthrough*/
+ if ((param_id == AUDIO_EXTN_PARAM_ADSP_STREAM_CMD) &&
+ !(new_out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM))
+ continue;
+ if (new_out->standby)
+ new_out->stream.write((struct audio_stream_out *)new_out, NULL, 0);
+ lock_output_stream(new_out);
+ ret = audio_extn_out_set_param_data(new_out, param_id, payload);
+ if(ret)
+ ALOGE("%s::audio_extn_out_set_param_data error %d", __func__, ret);
+ pthread_mutex_unlock(&new_out->lock);
+ }
+ return ret;
+}
+
+int audio_extn_qaf_out_get_param_data(struct stream_out *out,
+ audio_extn_param_id param_id,
+ audio_extn_param_payload *payload)
+{
+ int ret = -EINVAL;
+ struct stream_out *new_out = NULL;
+
+ if (!out || !payload) {
+ ALOGE("%s:: Invalid Param",__func__);
+ return ret;
+ }
+
+ if (!qaf_mod->hdmi_connect) {
+ ALOGE("%s:: hdmi not connected",__func__);
+ return ret;
+ }
+
+ /* get session which is routed to hdmi*/
+ if (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH])
+ new_out = qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH];
+ else if (qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH])
+ new_out = qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH];
+ else if (qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH])
+ new_out = qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH];
+ else if (qaf_mod->qaf_out[QAF_OUT_OFFLOAD])
+ new_out = qaf_mod->qaf_out[QAF_OUT_OFFLOAD];
+
+ if (!new_out) {
+ ALOGE("%s:: No out session active",__func__);
+ return ret;
+ }
+
+ if (new_out->standby)
+ new_out->stream.write((struct audio_stream_out *)new_out, NULL, 0);
+
+ lock_output_stream(new_out);
+ ret = audio_extn_out_get_param_data(new_out, param_id, payload);
+ if(ret)
+ ALOGE("%s::audio_extn_out_get_param_data error %d", __func__, ret);
+ pthread_mutex_unlock(&new_out->lock);
return ret;
}
@@ -1485,14 +1686,15 @@
struct audio_stream_out *stream)
{
struct stream_out *out = (struct stream_out *)stream;
+ int index;
ALOGV("%s: enter:stream_handle(%p) format = %x", __func__, out, out->format);
- if (qaf_mod->qaf_passthrough_out) {
- ALOGD("%s %d closing stream handle %p", __func__, __LINE__, qaf_mod->qaf_passthrough_out);
+ if (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]) {
+ ALOGD("%s %d closing stream handle %p", __func__, __LINE__, qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]);
pthread_mutex_lock(&qaf_mod->lock);
- adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev, (struct audio_stream_out *) (qaf_mod->qaf_passthrough_out));
+ adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev, (struct audio_stream_out *) (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]));
adev_close_output_stream(dev, stream);
- qaf_mod->qaf_passthrough_out = NULL;
+ qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] = NULL;
qaf_mod->main_output_active = false;
pthread_mutex_unlock(&qaf_mod->lock);
return;
@@ -1501,7 +1703,15 @@
if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
qaf_destroy_offload_callback_thread(out);
}
- qaf_mod->stream_drain_main = NULL;
+
+ index = get_input_stream_index(out);
+ if (index < 0)
+ ALOGE("%s:: Invalid stream",__func__);
+ else
+ memset(&qaf_mod->adsp_hdlr_config[index], 0,
+ sizeof(struct qaf_adsp_hdlr_config_state));
+
+ qaf_mod->stream[index] = NULL;
lock_output_stream(out);
qaf_stream_close(out);
pthread_mutex_unlock(&out->lock);
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 7b69ca2..68a552d 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -2105,9 +2105,9 @@
lock_output_stream(out);
out->offload_thread_blocked = false;
pthread_cond_signal(&out->cond);
- if (send_callback && out->offload_callback) {
- ALOGVV("%s: sending offload_callback event %d", __func__, event);
- out->offload_callback(event, NULL, out->offload_cookie);
+ if (send_callback && out->client_callback) {
+ ALOGVV("%s: sending client_callback event %d", __func__, event);
+ out->client_callback(event, NULL, out->client_cookie);
}
free(cmd);
}
@@ -2362,7 +2362,7 @@
/* compress_open sends params of the track, so reset the flag here */
out->is_compr_metadata_avail = false;
- if (out->offload_callback)
+ if (out->client_callback)
compress_nonblock(out->compr, out->non_blocking);
/* Since small bufs uses blocking writes, a write will be blocked
@@ -3431,11 +3431,21 @@
stream_callback_t callback, void *cookie)
{
struct stream_out *out = (struct stream_out *)stream;
+ int ret;
ALOGV("%s", __func__);
lock_output_stream(out);
- out->offload_callback = callback;
- out->offload_cookie = cookie;
+ out->client_callback = callback;
+ out->client_cookie = cookie;
+ if (out->adsp_hdlr_stream_handle) {
+ ret = audio_extn_adsp_hdlr_stream_set_callback(
+ out->adsp_hdlr_stream_handle,
+ callback,
+ cookie);
+ if (ret)
+ ALOGW("%s:adsp hdlr callback registration failed %d",
+ __func__, ret);
+ }
pthread_mutex_unlock(&out->lock);
return 0;
}
@@ -3921,6 +3931,7 @@
struct stream_out *out;
int ret = 0;
audio_format_t format;
+ struct adsp_hdlr_stream_cfg hdlr_stream_cfg;
*stream_out = NULL;
@@ -4365,7 +4376,20 @@
if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)
audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
popcount(out->channel_mask), out->playback_started);
-
+ /* setup a channel for client <--> adsp communication for stream events */
+ if ((out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) ||
+ (out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM)) {
+ hdlr_stream_cfg.pcm_device_id = platform_get_pcm_device_id(
+ out->usecase, PCM_PLAYBACK);
+ hdlr_stream_cfg.flags = out->flags;
+ hdlr_stream_cfg.type = PCM_PLAYBACK;
+ ret = audio_extn_adsp_hdlr_stream_open(&out->adsp_hdlr_stream_handle,
+ &hdlr_stream_cfg);
+ if (ret) {
+ ALOGE("%s: adsp_hdlr_stream_open failed %d",__func__, ret);
+ out->adsp_hdlr_stream_handle = NULL;
+ }
+ }
ALOGV("%s: exit", __func__);
return 0;
@@ -4387,6 +4411,14 @@
ALOGD("%s: enter:stream_handle(%p)",__func__, out);
+ /* close adsp hdrl session before standby */
+ if (out->adsp_hdlr_stream_handle) {
+ ret = audio_extn_adsp_hdlr_stream_close(out->adsp_hdlr_stream_handle);
+ if (ret)
+ ALOGE("%s: adsp_hdlr_stream_close failed %d",__func__, ret);
+ out->adsp_hdlr_stream_handle = NULL;
+ }
+
if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
pthread_mutex_lock(&adev->lock);
ret = voice_extn_compress_voip_close_output_stream(&stream->common);
@@ -5080,6 +5112,7 @@
if (adev->adm_deinit)
adev->adm_deinit(adev->adm_data);
qahwi_deinit(device);
+ audio_extn_adsp_hdlr_deinit();
free(device);
adev = NULL;
}
@@ -5334,6 +5367,7 @@
qahwi_init(*device);
audio_extn_perf_lock_init();
+ audio_extn_adsp_hdlr_init(adev->mixer);
ALOGV("%s: exit", __func__);
return 0;
}
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 68dc91b..ff9149f 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -175,7 +175,6 @@
* We should take care of returning proper size when AudioFlinger queries for
* the buffer size of an input/output stream
*/
-
enum {
OFFLOAD_CMD_EXIT, /* exit compress offload thread loop*/
OFFLOAD_CMD_DRAIN, /* send a full drain request to DSP */
@@ -243,8 +242,10 @@
struct listnode offload_cmd_list;
bool offload_thread_blocked;
- stream_callback_t offload_callback;
- void *offload_cookie;
+ void *adsp_hdlr_stream_handle;
+
+ stream_callback_t client_callback;
+ void *client_cookie;
struct compr_gapless_mdata gapless_mdata;
int send_new_metadata;
bool send_next_track_params;
diff --git a/hal/audio_hw_extn_api.c b/hal/audio_hw_extn_api.c
index 4806149..a1bd04d 100644
--- a/hal/audio_hw_extn_api.c
+++ b/hal/audio_hw_extn_api.c
@@ -59,33 +59,24 @@
int qahwi_out_set_param_data(struct audio_stream_out *stream,
audio_extn_param_id param_id,
audio_extn_param_payload *payload) {
- int ret = -EINVAL;
+ int ret = 0;
struct stream_out *out = (struct stream_out *)stream;
- if (!stream || !payload) {
- ALOGE("%s:: Invalid Param",__func__);
- return ret;
+ /* call qaf extn set_param if needed */
+ if (audio_extn_is_qaf_stream(out)) {
+ /* qaf acquires out->lock internally*/
+ ret = audio_extn_qaf_out_set_param_data(out, param_id, payload);
+ if (ret)
+ ALOGE("%s::qaf_out_set_param_data failed error %d", __func__ , ret);
+ } else {
+ if (out->standby)
+ out->stream.write(&out->stream, NULL, 0);
+ lock_output_stream(out);
+ ret = audio_extn_out_set_param_data(out, param_id, payload);
+ if (ret)
+ ALOGE("%s::audio_extn_out_set_param_data error %d", __func__, ret);
+ pthread_mutex_unlock(&out->lock);
}
-
- lock_output_stream(out);
- ALOGD("%s: enter: stream (%p) usecase(%d: %s) param_id %d", __func__,
- stream, out->usecase, use_case_table[out->usecase], param_id);
-
- switch (param_id) {
- case AUDIO_EXTN_PARAM_OUT_RENDER_WINDOW:
- ret = audio_extn_utils_compress_set_render_window(out,
- (struct audio_out_render_window_param *)(payload));
- break;
- case AUDIO_EXTN_PARAM_OUT_START_DELAY:
- ret = audio_extn_utils_compress_set_start_delay(out,
- (struct audio_out_start_delay_param *)(payload));
- break;
- default:
- ALOGE("%s:: unsupported param_id %d", __func__, param_id);
- break;
- }
-
- pthread_mutex_unlock(&out->lock);
return ret;
}
@@ -94,39 +85,25 @@
audio_extn_param_id param_id,
audio_extn_param_payload *payload)
{
- int ret = -EINVAL;
+ int ret;
struct stream_out *out = (struct stream_out *)stream;
- struct audio_usecase *uc_info;
- if (!stream || !payload) {
- ALOGE("%s:: Invalid Param",__func__);
- return ret;
+ /* call qaf extn set_param if enabled */
+ if (audio_extn_is_qaf_stream(out)) {
+ /* qaf acquires out->lock internally*/
+ ret = audio_extn_qaf_out_get_param_data(out, param_id, payload);
+ if (ret)
+ ALOGE("%s::qaf_out_get_param_data failed error %d", __func__, ret);
+ } else {
+ if (out->standby)
+ out->stream.write(&out->stream, NULL, 0);
+ lock_output_stream(out);
+ ret = audio_extn_out_get_param_data(out, param_id, payload);
+ if (ret)
+ ALOGE("%s::audio_extn_out_get_param_data failed error %d",__func__, ret);
+ pthread_mutex_unlock(&out->lock);
}
- lock_output_stream(out);
- ALOGD("%s: enter: stream (%p) usecase(%d: %s) param_id %d", __func__,
- stream, out->usecase, use_case_table[out->usecase], param_id);
-
- switch (param_id) {
- case AUDIO_EXTN_PARAM_AVT_DEVICE_DRIFT:
- uc_info = get_usecase_from_list(out->dev, out->usecase);
- if (uc_info == NULL) {
- ALOGE("%s: Could not find the usecase (%d) in the list",
- __func__, out->usecase);
- ret = -EINVAL;
- } else {
- ret = audio_extn_utils_get_avt_device_drift(uc_info,
- (struct audio_avt_device_drift_param *)payload);
- if(ret)
- ALOGE("%s:: avdrift query failed error %d", __func__, ret);
- }
- break;
- default:
- ALOGE("%s:: unsupported param_id %d", __func__, param_id);
- break;
- }
-
- pthread_mutex_unlock(&out->lock);
return ret;
}
diff --git a/qahw_api/inc/qahw_defs.h b/qahw_api/inc/qahw_defs.h
index d9231da..7ae9475 100644
--- a/qahw_api/inc/qahw_defs.h
+++ b/qahw_api/inc/qahw_defs.h
@@ -180,7 +180,12 @@
/* type of asynchronous write callback events. Mutually exclusive */
typedef enum {
QAHW_STREAM_CBK_EVENT_WRITE_READY, /* non blocking write completed */
- QAHW_STREAM_CBK_EVENT_DRAIN_READY /* drain completed */
+ QAHW_STREAM_CBK_EVENT_DRAIN_READY, /* drain completed */
+
+ QAHW_STREAM_CBK_EVENT_ADSP = 0x100 /* callback event from ADSP PP,
+ * corresponding payload will be
+ * sent as is to the client
+ */
} qahw_stream_callback_event_t;
typedef int qahw_stream_callback_t(qahw_stream_callback_event_t event,
@@ -273,6 +278,16 @@
uint64_t start_delay; /* session start delay in microseconds*/
};
+#define QAHW_MAX_ADSP_STREAM_CMD_PAYLOAD_LEN 512
+
+/* payload format for HAL parameter
+ * QAHW_PARAM_ADSP_STREAM_CMD
+ */
+struct qahw_adsp_event {
+ uint32_t payload_length; /* length in bytes of the payload */
+ void *payload; /* the actual payload */
+};
+
typedef union {
struct qahw_source_tracking_param st_params;
struct qahw_sound_focus_param sf_params;
@@ -280,6 +295,7 @@
struct qahw_avt_device_drift_param drift_params;
struct qahw_out_render_window_param render_window_params;
struct qahw_out_start_delay_param start_delay;
+ struct qahw_adsp_event adsp_event_params;
} qahw_param_payload;
typedef enum {
@@ -288,7 +304,8 @@
QAHW_PARAM_APTX_DEC,
QAHW_PARAM_AVT_DEVICE_DRIFT, /* PARAM to query AV timer vs device drift */
QAHW_PARAM_OUT_RENDER_WINDOW, /* PARAM to set render window */
- QAHW_PARAM_OUT_START_DELAY /* PARAM to set session start delay*/
+ QAHW_PARAM_OUT_START_DELAY, /* PARAM to set session start delay*/
+ QAHW_PARAM_ADSP_STREAM_CMD
} qahw_param_id;
__END_DECLS
diff --git a/qahw_api/test/qahw_playback_test.c b/qahw_api/test/qahw_playback_test.c
index e316fd9..1f65368 100644
--- a/qahw_api/test/qahw_playback_test.c
+++ b/qahw_api/test/qahw_playback_test.c
@@ -136,6 +136,16 @@
volatile bool thread_exit;
};
+struct event_data {
+ uint32_t version;
+ uint32_t num_events;
+ uint32_t event_id;
+ uint32_t module_id;
+ uint16_t instance_id;
+ uint16_t reserved;
+ uint32_t config_mask;
+};
+
typedef struct {
qahw_module_handle_t *qahw_in_hal_handle;
qahw_module_handle_t *qahw_out_hal_handle;
@@ -184,6 +194,7 @@
stream_config stream_param[MAX_PLAYBACK_STREAMS];
bool kpi_mode;
+bool event_trigger;
/*
* Set to a high number so it doesn't interfere with existing stream handles
@@ -233,6 +244,7 @@
void usage();
int measure_kpi_values(qahw_stream_handle_t* out_handle, bool is_offload);
+int tigger_event(qahw_stream_handle_t* out_handle);
static void init_streams(void)
{
@@ -313,9 +325,12 @@
}
}
-int async_callback(qahw_stream_callback_event_t event, void *param __unused,
+int async_callback(qahw_stream_callback_event_t event, void *param,
void *cookie)
{
+ uint32_t *payload = param;
+ int i;
+
if(cookie == NULL) {
fprintf(log_file, "Invalid callback handle\n");
fprintf(stderr, "Invalid callback handle\n");
@@ -336,6 +351,15 @@
pthread_mutex_lock(¶ms->drain_lock);
pthread_cond_signal(¶ms->drain_cond);
pthread_mutex_unlock(¶ms->drain_lock);
+ break;
+ case QAHW_STREAM_CBK_EVENT_ADSP:
+ fprintf(log_file, "stream %d: received event - QAHW_STREAM_CBK_EVENT_ADSP\n", params->stream_index);
+ if (payload != NULL) {
+ fprintf(log_file, "param_length %d\n", payload[0]);
+ for (i=1; i* sizeof(uint32_t) <= payload[0]; i++)
+ fprintf(log_file, "param[%d] = 0x%x\n", i, payload[i]);
+ }
+ break;
default:
break;
}
@@ -638,6 +662,10 @@
latency = qahw_out_get_latency(params->out_handle);
fprintf(log_file, "playback latency before starting a session %dms!!\n",
latency);
+
+ if (event_trigger == true)
+ tigger_event(params->out_handle);
+
while (!exit && !stop_playback) {
if (!bytes_remaining) {
fprintf(log_file, "\nstream %d: reading bytes %zd\n", params->stream_index, bytes_wanted);
@@ -1031,6 +1059,42 @@
return rc;
}
+int tigger_event(qahw_stream_handle_t* out_handle)
+{
+ qahw_param_payload payload;
+ struct event_data event_payload = {0};
+ int ret = 0;
+
+ event_payload.num_events = 1;
+ event_payload.event_id = 0x13236;
+ event_payload.module_id = 0x10EEC;
+ event_payload.config_mask = 1;
+
+ payload.adsp_event_params.payload_length = sizeof(event_payload);
+ payload.adsp_event_params.payload = &event_payload;
+
+ fprintf(log_file, "Set callback for event trigger usecase\n");
+ ret = qahw_out_set_callback(out_handle, async_callback,
+ &stream_param[PRIMARY_STREAM_INDEX]);
+ if (ret < 0) {
+ fprintf(log_file, "qahw_out_set_callback failed with err %d\n",
+ ret);
+ goto done;
+ }
+ fprintf(log_file, "Register for event using qahw_out_set_param_data\n");
+ ret = qahw_out_set_param_data(out_handle, QAHW_PARAM_ADSP_STREAM_CMD,
+ (qahw_param_payload *)&payload);
+ if (ret < 0) {
+ fprintf(log_file, "qahw_out_set_param_data failed with err %d\n",
+ ret);
+ goto done;
+ }
+ fprintf(log_file, "qahw_out_set_paramdata succeeded\n");
+
+done:
+ return ret;
+}
+
void parse_aptx_dec_bt_addr(char *value, struct qahw_aptx_dec_param *aptx_cfg)
{
int ba[6];
@@ -1314,6 +1378,7 @@
printf(" -k --kpi-mode - Required for Latency KPI measurement\n");
printf(" file path is not used here as file playback is not done in this mode\n");
printf(" file path and other file specific options would be ignored in this mode.\n\n");
+ printf(" -E --event-trigger - Trigger DTMF event during playback\n");
printf(" -e --effect-type <effect type> - Effect used for test\n");
printf(" 0:bassboost 1:virtualizer 2:equalizer 3:visualizer(NA) 4:reverb 5:audiosphere others:null\n\n");
printf(" -A --bt-addr <bt device addr> - Required to set bt device adress for aptx decoder\n\n");
@@ -1508,6 +1573,7 @@
int i = 0;
int j = 0;
kpi_mode = false;
+ event_trigger = false;
log_file = stdout;
proxy_params.acp.file_name = "/data/pcm_dump.wav";
@@ -1534,6 +1600,7 @@
{"flags", required_argument, 0, 'F'},
{"kpi-mode", no_argument, 0, 'K'},
{"plus", no_argument, 0, 'P'},
+ {"event-trigger", no_argument, 0, 'E'},
{"effect-path", required_argument, 0, 'e'},
{"bt-addr", required_argument, 0, 'A'},
{"query drift", no_argument, 0, 'q'},
@@ -1562,7 +1629,7 @@
while ((opt = getopt_long(argc,
argv,
- "-f:r:c:b:d:s:v:l:t:a:w:k:PD:KF:e:A:u:m:qh",
+ "-f:r:c:b:d:s:v:l:t:a:w:k:PD:KF:Ee:A:u:m:qh",
long_options,
&option_index)) != -1) {
@@ -1625,6 +1692,9 @@
stream_param[i].flags = atoll(optarg);
stream_param[i].flags_set = true;
break;
+ case 'E':
+ event_trigger = true;
+ break;
case 'e':
stream_param[i].effect_index = atoi(optarg);
if (stream_param[i].effect_index < 0 || stream_param[i].effect_index >= EFFECT_MAX) {
@@ -1676,6 +1746,10 @@
fprintf(log_file, "kpi-mode is not supported for multi-playback usecase\n");
fprintf(stderr, "kpi-mode is not supported for multi-playback usecase\n");
goto exit;
+ } else if (event_trigger == true && num_of_streams > 1) {
+ fprintf(log_file, "event_trigger is not supported for multi-playback usecase\n");
+ fprintf(stderr, "event_trigger is not supported for multi-playback usecase\n");
+ goto exit;
}
if (num_of_streams > 1 && stream_param[num_of_streams-1].output_device & AUDIO_DEVICE_OUT_ALL_A2DP) {