Back merging due to audio make errors as other project dependency during AOSP
Change-Id: I978b93bc5ed5dd06f42d029c36fee0d51e8f6fcb
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 ad28c44..4573ecc 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"
@@ -1337,3 +1338,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/passthru.c b/hal/audio_extn/passthru.c
index eaa8c0a..dd4d4d4 100644
--- a/hal/audio_extn/passthru.c
+++ b/hal/audio_extn/passthru.c
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+* Copyright (c) 2014-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
@@ -46,7 +46,8 @@
AUDIO_FORMAT_E_AC3,
AUDIO_FORMAT_E_AC3_JOC,
AUDIO_FORMAT_DTS,
- AUDIO_FORMAT_DTS_HD
+ AUDIO_FORMAT_DTS_HD,
+ AUDIO_FORMAT_DOLBY_TRUEHD
};
/*
@@ -216,6 +217,8 @@
bool passt = false;
switch (out->format) {
case AUDIO_FORMAT_E_AC3:
+ case AUDIO_FORMAT_DTS_HD:
+ case AUDIO_FORMAT_DOLBY_TRUEHD:
if (platform_is_edid_supported_format(adev->platform, out->format)) {
ALOGV("%s:PASSTHROUGH supported for format %x",
__func__, out->format);
@@ -249,13 +252,6 @@
passt = true;
}
break;
- case AUDIO_FORMAT_DTS_HD:
- if (platform_is_edid_supported_format(adev->platform, out->format)) {
- ALOGV("%s:PASSTHROUGH supported for format %x",
- __func__, out->format);
- passt = true;
- }
- break;
default:
ALOGV("%s:Passthrough not supported", __func__);
}
diff --git a/hal/audio_extn/qaf.c b/hal/audio_extn/qaf.c
index 5b88274..caf64ee 100644
--- a/hal/audio_extn/qaf.c
+++ b/hal/audio_extn/qaf.c
@@ -36,21 +36,18 @@
#define ALOGVV(a...) do { } while(0)
#endif
+#define DEBUG_MSG(arg,...) ALOGV("%s: %d: " arg, __func__, __LINE__, ##__VA_ARGS__)
+#define ERROR_MSG(arg,...) ALOGE("%s: %d: " arg, __func__, __LINE__, ##__VA_ARGS__)
+
#define COMPRESS_OFFLOAD_NUM_FRAGMENTS 2
-#define COMPRESS_OFFLOAD_FRAGMENT_SIZE (2 * 1024)
-#define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000
+#define COMPRESS_PASSTHROUGH_DDP_FRAGMENT_SIZE 4608
+
#define QAF_DEFAULT_COMPR_AUDIO_HANDLE 1001
#define QAF_DEFAULT_COMPR_PASSTHROUGH_HANDLE 1002
#define QAF_DEFAULT_PASSTHROUGH_HANDLE 1003
-/*
- * MS12 Latency (Input Buffer Processing latency)+
- * Kernel Latency (Calculated based on the available offload buffer size) +
- * DSP Latency (Calculated based on the Platform render latency)
-*/
+
#define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 300
-/* Used in calculating fragment size for pcm offload */
-#define QAF_PCM_OFFLOAD_BUFFER_DURATION 32 /*32 msecs */
#define MIN_PCM_OFFLOAD_FRAGMENT_SIZE 512
#define MAX_PCM_OFFLOAD_FRAGMENT_SIZE (240 * 1024)
@@ -58,47 +55,36 @@
#define ALIGN(x, y) ((y) * DIV_ROUND_UP((x), (y)))
/* Pcm input node buffer size is 6144 bytes, i.e, 32msec for 48000 samplerate */
-#define MS12_PCM_INPUT_BUFFER_LATENCY 32
+#define QAF_MODULE_PCM_INPUT_BUFFER_LATENCY 32
-/* In msec for 2 fragments of 32ms */
-#define QAF_PCM_OFFLOAD_PLAYBACK_LATENCY \
- (QAF_PCM_OFFLOAD_BUFFER_DURATION * COMPRESS_OFFLOAD_NUM_FRAGMENTS)
+#define MS12_PCM_OUT_FRAGMENT_SIZE 1536 //samples
-#define PCM_OFFLOAD_PLAYBACK_LATENCY \
- (MS12_PCM_INPUT_BUFFER_LATENCY + QAF_PCM_OFFLOAD_PLAYBACK_LATENCY)
-
-/*
- * Buffer size for compress passthrough is 8192 bytes
- */
-#define COMPRESS_PASSTHROUGH_BUFFER_SIZE \
- (COMPRESS_OFFLOAD_NUM_FRAGMENTS * COMPRESS_OFFLOAD_FRAGMENT_SIZE)
-/*
- * Frame size for DD/DDP is 1536 samples corresponding to 32ms.
- */
#define DD_FRAME_SIZE 1536
+#define DDP_FRAME_SIZE DD_FRAME_SIZE
/*
- * DD encoder output size for 32ms.
+ * DD encoder output size for one frame.
*/
#define DD_ENCODER_OUTPUT_SIZE 2560
/*
- * DDP encoder output size for 32ms.
+ * DDP encoder output size for one frame.
*/
#define DDP_ENCODER_OUTPUT_SIZE 4608
+/*********TODO Need to get correct values.*************************/
+
+#define DTS_PCM_OUT_FRAGMENT_SIZE 1024 //samples
+
+#define DTS_FRAME_SIZE 1536
+#define DTSHD_FRAME_SIZE DTS_FRAME_SIZE
/*
- * Frame size for DD/DDP is 1536 samples.
- * For a bit rate of 640 bps, DD encoder output size is 2560 bytes of
- * 32ms;
- * DDP encoder output size is 4608 bytes of 32 ms.
- * Kernel buffer buffer allocation for compress passthrough is
- * 2 x 2048 bytes = 4096 bytes
- * The Latency for DD (measured in samples) is calculated as:
- * Time taken to play 8192 bytes (for DD) = 4096 x 32/2560 = 51.2ms
- * Samples for 51.2ms = 51.2 x 1536/32 = 2457 samples.
- * Latency calculated similarly for DPP is 1365 samples.
+ * DTS encoder output size for one frame.
*/
-#define TRANSCODE_LATENCY(buffer_size, frame_size, encoder_output_in_bytes) \
- ((buffer_size * frame_size) / encoder_output_in_bytes)
+#define DTS_ENCODER_OUTPUT_SIZE 2560
+/*
+ * DTSHD encoder output size for one frame.
+ */
+#define DTSHD_ENCODER_OUTPUT_SIZE 4608
+/******************************************************************/
/*
* QAF Latency to process buffers since out_write from primary HAL
@@ -106,6 +92,7 @@
#define QAF_COMPRESS_OFFLOAD_PROCESSING_LATENCY 18
#define QAF_PCM_OFFLOAD_PROCESSING_LATENCY 48
+//TODO: Need to handle for DTS
#define QAF_DEEP_BUFFER_OUTPUT_PERIOD_SIZE 1536
#include <stdlib.h>
@@ -128,20 +115,56 @@
#include <qti_audio.h>
#include "sound/compress_params.h"
+//TODO: Need to remove this.
#define QAF_OUTPUT_SAMPLING_RATE 48000
#ifdef QAF_DUMP_ENABLED
FILE *fp_output_writer_hdmi = NULL;
#endif
-struct qaf {
- struct audio_device *adev;
+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;
+};
+
+//Types of MM module, currently supported by QAF.
+typedef enum {
+ MS12,
+ DTS_M8,
+ MAX_MM_MODULE_TYPE,
+ INVALID_MM_MODULE
+} mm_module_type;
+
+typedef enum {
+ QAF_OUT_TRANSCODE_PASSTHROUGH = 0, /* Transcode passthrough via MM module*/
+ QAF_OUT_OFFLOAD_MCH, /* Multi-channel PCM offload*/
+ QAF_OUT_OFFLOAD, /* PCM offload */
+
+ MAX_QAF_MODULE_OUT
+} mm_module_output_type;
+
+typedef enum {
+ QAF_IN_MAIN = 0, /* Single PID Main/Primary or Dual-PID stream */
+ QAF_IN_ASSOC, /* Associated/Secondary stream */
+ QAF_IN_PCM, /* PCM stream. */
+
+ MAX_QAF_MODULE_IN
+} mm_module_input_type;
+
+struct qaf_module {
audio_session_handle_t session_handle;
void *qaf_lib;
- int (*qaf_audio_session_open)(audio_session_handle_t* session_handle, void *p_data, void* license_data);
+ int (*qaf_audio_session_open)(audio_session_handle_t* session_handle,
+ void *p_data,
+ void* license_data);
int (*qaf_audio_session_close)(audio_session_handle_t session_handle);
- int (*qaf_audio_stream_open)(audio_session_handle_t session_handle, audio_stream_handle_t* stream_handle,
- audio_stream_config_t input_config, audio_devices_t devices, stream_type_t flags);
+ int (*qaf_audio_stream_open)(audio_session_handle_t session_handle,
+ audio_stream_handle_t* stream_handle,
+ audio_stream_config_t input_config,
+ audio_devices_t devices,
+ stream_type_t flags);
int (*qaf_audio_stream_close)(audio_stream_handle_t stream_handle);
int (*qaf_audio_stream_set_param)(audio_stream_handle_t stream_handle, const char* kv_pairs);
int (*qaf_audio_session_set_param)(audio_session_handle_t handle, const char* kv_pairs);
@@ -152,47 +175,151 @@
int (*qaf_audio_stream_pause)(audio_stream_handle_t stream_handle);
int (*qaf_audio_stream_flush)(audio_stream_handle_t stream_handle);
int (*qaf_audio_stream_write)(audio_stream_handle_t stream_handle, const void* buf, int size);
- 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;
+ 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);
+
+ /*Input stream of MM module */
+ struct stream_out *stream_in[MAX_QAF_MODULE_IN];
+ /*Output Stream from MM module */
+ struct stream_out *stream_out[MAX_QAF_MODULE_OUT];
+
+ struct qaf_adsp_hdlr_config_state adsp_hdlr_config[MAX_QAF_MODULE_IN];
+
+ //BT session handle.
void *bt_hdl;
- bool hdmi_connect;
- int passthrough_enabled;
- int hdmi_sink_channels;
- bool main_output_active;
- bool assoc_output_active;
- bool qaf_msmd_enabled;
+
float vol_left;
float vol_right;
+ bool is_vol_set;
+ bool drain_received[MAX_QAF_MODULE_IN];
};
-static struct qaf *qaf_mod = NULL;
-static int qaf_stream_set_param(struct stream_out *out, const char *kv_pair) __attribute__ ((unused));
+struct qaf {
+ struct audio_device *adev;
-static bool is_ms12_format(audio_format_t format)
+ pthread_mutex_t lock;
+
+ bool hdmi_connect;
+ int hdmi_sink_channels;
+
+ //Flag to indicate if QAF transcode output stream is enabled from any mm module.
+ bool passthrough_enabled;
+ //Flag to indicate if QAF mch pcm output stream is enabled from any mm module.
+ bool mch_pcm_hdmi_enabled;
+
+ //Flag to indicate if msmd is supported.
+ bool qaf_msmd_enabled;
+
+ //Handle of QAF input stream, which is routed as QAF passthrough.
+ struct stream_out *passthrough_in;
+ //Handle of QAF passthrough stream.
+ struct stream_out *passthrough_out;
+
+ struct qaf_module qaf_mod[MAX_MM_MODULE_TYPE];
+};
+
+static int qaf_out_pause(struct audio_stream_out* stream);
+static int qaf_out_flush(struct audio_stream_out* stream);
+static int qaf_out_drain(struct audio_stream_out* stream, audio_drain_type_t type);
+
+//Global handle of QAF. Access to this should be protected by mutex lock.
+static struct qaf *p_qaf = NULL;
+
+/* Gets the pointer to qaf module for the qaf input stream. */
+static struct qaf_module* get_qaf_module_for_input_stream(struct stream_out *out)
{
- if((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AC3)
- return true;
- if((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_E_AC3)
- return true;
- if((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC)
- return true;
- if((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC_ADTS)
- return true;
- if((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AC4)
- return true;
- if(format == AUDIO_FORMAT_PCM_16_BIT)
- return true;
+ struct qaf_module *qaf_mod = NULL;
+ int i, j;
+ if (!p_qaf) return NULL;
- return false;
+ for (i = 0; i < MAX_MM_MODULE_TYPE; i++) {
+ for (j = 0; j < MAX_QAF_MODULE_IN; j++) {
+ if (p_qaf->qaf_mod[i].stream_in[j] == out) {
+ qaf_mod = &(p_qaf->qaf_mod[i]);
+ break;
+ }
+ }
+ }
+
+ return qaf_mod;
}
+/* Finds the mm module input stream index for the QAF input stream. */
+static int get_input_stream_index(struct stream_out *out)
+{
+ int index = -1, j;
+ struct qaf_module* qaf_mod = NULL;
+
+ qaf_mod = get_qaf_module_for_input_stream(out);
+ if (!qaf_mod) return index;
+
+ for (j = 0; j < MAX_QAF_MODULE_IN; j++) {
+ if (qaf_mod->stream_in[j] == out) {
+ index = j;
+ break;
+ }
+ }
+
+ return index;
+}
+
+/* Finds the right mm module for the QAF input stream format. */
+static mm_module_type get_mm_module_for_format(audio_format_t format)
+{
+ int j;
+
+ DEBUG_MSG("Format 0x%x", format);
+
+ if (format == AUDIO_FORMAT_PCM_16_BIT) {
+ //If dts is not supported then alway support pcm with MS12
+ if (!property_get_bool("audio.qaf.dts_m8", false)) { //TODO: Need to add this property for DTS.
+ return MS12;
+ }
+
+ //If QAF passthrough is active then send the PCM stream to primary HAL.
+ if (!p_qaf->passthrough_out) {
+ /* Iff any stream is active in MS12 module then route PCM stream to it. */
+ for (j = 0; j < MAX_QAF_MODULE_IN; j++) {
+ if (p_qaf->qaf_mod[MS12].stream_in[j]) {
+ return MS12;
+ }
+ }
+ }
+ return INVALID_MM_MODULE;
+ }
+
+ switch (format & AUDIO_FORMAT_MAIN_MASK) {
+ case AUDIO_FORMAT_AC3:
+ case AUDIO_FORMAT_E_AC3:
+ case AUDIO_FORMAT_AAC:
+ case AUDIO_FORMAT_AAC_ADTS:
+ case AUDIO_FORMAT_AC4:
+ return MS12;
+ case AUDIO_FORMAT_DTS:
+ case AUDIO_FORMAT_DTS_HD:
+ return DTS_M8;
+ default:
+ return INVALID_MM_MODULE;
+ }
+}
+
+/* Gets the pcm output buffer size(in samples) for the mm module. */
+static uint32_t get_pcm_output_buffer_size_samples(struct qaf_module *qaf_mod)
+{
+ uint32_t pcm_output_buffer_size = 0;
+
+ if (qaf_mod == &p_qaf->qaf_mod[MS12]) {
+ pcm_output_buffer_size = MS12_PCM_OUT_FRAGMENT_SIZE;
+ } else if (qaf_mod == &p_qaf->qaf_mod[DTS_M8]) {
+ pcm_output_buffer_size = DTS_PCM_OUT_FRAGMENT_SIZE;
+ }
+
+ return pcm_output_buffer_size;
+}
+
+/* Acquire Mutex lock on output stream */
static void lock_output_stream(struct stream_out *out)
{
pthread_mutex_lock(&out->pre_lock);
@@ -200,85 +327,207 @@
pthread_mutex_unlock(&out->pre_lock);
}
+/* Release Mutex lock on output stream */
+static void unlock_output_stream(struct stream_out *out)
+{
+ pthread_mutex_unlock(&out->lock);
+}
+
+/* Checks if stream can be routed as QAF passthrough or not. */
static bool audio_extn_qaf_passthrough_enabled(struct stream_out *out)
{
- ALOGV("%s %d ", __func__, __LINE__);
- if ((!property_get_bool("audio.qaf.reencode", false)) &&
- property_get_bool("audio.qaf.passthrough", false)) {
- if (property_get_bool("audio.offload.passthrough", false)) {
- if (((out->format == AUDIO_FORMAT_AC3) && platform_is_edid_supported_format(qaf_mod->adev->platform, AUDIO_FORMAT_AC3)) ||
- ((out->format == AUDIO_FORMAT_E_AC3) && platform_is_edid_supported_format(qaf_mod->adev->platform, AUDIO_FORMAT_E_AC3)) ||
- ((out->format == AUDIO_FORMAT_DTS) && platform_is_edid_supported_format(qaf_mod->adev->platform, AUDIO_FORMAT_DTS)) ||
- ((out->format == AUDIO_FORMAT_DTS_HD) && platform_is_edid_supported_format(qaf_mod->adev->platform, AUDIO_FORMAT_DTS_HD))) {
- return true;
- }
- } else {
- if ((out->format == AUDIO_FORMAT_PCM_16_BIT) && (popcount(out->channel_mask) > 2)) {
- return true;
+ DEBUG_MSG("Format 0x%x", out->format);
+ bool is_enabled = false;
+
+ if (!p_qaf) return false;
+
+ if ((!property_get_bool("audio.qaf.reencode", false))
+ && property_get_bool("audio.qaf.passthrough", false)) {
+
+ if ((out->format == AUDIO_FORMAT_PCM_16_BIT) && (popcount(out->channel_mask) > 2)) {
+ is_enabled = true;
+ } else if (property_get_bool("audio.offload.passthrough", false)) {
+ switch (out->format) {
+ case AUDIO_FORMAT_AC3:
+ case AUDIO_FORMAT_E_AC3:
+ case AUDIO_FORMAT_DTS:
+ case AUDIO_FORMAT_DTS_HD:
+ case AUDIO_FORMAT_DOLBY_TRUEHD: {
+ is_enabled = true;
+ break;
+ }
+ default:
+ is_enabled = false;
+ break;
}
}
}
- return false;
+
+ return is_enabled;
+}
+
+/*Closes all pcm hdmi output from QAF. */
+static void close_all_pcm_hdmi_output()
+{
+ int i;
+ //Closing all the PCM HDMI output stream from QAF.
+ for (i = 0; i < MAX_MM_MODULE_TYPE; i++) {
+ if (p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD_MCH]) {
+ adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
+ (struct audio_stream_out *)(p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD_MCH]));
+ p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD_MCH] = NULL;
+ }
+
+ if ((p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD])
+ && (p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD]->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
+ adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
+ (struct audio_stream_out *)(p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD]));
+ p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD] = NULL;
+ }
+ }
+
+ p_qaf->mch_pcm_hdmi_enabled = 0;
+}
+
+static void close_all_hdmi_output()
+{
+ int k;
+ for (k = 0; k < MAX_MM_MODULE_TYPE; k++) {
+ if (p_qaf->qaf_mod[k].stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]) {
+ adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
+ (struct audio_stream_out *)(p_qaf->qaf_mod[k].stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]));
+ p_qaf->qaf_mod[k].stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH] = NULL;
+ }
+ }
+ p_qaf->passthrough_enabled = 0;
+
+ close_all_pcm_hdmi_output();
}
static int qaf_out_callback(stream_callback_event_t event, void *param __unused, void *cookie)
{
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;
}
-static int create_output_stream(struct stream_out *out, struct audio_config *config, audio_output_flags_t flags, audio_devices_t devices, int handle_id)
+/* Creates the QAF passthrough output stream. */
+static int create_qaf_passthrough_stream()
{
- int ret = 0;
+ DEBUG_MSG();
- ALOGV("%s %d", __func__, __LINE__);
- if ((handle_id == QAF_DEFAULT_PASSTHROUGH_HANDLE) &&
- (NULL == qaf_mod->qaf_passthrough_out)) {
- 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);
+ int ret = 0, k;
+ struct stream_out *out = p_qaf->passthrough_in;
+
+ if (!out) return -EINVAL;
+
+ pthread_mutex_lock(&p_qaf->lock);
+ lock_output_stream(out);
+
+ //Creating QAF passthrough output stream.
+ if (NULL == p_qaf->passthrough_out) {
+ audio_output_flags_t flags;
+ struct audio_config config;
+ audio_devices_t devices;
+
+ config.sample_rate = config.offload_info.sample_rate = out->sample_rate;
+ config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
+ config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
+ config.offload_info.format = out->format;
+ config.offload_info.bit_width = out->bit_width;
+ config.format = out->format;
+ config.offload_info.channel_mask = config.channel_mask = out->channel_mask;
+
+ //Device is copied from the QAF passthrough input stream.
+ devices = out->devices;
+ flags = out->flags;
+
+ ret = adev_open_output_stream((struct audio_hw_device *)p_qaf->adev,
+ QAF_DEFAULT_PASSTHROUGH_HANDLE,
+ devices,
+ flags,
+ &config,
+ (struct audio_stream_out **)&(p_qaf->passthrough_out),
+ 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;
+ ERROR_MSG("adev_open_output_stream failed with ret = %d!", ret);
+ unlock_output_stream(out);
+ return ret;
}
- qaf_mod->qaf_passthrough_out->stream.set_callback((struct audio_stream_out *)qaf_mod->qaf_passthrough_out, (stream_callback_t) qaf_out_callback, out);
- pthread_mutex_unlock(&out->lock);
- pthread_mutex_unlock(&qaf_mod->lock);
+ p_qaf->passthrough_in = out;
+ p_qaf->passthrough_out->stream.set_callback((struct audio_stream_out *)p_qaf->passthrough_out,
+ (stream_callback_t) qaf_out_callback, out);
}
+
+ unlock_output_stream(out);
+
+ //Since QAF-Passthrough is created, close other HDMI outputs.
+ close_all_hdmi_output();
+
+ pthread_mutex_unlock(&p_qaf->lock);
return ret;
}
+/* Closes the QAF passthrough output stream. */
+static void close_qaf_passthrough_stream()
+{
+ if (p_qaf->passthrough_out != NULL) { //QAF pasthroug is enabled. Close it.
+ pthread_mutex_lock(&p_qaf->lock);
+ adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
+ (struct audio_stream_out *)(p_qaf->passthrough_out));
+ p_qaf->passthrough_out = NULL;
+ pthread_mutex_unlock(&p_qaf->lock);
+
+ if (p_qaf->passthrough_in->qaf_stream_handle) {
+ qaf_out_pause((struct audio_stream_out*)p_qaf->passthrough_in);
+ qaf_out_flush((struct audio_stream_out*)p_qaf->passthrough_in);
+ qaf_out_drain((struct audio_stream_out*)p_qaf->passthrough_in,
+ (audio_drain_type_t)STREAM_CBK_EVENT_DRAIN_READY);
+ }
+ }
+}
+
+/* Sends a command to output stream offload thread. */
static int qaf_send_offload_cmd_l(struct stream_out* out, int command)
{
+ DEBUG_MSG("command is %d", command);
+
struct offload_cmd *cmd = (struct offload_cmd *)calloc(1, sizeof(struct offload_cmd));
if (!cmd) {
- ALOGE("failed to allocate mem for command 0x%x", command);
+ ERROR_MSG("failed to allocate mem for command 0x%x", command);
return -ENOMEM;
}
- ALOGV("%s %d", __func__, command);
-
cmd->cmd = command;
+
+ lock_output_stream(out);
list_add_tail(&out->qaf_offload_cmd_list, &cmd->node);
pthread_cond_signal(&out->qaf_offload_cond);
+ unlock_output_stream(out);
return 0;
}
+/* Stops a QAF module stream.*/
static int audio_extn_qaf_stream_stop(struct stream_out *out)
{
- ALOGV("%s: %d start", __func__, __LINE__);
- if (!qaf_mod->qaf_audio_stream_stop)
- return -EINVAL;
+ int ret = 0;
+ DEBUG_MSG("Output Stream 0x%x", out);
- return qaf_mod->qaf_audio_stream_stop(out->qaf_stream_handle);
+ struct qaf_module *qaf_mod = get_qaf_module_for_input_stream(out);
+ if ((!qaf_mod) || (!qaf_mod->qaf_audio_stream_stop)) {
+ return ret;
+ }
+
+ if (out->qaf_stream_handle) {
+ ret = qaf_mod->qaf_audio_stream_stop(out->qaf_stream_handle);
+ }
+
+ return ret;
}
+/* Puts a QAF module stream in standby. */
static int qaf_out_standby(struct audio_stream *stream)
{
struct stream_out *out = (struct stream_out *)stream;
@@ -288,70 +537,73 @@
stream, out->usecase, use_case_table[out->usecase]);
lock_output_stream(out);
- if (qaf_mod->qaf_passthrough_out && qaf_mod->hdmi_connect) {
- if ((out->format == AUDIO_FORMAT_PCM_16_BIT) && (popcount(out->channel_mask) <= 2)) {
- pthread_mutex_unlock(&out->lock);
- return status;
+
+ //If QAF passthrough is active then block standby on all the input streams of QAF mm modules.
+ if (p_qaf->passthrough_out) {
+ //If standby is received on QAF passthrough stream then forward it to primary HAL.
+ if (p_qaf->passthrough_in == out) {
+ status = p_qaf->passthrough_out->stream.common.standby(
+ (struct audio_stream *)p_qaf->passthrough_out);
}
- status = qaf_mod->qaf_passthrough_out->stream.common.standby((struct audio_stream *) qaf_mod->qaf_passthrough_out);
- if (!out->standby) {
- out->standby = true;
- }
- pthread_mutex_unlock(&out->lock);
- return status;
+ } else {
+ //If QAF passthrough stream is not active then stop the QAF module stream.
+ status = audio_extn_qaf_stream_stop(out);
}
if (!out->standby) {
out->standby = true;
- status = audio_extn_qaf_stream_stop(out);
}
- pthread_mutex_unlock(&out->lock);
+
+ unlock_output_stream(out);
return status;
}
-static int qaf_stream_set_param(struct stream_out *out, const char *kv_pair)
-{
- ALOGV("%s %d kvpair: %s", __func__, __LINE__, kv_pair);
- if (!qaf_mod->qaf_audio_stream_set_param)
- return -EINVAL;
-
- return qaf_mod->qaf_audio_stream_set_param(out->qaf_stream_handle, kv_pair);
-}
-
-static int qaf_write_input_buffer(struct stream_out *out, const void *buffer, int bytes)
+/* Sets the volume to PCM output stream. */
+static int qaf_out_set_volume(struct audio_stream_out *stream, float left, float right)
{
int ret = 0;
- ALOGVV("%s bytes = %d [%p]", __func__, bytes, out->qaf_stream_handle);
- if (!qaf_mod->qaf_audio_stream_write)
- return -EINVAL;
+ struct stream_out *out = (struct stream_out *)stream;
+ struct qaf_module *qaf_mod = NULL;
- if (out->qaf_stream_handle)
- ret = qaf_mod->qaf_audio_stream_write(out->qaf_stream_handle, buffer, bytes);
+ DEBUG_MSG("Left %f, Right %f", left, right);
+
+ qaf_mod = get_qaf_module_for_input_stream(out);
+ if (!qaf_mod) {
+ return -EINVAL;
+ }
+
+ pthread_mutex_lock(&p_qaf->lock);
+ qaf_mod->vol_left = left;
+ qaf_mod->vol_right = right;
+ qaf_mod->is_vol_set = true;
+ pthread_mutex_unlock(&p_qaf->lock);
+
+ if (qaf_mod->stream_out[QAF_OUT_OFFLOAD] != NULL) {
+ ret = qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.set_volume(
+ (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD], left, right);
+ }
+
return ret;
}
-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
- * 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);
- }
- return -ENOSYS;
-}
-
+/* Starts a QAF module stream. */
static int qaf_stream_start(struct stream_out *out)
{
- if (!qaf_mod->qaf_audio_stream_start)
- return -EINVAL;
+ int ret = -EINVAL;
+ struct qaf_module *qaf_mod = NULL;
- return qaf_mod->qaf_audio_stream_start(out->qaf_stream_handle);
+ DEBUG_MSG("Output Stream = %p", out);
+
+ qaf_mod = get_qaf_module_for_input_stream(out);
+ if ((!qaf_mod) || (!qaf_mod->qaf_audio_stream_start)) {
+ return -EINVAL;
+ }
+
+ if (out->qaf_stream_handle) {
+ ret = qaf_mod->qaf_audio_stream_start(out->qaf_stream_handle);
+ }
+
+ return ret;
}
static int qaf_start_output_stream(struct stream_out *out)
@@ -380,116 +632,179 @@
return qaf_stream_start(out);
}
-static ssize_t qaf_out_write(struct audio_stream_out *stream, const void *buffer,
- size_t bytes)
+/* Sends input buffer to the QAF MM module. */
+static int qaf_module_write_input_buffer(struct stream_out *out, const void *buffer, int bytes)
+{
+ int ret = -EINVAL;
+ struct qaf_module *qaf_mod = NULL;
+ DEBUG_MSG("bytes = %d [%p]", bytes, out->qaf_stream_handle);
+
+ qaf_mod = get_qaf_module_for_input_stream(out);
+ if ((!qaf_mod) || (!qaf_mod->qaf_audio_stream_write)) {
+ return ret;
+ }
+
+ if (out->qaf_stream_handle) {
+ ret = qaf_mod->qaf_audio_stream_write(out->qaf_stream_handle, buffer, bytes);
+ }
+ return ret;
+}
+
+/* Writes buffer to QAF input stream. */
+static ssize_t qaf_out_write(struct audio_stream_out *stream, const void *buffer, size_t bytes)
{
struct stream_out *out = (struct stream_out *)stream;
struct audio_device *adev = out->dev;
ssize_t ret = 0;
- ALOGV("qaf_out_write bytes = %d, usecase[%d] and flags[%x] for handle[%p]",(int)bytes, out->usecase, out->flags, out);
+ DEBUG_MSG("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 ((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;
+ // If QAF passthrough is active then block writing data to QAF mm module.
+ if (p_qaf->passthrough_out) {
+ //If write is received for the QAF passthrough stream then send the buffer to primary HAL.
+ if (p_qaf->passthrough_in == out) {
+ ret = p_qaf->passthrough_out->stream.write(
+ (struct audio_stream_out *)(p_qaf->passthrough_out),
+ buffer,
+ bytes);
+ if (ret > 0) out->standby = false;
}
- ret = qaf_mod->qaf_passthrough_out->stream.write((struct audio_stream_out *)(qaf_mod->qaf_passthrough_out), buffer, bytes);
- pthread_mutex_unlock(&out->lock);
+ unlock_output_stream(out);
return ret;
- }
-
- if (out->standby) {
- out->standby = false;
+ } else if (out->standby) {
pthread_mutex_lock(&adev->lock);
ret = qaf_start_output_stream(out);
pthread_mutex_unlock(&adev->lock);
- /* ToDo: If use case is compress offload should return 0 */
- if (ret != 0) {
- out->standby = true;
+ if (ret == 0) {
+ out->standby = false;
+ } else {
goto exit;
}
}
- if (adev->is_channel_status_set == false && (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)){
+ if ((adev->is_channel_status_set == false) && (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
audio_utils_set_hdmi_channel_status(out, (char *)buffer, bytes);
adev->is_channel_status_set = true;
}
- ret = qaf_write_input_buffer(out, buffer, bytes);
- ALOGV("%s, ret [%d] ", __func__, (int)ret);
- if (ret < 0) {
- goto exit;
+ ret = qaf_module_write_input_buffer(out, buffer, bytes);
+ DEBUG_MSG("ret [%d]", (int)ret);
+
+ if (ret >= 0) {
+ bytes = ret;
+ out->written += bytes / ((popcount(out->channel_mask) * sizeof(short)));
}
- out->written += bytes / ((popcount(out->channel_mask) * sizeof(short)));
+
exit:
-
- pthread_mutex_unlock(&out->lock);
+ unlock_output_stream(out);
if (ret < 0) {
if (ret == -EAGAIN) {
- ALOGV("No space available in ms12 driver, post msg to cb thread");
- lock_output_stream(out);
+ DEBUG_MSG("No space available in mm module, post msg to cb thread");
ret = qaf_send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER);
- pthread_mutex_unlock(&out->lock);
bytes = 0;
- }
- if(ret == -ENOMEM || ret == -EPERM){
+ } else if (ret == -ENOMEM || ret == -EPERM) {
if (out->pcm)
- ALOGE("%s: error %d, %s", __func__, (int)ret, pcm_get_error(out->pcm));
+ ERROR_MSG("error %d, %s", (int)ret, pcm_get_error(out->pcm));
qaf_out_standby(&out->stream.common);
- usleep(bytes * 1000000 / audio_stream_out_frame_size(stream) /
- out->stream.common.get_sample_rate(&out->stream.common));
+ usleep(bytes * 1000000
+ / audio_stream_out_frame_size(stream)
+ / out->stream.common.get_sample_rate(&out->stream.common));
}
}
return bytes;
}
-static uint32_t qaf_get_pcm_offload_buffer_size(audio_offload_info_t* info)
+/* Gets PCM offload buffer size for QAF module output. */
+static uint32_t qaf_get_pcm_offload_buffer_size(struct qaf_module *qaf_mod,
+ audio_offload_info_t* info)
{
+ uint32_t samples_per_frame = get_pcm_output_buffer_size_samples(qaf_mod);
uint32_t fragment_size = 0;
- uint32_t bits_per_sample = 16;
- uint32_t pcm_offload_time = QAF_PCM_OFFLOAD_BUFFER_DURATION;
- //duration is set to 32 ms worth of stereo data at 48Khz
- //with 16 bit per sample, modify this when the channel
- //configuration is different
- fragment_size = (pcm_offload_time
- * info->sample_rate
- * (bits_per_sample >> 3)
- * popcount(info->channel_mask))/1000;
- if(fragment_size < MIN_PCM_OFFLOAD_FRAGMENT_SIZE)
+ fragment_size = (samples_per_frame * (info->bit_width >> 3) * popcount(info->channel_mask));
+
+ if (fragment_size < MIN_PCM_OFFLOAD_FRAGMENT_SIZE)
fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE;
- else if(fragment_size > MAX_PCM_OFFLOAD_FRAGMENT_SIZE)
+ else if (fragment_size > MAX_PCM_OFFLOAD_FRAGMENT_SIZE)
fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE;
+
// To have same PCM samples for all channels, the buffer size requires to
// be multiple of (number of channels * bytes per sample)
// For writes to succeed, the buffer must be written at address which is multiple of 32
- fragment_size = ALIGN(fragment_size, ((bits_per_sample >> 3)* popcount(info->channel_mask) * 32));
+ fragment_size = ALIGN(fragment_size,
+ ((info->bit_width >> 3) * popcount(info->channel_mask) * 32));
ALOGI("Qaf PCM offload Fragment size to %d bytes", fragment_size);
return fragment_size;
}
-static int qaf_get_timestamp(struct stream_out *out, uint64_t *frames, struct timespec *timestamp)
+/* Gets buffer latency in samples. */
+static int get_buffer_latency(struct stream_out *out, uint32_t buffer_size, uint32_t *latency)
{
- int ret = 0;
+ unsigned long int samples_in_one_encoded_frame;
+ unsigned long int size_of_one_encoded_frame;
+
+ switch (out->format) {
+ case AUDIO_FORMAT_AC3:
+ samples_in_one_encoded_frame = DD_FRAME_SIZE;
+ size_of_one_encoded_frame = DD_ENCODER_OUTPUT_SIZE;
+ break;
+ case AUDIO_FORMAT_E_AC3:
+ samples_in_one_encoded_frame = DDP_FRAME_SIZE;
+ size_of_one_encoded_frame = DDP_ENCODER_OUTPUT_SIZE;
+ break;
+ case AUDIO_FORMAT_DTS:
+ samples_in_one_encoded_frame = DTS_FRAME_SIZE;
+ size_of_one_encoded_frame = DTS_ENCODER_OUTPUT_SIZE;
+ break;
+ case AUDIO_FORMAT_DTS_HD:
+ samples_in_one_encoded_frame = DTSHD_FRAME_SIZE;
+ size_of_one_encoded_frame = DTSHD_ENCODER_OUTPUT_SIZE;
+ break;
+ case AUDIO_FORMAT_PCM_16_BIT:
+ samples_in_one_encoded_frame = 1;
+ size_of_one_encoded_frame = ((out->bit_width) >> 3) * popcount(out->channel_mask);
+ break;
+ default:
+ *latency = 0;
+ return (-EINVAL);
+ }
+
+ *latency = ((buffer_size * samples_in_one_encoded_frame) / size_of_one_encoded_frame);
+ return 0;
+}
+
+/* Returns the number of frames rendered to outside observer. */
+static int qaf_get_rendered_frames(struct stream_out *out, uint64_t *frames)
+{
+ int ret = 0, i;
struct str_parms *parms;
int value = 0;
- int latency = 0;
+ int module_latency = 0;
+ uint32_t kernel_latency = 0;
+ uint32_t dsp_latency = 0;
int signed_frames = 0;
char* kvpairs = NULL;
+ struct qaf_module *qaf_mod = NULL;
- ALOGV("%s out->format %d", __func__, out->format);
+ DEBUG_MSG("Output Format %d", out->format);
+
+ qaf_mod = get_qaf_module_for_input_stream(out);
+ if ((!qaf_mod) || (!qaf_mod->qaf_audio_stream_get_param)) {
+ return -EINVAL;
+ }
+
+ //Get MM module latency.
kvpairs = qaf_mod->qaf_audio_stream_get_param(out->qaf_stream_handle, "get_latency");
if (kvpairs) {
parms = str_parms_create_str(kvpairs);
- ret = str_parms_get_int(parms, "get_latency", &latency);
+ ret = str_parms_get_int(parms, "get_latency", &module_latency);
if (ret >= 0) {
str_parms_destroy(parms);
parms = NULL;
@@ -497,26 +812,54 @@
free(kvpairs);
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);
- } 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);
+
+ //Get kernel Latency
+ for (i = MAX_QAF_MODULE_OUT - 1; i >= 0; i--) {
+ if (qaf_mod->stream_out[i] == NULL) {
+ continue;
+ } else {
+ unsigned int num_fragments = qaf_mod->stream_out[i]->compr_config.fragments;
+ uint32_t fragment_size = qaf_mod->stream_out[i]->compr_config.fragment_size;
+ uint32_t kernel_buffer_size = num_fragments * fragment_size;
+ get_buffer_latency(qaf_mod->stream_out[i], kernel_buffer_size, &kernel_latency);
+ break;
+ }
}
- if(out->format & AUDIO_FORMAT_PCM_16_BIT) {
- *frames = 0;
- signed_frames = out->written - out->platform_latency;
- // It would be unusual for this value to be negative, but check just in case ...
- if (signed_frames >= 0) {
- *frames = signed_frames;
- }
- clock_gettime(CLOCK_MONOTONIC, timestamp);
+ //Get DSP latency
+ if ((qaf_mod->stream_out[QAF_OUT_OFFLOAD] != NULL)
+ || (qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH] != NULL)) {
+ unsigned int sample_rate = 0;
+
+ if (qaf_mod->stream_out[QAF_OUT_OFFLOAD])
+ sample_rate = qaf_mod->stream_out[QAF_OUT_OFFLOAD]->sample_rate;
+ else if (qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH])
+ sample_rate = qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->sample_rate;
+
+ audio_usecase_t platform_latency =
+ platform_render_latency(qaf_mod->stream_out[QAF_OUT_OFFLOAD]->usecase);
+ dsp_latency = (platform_latency * sample_rate) / 1000000LL;
+ } else if (qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH] != NULL) {
+ unsigned int sample_rate = 0;
+
+ sample_rate = qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]->sample_rate; //TODO: How this sample rate can be used?
+ dsp_latency = (COMPRESS_OFFLOAD_PLAYBACK_LATENCY * sample_rate) / 1000;
+ }
+
+ // MM Module Latency + Kernel Latency + DSP Latency
+ if ( audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl) != NULL) {
+ out->platform_latency = module_latency + audio_extn_bt_hal_get_latency(qaf_mod->bt_hdl);
+ } else {
+ out->platform_latency = (uint32_t)module_latency + kernel_latency + dsp_latency;
+ }
+
+ if (out->format & AUDIO_FORMAT_PCM_16_BIT) {
+ *frames = 0;
+ signed_frames = out->written - out->platform_latency;
+ // It would be unusual for this value to be negative, but check just in case ...
+ if (signed_frames >= 0) {
+ *frames = signed_frames;
+ }
} else if (qaf_mod->qaf_audio_stream_get_param) {
kvpairs = qaf_mod->qaf_audio_stream_get_param(out->qaf_stream_handle, "position");
if (kvpairs) {
@@ -529,122 +872,173 @@
if (signed_frames >= 0) {
*frames = signed_frames;
}
- clock_gettime(CLOCK_MONOTONIC, timestamp);
}
str_parms_destroy(parms);
}
} else {
ret = -EINVAL;
}
+
return ret;
}
static int qaf_out_get_presentation_position(const struct audio_stream_out *stream,
- uint64_t *frames, struct timespec *timestamp)
+ uint64_t *frames,
+ struct timespec *timestamp)
{
struct stream_out *out = (struct stream_out *)stream;
- int ret = -1;
- lock_output_stream(out);
+ int ret = 0;
- 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);
- pthread_mutex_unlock(&out->lock);
+ DEBUG_MSG("Output Stream %p", stream);
+
+ //If QAF passthorugh output stream is active.
+ if (p_qaf->passthrough_out) {
+ if (p_qaf->passthrough_in == out) {
+ //If api is called for QAF passthorugh stream then call the primary HAL api to get the position.
+ pthread_mutex_lock(&p_qaf->lock);
+ ret = p_qaf->passthrough_out->stream.get_presentation_position(
+ (struct audio_stream_out *)p_qaf->passthrough_out,
+ frames,
+ timestamp);
+ pthread_mutex_unlock(&p_qaf->lock);
+ } else {
+ //If api is called for other stream then return zero frames.
+ *frames = 0;
+ clock_gettime(CLOCK_MONOTONIC, timestamp);
+ }
return ret;
}
- ret = qaf_get_timestamp(out, frames, timestamp);
- pthread_mutex_unlock(&out->lock);
+ ret = qaf_get_rendered_frames(out, frames);
+ clock_gettime(CLOCK_MONOTONIC, timestamp);
return ret;
}
+/* Pause the QAF module input stream. */
static int qaf_stream_pause(struct stream_out *out)
{
- ALOGV("%s: %d start", __func__, __LINE__);
- if (!qaf_mod->qaf_audio_stream_pause)
- return -EINVAL;
+ struct qaf_module *qaf_mod = NULL;
+ int ret = -EINVAL;
- return qaf_mod->qaf_audio_stream_pause(out->qaf_stream_handle);
+ qaf_mod = get_qaf_module_for_input_stream(out);
+ if (!qaf_mod || !qaf_mod->qaf_audio_stream_pause) {
+ return -EINVAL;
+ }
+
+ if (out->qaf_stream_handle)
+ ret = qaf_mod->qaf_audio_stream_pause(out->qaf_stream_handle);
+
+ return ret;
}
+/* Pause a QAF input stream. */
static int qaf_out_pause(struct audio_stream_out* stream)
{
struct stream_out *out = (struct stream_out *)stream;
- int status = -ENOSYS;
- ALOGE("%s", __func__);
+ int status = 0;
+ DEBUG_MSG("Output Stream %p", out);
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);
- out->offload_state = OFFLOAD_STATE_PAUSED;
- pthread_mutex_unlock(&out->lock);
- return status;
+
+ //If QAF passthrough is enabled then block the pause on module stream.
+ if (p_qaf->passthrough_out) {
+ pthread_mutex_lock(&p_qaf->lock);
+ //If pause is received for QAF passthorugh stream then call the primary HAL api.
+ if (p_qaf->passthrough_in == out) {
+ status = p_qaf->passthrough_out->stream.pause(
+ (struct audio_stream_out *)p_qaf->passthrough_out);
+ out->offload_state = OFFLOAD_STATE_PAUSED;
+ }
+ pthread_mutex_unlock(&p_qaf->lock);
+ } else {
+ //Pause the module input stream.
+ status = qaf_stream_pause(out);
}
- status = qaf_stream_pause(out);
- pthread_mutex_unlock(&out->lock);
+ unlock_output_stream(out);
return status;
}
-static int qaf_out_drain(struct audio_stream_out* stream,
- audio_drain_type_t type)
+/* Drains a qaf input stream. */
+static int qaf_out_drain(struct audio_stream_out* stream, audio_drain_type_t type)
{
struct stream_out *out = (struct stream_out *)stream;
int status = 0;
- ALOGV("%s stream_handle = %p , format = %x", __func__,
- out->qaf_stream_handle, out->format);
+ DEBUG_MSG("Output Stream %p", out);
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);
- pthread_mutex_unlock(&out->lock);
- return status;
- }
-
- if (out->offload_callback && out->qaf_stream_handle) {
+ //If QAF passthrough is enabled then block the drain on module stream.
+ if (p_qaf->passthrough_out) {
+ pthread_mutex_lock(&p_qaf->lock);
+ //If drain is received for QAF passthorugh stream then call the primary HAL api.
+ if (p_qaf->passthrough_in == out) {
+ status = p_qaf->passthrough_out->stream.drain(
+ (struct audio_stream_out *)p_qaf->passthrough_out, type);
+ }
+ pthread_mutex_unlock(&p_qaf->lock);
+ } else {
+ //Drain the module input stream.
/* Stream stop will trigger EOS and on EOS_EVENT received
- from callback DRAIN_READY command is sent */
+ 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;
- }
+
+ if (status == 0) {
+ struct qaf_module *qaf_mod = get_qaf_module_for_input_stream(out);
+ int index = get_input_stream_index(out);
+ if (qaf_mod && index >= 0) qaf_mod->drain_received[index] = true;
}
}
- pthread_mutex_unlock(&out->lock);
+
+ unlock_output_stream(out);
return status;
}
+/* Flush the QAF module input stream. */
static int audio_extn_qaf_stream_flush(struct stream_out *out)
{
- ALOGV("%s: %d exit", __func__, __LINE__);
- if (!qaf_mod->qaf_audio_stream_flush)
- return -EINVAL;
+ DEBUG_MSG("Output Stream %p", out);
+ int ret = -EINVAL;
+ struct qaf_module *qaf_mod = NULL;
- return qaf_mod->qaf_audio_stream_flush(out->qaf_stream_handle);
+ qaf_mod = get_qaf_module_for_input_stream(out);
+ if ((!qaf_mod) || (!qaf_mod->qaf_audio_stream_flush)) {
+ return -EINVAL;
+ }
+
+ if (out->qaf_stream_handle)
+ ret = qaf_mod->qaf_audio_stream_flush(out->qaf_stream_handle);
+
+ return ret;
}
+/* Flush the QAF input stream. */
static int qaf_out_flush(struct audio_stream_out* stream)
{
struct stream_out *out = (struct stream_out *)stream;
- ALOGV("%s", __func__);
- int status = -ENOSYS;
+ int status = 0;
+ DEBUG_MSG("Output Stream %p", out);
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);
- out->offload_state = OFFLOAD_STATE_IDLE;
- pthread_mutex_unlock(&out->lock);
- return status;
+
+ //If QAF passthrough is active then block the flush on module input streams.
+ if (p_qaf->passthrough_out) {
+ pthread_mutex_lock(&p_qaf->lock);
+ //If flush is received for the QAF passthrough stream then call the primary HAL api.
+ if (p_qaf->passthrough_in == out) {
+ status = p_qaf->passthrough_out->stream.flush(
+ (struct audio_stream_out *)p_qaf->passthrough_out);
+ out->offload_state = OFFLOAD_STATE_IDLE;
+ }
+ pthread_mutex_unlock(&p_qaf->lock);
+ } else {
+ //Flush the module input stream.
+ status = audio_extn_qaf_stream_flush(out);
}
- status = audio_extn_qaf_stream_flush(out);
- pthread_mutex_unlock(&out->lock);
- ALOGV("%s Exit", __func__);
+ unlock_output_stream(out);
+ DEBUG_MSG("Exit");
return status;
}
@@ -652,289 +1046,395 @@
{
struct stream_out *out = (struct stream_out *)stream;
uint32_t latency = 0;
+ struct qaf_module *qaf_mod = NULL;
+ DEBUG_MSG("Output Stream %p", out);
-
- 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);
- ALOGV("%s: latency = %u", __FUNCTION__, latency);
- pthread_mutex_unlock(&out->lock);
- return latency;
+ qaf_mod = get_qaf_module_for_input_stream(out);
+ if (!qaf_mod) {
+ return 0;
}
- pthread_mutex_unlock(&out->lock);
- if (is_offload_usecase(out->usecase)) {
- latency = COMPRESS_OFFLOAD_PLAYBACK_LATENCY;
+ //If QAF passthrough is active then block the get latency on module input streams.
+ if (p_qaf->passthrough_out) {
+ pthread_mutex_lock(&p_qaf->lock);
+ //If get latency is called for the QAF passthrough stream then call the primary HAL api.
+ if (p_qaf->passthrough_in == out) {
+ latency = p_qaf->passthrough_out->stream.get_latency(
+ (struct audio_stream_out *)p_qaf->passthrough_out);
+ }
+ pthread_mutex_unlock(&p_qaf->lock);
} else {
- latency = PCM_OFFLOAD_PLAYBACK_LATENCY;
- }
-
- if (audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl) != NULL) {
-
if (is_offload_usecase(out->usecase)) {
- latency = audio_extn_bt_hal_get_latency(qaf_mod->bt_hdl) + QAF_COMPRESS_OFFLOAD_PROCESSING_LATENCY;
+ latency = COMPRESS_OFFLOAD_PLAYBACK_LATENCY;
} else {
- latency = audio_extn_bt_hal_get_latency(qaf_mod->bt_hdl) + QAF_PCM_OFFLOAD_PROCESSING_LATENCY;
+ uint32_t sample_rate = 0;
+ latency = QAF_MODULE_PCM_INPUT_BUFFER_LATENCY; //Input latency
+
+ if (qaf_mod->stream_out[QAF_OUT_OFFLOAD])
+ sample_rate = qaf_mod->stream_out[QAF_OUT_OFFLOAD]->sample_rate;
+ else if (qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH])
+ sample_rate = qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->sample_rate;
+
+ if (sample_rate) {
+ latency += (get_pcm_output_buffer_size_samples(qaf_mod) * 1000) / out->sample_rate;
+ }
+ }
+
+ if ( audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl) != NULL) {
+ if (is_offload_usecase(out->usecase)) {
+ latency = audio_extn_bt_hal_get_latency(qaf_mod->bt_hdl) +
+ QAF_COMPRESS_OFFLOAD_PROCESSING_LATENCY;
+ } else {
+ latency = audio_extn_bt_hal_get_latency(qaf_mod->bt_hdl) +
+ QAF_PCM_OFFLOAD_PROCESSING_LATENCY;
+ }
}
}
- ALOGV("%s: Latency %d", __func__, latency);
+
+ DEBUG_MSG("Latency %d", latency);
return latency;
}
-static void notify_event_callback(
- audio_session_handle_t session_handle __unused, void *prv_data,
- void *buf, audio_event_id_t event_id, int size, int device)
+static bool check_and_get_compressed_device_format(int device, int *format)
+{
+ switch (device) {
+ case (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_COMPRESSED_OUT_DD):
+ *format = AUDIO_FORMAT_AC3;
+ return true;
+ case (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_COMPRESSED_OUT_DDP):
+ *format = AUDIO_FORMAT_E_AC3;
+ return true;
+ case (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_FORMAT_DTS):
+ *format = AUDIO_FORMAT_DTS;
+ return true;
+ case (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_FORMAT_DTS_HD):
+ *format = AUDIO_FORMAT_DTS_HD;
+ return true;
+ default:
+ return false;
+ }
+}
+
+/* Call back function for mm module. */
+static void notify_event_callback(audio_session_handle_t session_handle /*__unused*/,
+ void *prv_data,
+ void *buf,
+ audio_event_id_t event_id,
+ int size,
+ int device) //TODO: add media format as well.
{
-/*
- For SPKR:
- 1. Open pcm device if device_id passed to it SPKR and write the data to
- pcm device
+ /*
+ For SPKR:
+ 1. Open pcm device if device_id passed to it SPKR and write the data to
+ pcm device
- For HDMI
- 1.Open compress device for HDMI(PCM or AC3) based on current hdmi o/p format
- 2.create offload_callback thread to receive async events
- 3.Write the data to compress device. If not all the data is consumed by
- the driver, add a command to offload_callback thread.
-*/
- int ret;
+ For HDMI
+ 1.Open compress device for HDMI(PCM or AC3) based on current hdmi o/p format and write
+ data to the HDMI device.
+ */
+ int ret, i;
audio_output_flags_t flags;
- struct qaf* qaf_module = (struct qaf* ) prv_data;
+ struct qaf_module* qaf_mod = (struct qaf_module*)prv_data;
struct audio_stream_out *bt_stream = NULL;
+ int format;
- ALOGV("%s device 0x%X, %d in event = %d",
- __func__, device, __LINE__, event_id);
+ DEBUG_MSG("Device 0x%X, Event = 0x%X", device, event_id);
+ pthread_mutex_lock(&p_qaf->lock);
if (event_id == AUDIO_DATA_EVENT) {
- ALOGVV("Device id %x %s %d, bytes to written %d",
- device, __func__,__LINE__, size);
+ DEBUG_MSG("Device id 0x%X, bytes to write %d", device, size);
- if ((qaf_mod->qaf_passthrough_out != NULL) && qaf_mod->hdmi_connect) {
- pthread_mutex_lock(&qaf_module->lock);
- 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));
- qaf_mod->qaf_compr_offload_out = NULL;
- }
- if (qaf_mod->qaf_compr_offload_out_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;
- }
- pthread_mutex_unlock(&qaf_module->lock);
- ALOGV("%s %d DROPPING DATA", __func__, __LINE__);
+ if (p_qaf->passthrough_out != NULL) {
+ //If QAF passthrough is active then all the module output will be dropped.
+ pthread_mutex_unlock(&p_qaf->lock);
+ DEBUG_MSG("QAF-PSTH is active, DROPPING DATA!");
return;
- } else {
- if (qaf_mod->qaf_passthrough_out != 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;
- qaf_mod->main_output_active = false;
- pthread_mutex_unlock(&qaf_module->lock);
+ }
+
+ if (check_and_get_compressed_device_format(device, &format)) {
+ /*
+ * CASE 1: Transcoded output of mm module.
+ * If HDMI is not connected then drop the data.
+ * Only one HDMI output can be supported from all the mm modules of QAF.
+ * Multi-Channel PCM HDMI output streams will be closed from all the mm modules.
+ * If transcoded output of other module is already enabled then this data will be dropped.
+ */
+
+ if (!p_qaf->hdmi_connect) {
+ DEBUG_MSG("HDMI not connected, DROPPING DATA!");
+ pthread_mutex_unlock(&p_qaf->lock);
+ return;
+ }
+
+ //Closing all the PCM HDMI output stream from QAF.
+ close_all_pcm_hdmi_output();
+
+ if (!p_qaf->passthrough_enabled
+ && !(qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH])) {
+
+ struct audio_config config;
+ audio_devices_t devices;
+
+ //TODO: need to update the actual sample rate.
+ config.sample_rate = config.offload_info.sample_rate =
+ QAF_OUTPUT_SAMPLING_RATE;
+ config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
+ config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
+ config.format = config.offload_info.format = format;
+ //TODO: need to update the actual bit width.
+ config.offload_info.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+ //TODO: What is the relevance of num of channels.
+ config.offload_info.channel_mask = config.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
+
+ flags = (AUDIO_OUTPUT_FLAG_NON_BLOCKING
+ | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD
+ | AUDIO_OUTPUT_FLAG_DIRECT);
+ devices = AUDIO_DEVICE_OUT_AUX_DIGITAL;
+
+ ret = adev_open_output_stream((struct audio_hw_device *)p_qaf->adev,
+ QAF_DEFAULT_COMPR_PASSTHROUGH_HANDLE,
+ devices,
+ flags,
+ &config,
+ (struct audio_stream_out **)&(qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]),
+ NULL);
+ if (ret < 0) {
+ ERROR_MSG("adev_open_output_stream failed with ret = %d!", ret);
+ pthread_mutex_unlock(&p_qaf->lock);
+ return;
+ }
+
+ if (format & AUDIO_COMPRESSED_OUT_DDP) {
+ qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]->compr_config.fragment_size =
+ COMPRESS_PASSTHROUGH_DDP_FRAGMENT_SIZE;
+ }
+ qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]->compr_config.fragments =
+ COMPRESS_OFFLOAD_NUM_FRAGMENTS;
+
+ p_qaf->passthrough_enabled = true;
+ }
+
+ if (qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]) {
+ ret = qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]->stream.write(
+ (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH],
+ buf,
+ size);
}
}
- pthread_mutex_lock(&qaf_module->lock);
- if ((device ==
- (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_COMPRESSED_OUT_DD)) ||
- (device ==
- (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_COMPRESSED_OUT_DDP))) {
+ else if ((device & AUDIO_DEVICE_OUT_AUX_DIGITAL)
+ && (p_qaf->hdmi_connect)
+ && (p_qaf->hdmi_sink_channels > 2)) {
- if (NULL == qaf_mod->qaf_compr_passthrough_out &&
- qaf_mod->hdmi_connect) {
+ /* CASE 2: Multi-Channel PCM output to HDMI.
+ * If any other HDMI output is already enabled then this has to be dropped.
+ */
+ bool create_mch_out_stream = false;
+
+ if (p_qaf->passthrough_enabled) {
+ //Closing all the multi-Channel PCM HDMI output stream from QAF.
+ close_all_pcm_hdmi_output();
+
+ //If passthrough is active then pcm hdmi output has to be dropped.
+ pthread_mutex_unlock(&p_qaf->lock);
+ DEBUG_MSG("Compressed passthrough enabled, DROPPING DATA!");
+ return;
+ }
+
+ if (!p_qaf->mch_pcm_hdmi_enabled && !(qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH])) {
struct audio_config config;
audio_devices_t devices;
- if (qaf_mod->qaf_compr_offload_out_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;
- }
-
+ //TODO: need to update the actual sample rate.
config.sample_rate = config.offload_info.sample_rate =
- QAF_OUTPUT_SAMPLING_RATE;
+ QAF_OUTPUT_SAMPLING_RATE;
config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
-
- if (device ==
- (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_COMPRESSED_OUT_DDP)) {
- config.format = config.offload_info.format =
- AUDIO_FORMAT_E_AC3;
- } else {
- config.format = config.offload_info.format =
- AUDIO_FORMAT_AC3;
- }
-
+ config.offload_info.format = config.format = AUDIO_FORMAT_PCM_16_BIT;
+ //TODO: need to update the actual bit width.
config.offload_info.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
- config.offload_info.channel_mask = config.channel_mask =
- AUDIO_CHANNEL_OUT_5POINT1;
- flags = (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|
- AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_DIRECT_PCM);
- devices = AUDIO_DEVICE_OUT_AUX_DIGITAL;
- ret = adev_open_output_stream(
- (struct audio_hw_device *) qaf_mod->adev,
- QAF_DEFAULT_COMPR_PASSTHROUGH_HANDLE, devices,
- flags, &config,
- (struct audio_stream_out **)
- &(qaf_mod->qaf_compr_passthrough_out), 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 =
- 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(
- (struct audio_stream_out *)
- qaf_mod->qaf_compr_passthrough_out, buf, size);
- }
- } else if ((device & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
- ((qaf_mod->hdmi_connect) &&
- (qaf_mod->qaf_passthrough_out == NULL) &&
- (qaf_mod->hdmi_sink_channels > 2))) {
- if (NULL == qaf_mod->qaf_compr_offload_out_mch) {
- struct audio_config config;
- audio_devices_t devices;
-
- config.sample_rate = config.offload_info.sample_rate =
- QAF_OUTPUT_SAMPLING_RATE;
- config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
- config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
- config.offload_info.format = AUDIO_FORMAT_PCM_16_BIT;
- config.offload_info.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
- config.format = AUDIO_FORMAT_PCM_16_BIT;
- devices = AUDIO_DEVICE_NONE;
-
- if (qaf_mod->hdmi_sink_channels == 8) {
+ if (p_qaf->hdmi_sink_channels == 8) {
config.offload_info.channel_mask = config.channel_mask =
- AUDIO_CHANNEL_OUT_7POINT1;
- } else if (qaf_mod->hdmi_sink_channels == 6) {
+ AUDIO_CHANNEL_OUT_7POINT1;
+ } else if (p_qaf->hdmi_sink_channels == 6) {
config.offload_info.channel_mask = config.channel_mask =
- AUDIO_CHANNEL_OUT_5POINT1;
+ AUDIO_CHANNEL_OUT_5POINT1;
} else {
config.offload_info.channel_mask = config.channel_mask =
- AUDIO_CHANNEL_OUT_STEREO;
+ AUDIO_CHANNEL_OUT_STEREO;
}
- 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);
+ devices = AUDIO_DEVICE_OUT_AUX_DIGITAL;
+ flags = (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_DIRECT_PCM);
+
+ ret = adev_open_output_stream((struct audio_hw_device *)p_qaf->adev,
+ QAF_DEFAULT_COMPR_AUDIO_HANDLE,
+ devices,
+ flags,
+ &config,
+ (struct audio_stream_out **)&(qaf_mod->stream_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);
+ ERROR_MSG("adev_open_output_stream failed with ret = %d!", ret);
+ pthread_mutex_unlock(&p_qaf->lock);
return;
}
- qaf_mod->qaf_compr_offload_out_mch->compr_config.fragments =
- COMPRESS_OFFLOAD_NUM_FRAGMENTS;
- qaf_mod->qaf_compr_offload_out_mch->compr_config.fragment_size =
- qaf_get_pcm_offload_buffer_size(&config.offload_info);
+
+ qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->compr_config.fragments =
+ COMPRESS_OFFLOAD_NUM_FRAGMENTS;
+ qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->compr_config.fragment_size =
+ qaf_get_pcm_offload_buffer_size(qaf_mod, &config.offload_info);
+
+ p_qaf->mch_pcm_hdmi_enabled = true;
+
+ if (qaf_mod->stream_in[QAF_IN_MAIN]
+ && qaf_mod->stream_in[QAF_IN_MAIN]->client_callback != NULL) {
+
+ qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->stream.set_callback(
+ (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH],
+ qaf_mod->stream_in[QAF_IN_MAIN]->client_callback,
+ qaf_mod->stream_in[QAF_IN_MAIN]->client_cookie);
+ } else if (qaf_mod->stream_in[QAF_IN_PCM]
+ && qaf_mod->stream_in[QAF_IN_PCM]->client_callback != NULL) {
+
+ qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->stream.set_callback(
+ (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH],
+ qaf_mod->stream_in[QAF_IN_PCM]->client_callback,
+ qaf_mod->stream_in[QAF_IN_PCM]->client_cookie);
+ }
+
+ 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->stream_out[QAF_OUT_OFFLOAD_MCH]->standby)
+ qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->stream.write(
+ (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH], NULL, 0);
+
+ lock_output_stream(qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]);
+ ret = audio_extn_out_set_param_data(
+ qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH],
+ AUDIO_EXTN_PARAM_ADSP_STREAM_CMD,
+ (audio_extn_param_payload *)&qaf_mod->adsp_hdlr_config[index].event_params);
+ unlock_output_stream(qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]);
+
+ }
}
- if (qaf_mod->qaf_compr_offload_out_mch) {
- ret = qaf_mod->qaf_compr_offload_out_mch->stream.write(
- (struct audio_stream_out *)
- qaf_mod->qaf_compr_offload_out_mch, buf, size);
+ if (qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]) {
+ ret = qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->stream.write(
+ (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH],
+ buf,
+ size);
}
- } else {
+ }
+ else {
+ /* CASE 3: PCM output.
+ */
bt_stream = audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl);
if (bt_stream != NULL) {
- if (qaf_mod->qaf_compr_offload_out) {
- 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;
+ if (qaf_mod->stream_out[QAF_OUT_OFFLOAD]) {
+ adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
+ (struct audio_stream_out *)(qaf_mod->stream_out[QAF_OUT_OFFLOAD]));
+ qaf_mod->stream_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) {
+ audio_extn_bt_hal_out_write(p_qaf->bt_hdl, buf, size);
+ } else if (NULL == qaf_mod->stream_out[QAF_OUT_OFFLOAD]) {
struct audio_config config;
audio_devices_t devices;
+ //TODO: need to update the actual sample rate.
config.sample_rate = config.offload_info.sample_rate =
- QAF_OUTPUT_SAMPLING_RATE;
+ QAF_OUTPUT_SAMPLING_RATE;
config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
- config.offload_info.format = AUDIO_FORMAT_PCM_16_BIT;
+ config.offload_info.format = config.format = AUDIO_FORMAT_PCM_16_BIT;
+ //TODO: need to update the actual bit width.
config.offload_info.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
- config.format = AUDIO_FORMAT_PCM_16_BIT;
- config.offload_info.channel_mask = config.channel_mask =
- AUDIO_CHANNEL_OUT_STEREO;
- devices = AUDIO_DEVICE_OUT_SPEAKER;
- flags = (AUDIO_OUTPUT_FLAG_DIRECT|
- AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|
- AUDIO_OUTPUT_FLAG_DIRECT_PCM);
+ //TODO: need to update the actual num channels.
+ config.offload_info.channel_mask = config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+
+ if (qaf_mod->stream_in[QAF_IN_MAIN])
+ devices = qaf_mod->stream_in[QAF_IN_MAIN]->devices;
+ else
+ devices = qaf_mod->stream_in[QAF_IN_PCM]->devices;
+
+ //If multi channel pcm or passthrough is already enabled then remove the hdmi flag from device.
+ if (p_qaf->mch_pcm_hdmi_enabled || p_qaf->passthrough_enabled) {
+ if (devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
+ devices ^= AUDIO_DEVICE_OUT_AUX_DIGITAL;
+ }
+ if (devices == 0) {
+ devices = device;
+ }
+
+ flags = (AUDIO_OUTPUT_FLAG_DIRECT | 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);
+ ret = adev_open_output_stream((struct audio_hw_device *)p_qaf->adev,
+ QAF_DEFAULT_COMPR_AUDIO_HANDLE,
+ devices,
+ flags,
+ &config,
+ (struct audio_stream_out **)&(qaf_mod->stream_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);
+ ERROR_MSG("adev_open_output_stream failed with ret = %d!", ret);
+ pthread_mutex_unlock(&p_qaf->lock);
return;
}
- qaf_mod->qaf_compr_offload_out->compr_config.fragments =
- COMPRESS_OFFLOAD_NUM_FRAGMENTS;
- qaf_mod->qaf_compr_offload_out->compr_config.fragment_size =
- qaf_get_pcm_offload_buffer_size(&config.offload_info);
- qaf_mod->qaf_compr_offload_out->info.channel_mask =
- config.offload_info.channel_mask;
- qaf_mod->qaf_compr_offload_out->info.format =
- config.offload_info.format;
- qaf_mod->qaf_compr_offload_out->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->vol_left, qaf_mod->vol_right);
- }
+ if (qaf_mod->stream_in[QAF_IN_MAIN]
+ && qaf_mod->stream_in[QAF_IN_MAIN]->client_callback != NULL) {
- if (!qaf_mod->hdmi_connect &&
- (qaf_mod->qaf_compr_passthrough_out ||
- qaf_mod->qaf_compr_offload_out_mch)) {
- qaf_mod->passthrough_enabled = 0;
- if (qaf_mod->qaf_compr_passthrough_out) {
- 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->stream_out[QAF_OUT_OFFLOAD]->stream.set_callback(
+ (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD],
+ qaf_mod->stream_in[QAF_IN_MAIN]->client_callback,
+ qaf_mod->stream_in[QAF_IN_MAIN]->client_cookie);
+ } else if (qaf_mod->stream_in[QAF_IN_PCM]
+ && qaf_mod->stream_in[QAF_IN_PCM]->client_callback != NULL) {
+
+ qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.set_callback(
+ (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD],
+ qaf_mod->stream_in[QAF_IN_PCM]->client_callback,
+ qaf_mod->stream_in[QAF_IN_PCM]->client_cookie);
}
- if (qaf_mod->qaf_compr_offload_out_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->stream_out[QAF_OUT_OFFLOAD]->compr_config.fragments =
+ COMPRESS_OFFLOAD_NUM_FRAGMENTS;
+ qaf_mod->stream_out[QAF_OUT_OFFLOAD]->compr_config.fragment_size =
+ qaf_get_pcm_offload_buffer_size(qaf_mod, &config.offload_info);
+
+ if (qaf_mod->is_vol_set) {
+ DEBUG_MSG("Setting Volume Left[%f], Right[%f]", qaf_mod->vol_left, qaf_mod->vol_right);
+ qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.set_volume(
+ (struct audio_stream_out *)qaf_mod->stream_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->stream_out[QAF_OUT_OFFLOAD]->standby) {
+ qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.write(
+ (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD], NULL, 0);
+ }
+
+ lock_output_stream(qaf_mod->stream_out[QAF_OUT_OFFLOAD]);
+ ret = audio_extn_out_set_param_data(
+ qaf_mod->stream_out[QAF_OUT_OFFLOAD],
+ AUDIO_EXTN_PARAM_ADSP_STREAM_CMD,
+ (audio_extn_param_payload *)&qaf_mod->adsp_hdlr_config[index].event_params);
+ unlock_output_stream(qaf_mod->stream_out[QAF_OUT_OFFLOAD]);
}
}
@@ -942,100 +1442,254 @@
* 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(
- (struct audio_stream_out *)
- qaf_mod->qaf_compr_offload_out, buf, size);
+ if (qaf_mod->stream_out[QAF_OUT_OFFLOAD]) {
+ ret = qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.write(
+ (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD],
+ buf,
+ size);
}
}
- ALOGVV("%s:%d stream write ret = %d", __func__, __LINE__, ret);
- pthread_mutex_unlock(&qaf_module->lock);
- } else if (event_id == AUDIO_EOS_MAIN_DD_DDP_EVENT
+ DEBUG_MSG("Bytes written = %d", ret);
+ }
+ else if (event_id == AUDIO_EOS_MAIN_DD_DDP_EVENT
|| 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_mod->stream_in[QAF_IN_MAIN];
+ struct stream_out *out_assoc = qaf_mod->stream_in[QAF_IN_ASSOC];
+ bool *main_drain_received = &qaf_mod->drain_received[QAF_IN_MAIN];
+ bool *assoc_drain_received = &qaf_mod->drain_received[QAF_IN_ASSOC];
/**
* TODO:: Only DD/DDP Associate Eos is handled, need to add support
* for other formats.
*/
- if (event_id == AUDIO_EOS_ASSOC_DD_DDP_EVENT && out_assoc != NULL) {
+ if (event_id == AUDIO_EOS_ASSOC_DD_DDP_EVENT
+ && (out_assoc != NULL)
+ && (*assoc_drain_received)) {
+
lock_output_stream(out_assoc);
- out_assoc->offload_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL,
- out_assoc->offload_cookie);
- pthread_mutex_unlock(&out_assoc->lock);
- qaf_module->stream_drain_assoc = NULL;
- } else if (out != NULL) {
+ out_assoc->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out_assoc->client_cookie);
+ *assoc_drain_received = false;
+ unlock_output_stream(out_assoc);
+ DEBUG_MSG("sent associated DRAIN_READY");
+ } else if ((out != NULL) && (*main_drain_received)) {
lock_output_stream(out);
- out->offload_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL,
- out->offload_cookie);
- pthread_mutex_unlock(&out->lock);
- qaf_module->stream_drain_main = NULL;
- ALOGV("%s %d sent DRAIN_READY", __func__, __LINE__);
+ out->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out->client_cookie);
+ *main_drain_received = false;
+ unlock_output_stream(out);
+ DEBUG_MSG("sent main DRAIN_READY");
}
}
- ALOGV("%s %d", __func__, __LINE__);
+#if 0
+ else if (event_id == AUDIO_MAIN_EOS_EVENT || event_id == AUDIO_ASSOC_EOS_EVENT) { //TODO: For DTS
+ struct stream_out *out = NULL;
+ bool *drain_received = NULL;
+
+ if (event_id == AUDIO_MAIN_EOS_EVENT) {
+ out = qaf_mod->stream_in[QAF_IN_MAIN];
+ drain_received = &qaf_mod->drain_received[QAF_IN_MAIN];
+ } else {
+ out = qaf_mod->stream_in[QAF_IN_ASSOC];
+ drain_received = &qaf_mod->drain_received[QAF_IN_ASSOC];
+ }
+
+ if ((out != NULL) && (*drain_received)) {
+ lock_output_stream(out);
+ out->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out->client_cookie);
+ *drain_received = false;
+ unlock_output_stream(out);
+ DEBUG_MSG("sent DRAIN_READY");
+ }
+ }
+#endif
+
+ pthread_mutex_unlock(&p_qaf->lock);
+ return;
}
-static int qaf_session_close()
+/* Close the mm module session. */
+static int qaf_session_close(struct qaf_module* qaf_mod)
{
- ALOGV("%s %d", __func__, __LINE__);
- if (qaf_mod != NULL) {
- if (!qaf_mod->qaf_audio_session_close)
- return -EINVAL;
+ int j;
+ //Check if all streams are closed or not.
+ for (j = 0; j < MAX_QAF_MODULE_IN; j++) {
+ if (qaf_mod->stream_in[j] != NULL) {
+ break;
+ }
+ }
+ if (j != MAX_QAF_MODULE_IN) {
+ return 0; //Some stream is already active, Can not close session.
+ }
+
+ if (qaf_mod->session_handle != NULL && qaf_mod->qaf_audio_session_close) {
qaf_mod->qaf_audio_session_close(qaf_mod->session_handle);
qaf_mod->session_handle = NULL;
- pthread_mutex_destroy(&qaf_mod->lock);
+ qaf_mod->is_vol_set = false;
+ memset(qaf_mod->drain_received, 0, sizeof(qaf_mod->drain_received));
}
+
+ for (j = 0; j < MAX_QAF_MODULE_OUT; j++) {
+ if (qaf_mod->stream_out[j]) {
+ adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
+ (struct audio_stream_out *)(qaf_mod->stream_out[j]));
+ qaf_mod->stream_out[j] = NULL;
+ }
+ }
+
+ DEBUG_MSG("Session Closed.");
+
return 0;
}
+/* Close the stream of QAF module. */
static int qaf_stream_close(struct stream_out *out)
{
- int ret = 0;
- ALOGV( "%s %d", __func__, __LINE__);
- if (!qaf_mod->qaf_audio_stream_close)
+ int ret = -EINVAL;
+ struct qaf_module *qaf_mod = NULL;
+ int index = -1;
+ DEBUG_MSG("Flag [0x%x], Stream handle [%p]", out->flags, out->qaf_stream_handle);
+
+ qaf_mod = get_qaf_module_for_input_stream(out);
+ index = get_input_stream_index(out);
+
+ if (!qaf_mod || !qaf_mod->qaf_audio_stream_close || index < 0) {
return -EINVAL;
+ }
+
+ qaf_mod->stream_in[index] = NULL;
+ memset(&qaf_mod->adsp_hdlr_config[index], 0, sizeof(struct qaf_adsp_hdlr_config_state));
+
+ lock_output_stream(out);
if (out->qaf_stream_handle) {
- ALOGV( "%s %d output active flag is %x and stream handle %p", __func__, __LINE__, out->flags, out->qaf_stream_handle);
- if ((out->flags & AUDIO_OUTPUT_FLAG_ASSOCIATED) && (out->flags & AUDIO_OUTPUT_FLAG_MAIN)) { /* Close for Stream with Main and Associated Content*/
- qaf_mod->main_output_active = false;
- qaf_mod->assoc_output_active = false;
- } else if (out->flags & AUDIO_OUTPUT_FLAG_MAIN) {/*Close for Main Stream*/
- qaf_mod->main_output_active = false;
- qaf_mod->assoc_output_active = false; /* TODO to remove resetting associated stream active flag when main stream is closed*/
- } else if (out->flags & AUDIO_OUTPUT_FLAG_ASSOCIATED) { /*Close for Associated Stream*/
- qaf_mod->assoc_output_active = false;
- } else { /*Close for Local Playback*/
- qaf_mod->main_output_active = false;
- }
ret = qaf_mod->qaf_audio_stream_close(out->qaf_stream_handle);
out->qaf_stream_handle = NULL;
}
- ALOGV( "%s %d", __func__, __LINE__);
+ unlock_output_stream(out);
+
+ //If all streams are closed then close the session.
+ qaf_session_close(qaf_mod);
+
+ DEBUG_MSG();
return ret;
}
-static int qaf_stream_open(struct stream_out *out, struct audio_config *config, audio_output_flags_t flags, audio_devices_t devices)
+/* Open a MM module session with QAF. */
+static int audio_extn_qaf_session_open(mm_module_type mod_type)
{
- int status = 0;
ALOGV("%s %d", __func__, __LINE__);
+ unsigned char* license_data = NULL;
+ device_license_config_t lic_config = {0};
+ int ret = -ENOSYS, size = 0;
+ char value[PROPERTY_VALUE_MAX] = {0};
+ struct qaf_module *qaf_mod = NULL;
- if (!qaf_mod->qaf_audio_stream_open)
- return -EINVAL;
+ if (mod_type >= MAX_MM_MODULE_TYPE || !(p_qaf->qaf_mod[mod_type].qaf_audio_session_open))
+ return -ENOTSUP; //Not supported by QAF module.
- if (audio_extn_qaf_passthrough_enabled(out) && qaf_mod->hdmi_connect) {
- ALOGV("%s %d passthrough is enabled", __func__, __LINE__);
- status = create_output_stream(out, config, flags, devices, QAF_DEFAULT_PASSTHROUGH_HANDLE);
- if (status < 0) {
- ALOGE("%s: adev_open_output_stream failed with ret = %d!", __func__, status);
+ pthread_mutex_lock(&p_qaf->lock);
+
+ qaf_mod = &(p_qaf->qaf_mod[mod_type]);
+
+ //If session is already opened then return.
+ if (qaf_mod->session_handle) {
+ DEBUG_MSG("Session is already opened.");
+ pthread_mutex_unlock(&p_qaf->lock);
+ return 0;
+ }
+
+ if (mod_type == MS12) {
+ //Getting the license
+ license_data = platform_get_license((struct audio_hw_device *)(p_qaf->adev->platform),
+ &size);
+ if (!license_data) {
+ ERROR_MSG("License data is not present.");
+ pthread_mutex_unlock(&p_qaf->lock);
return -EINVAL;
}
- return 0;
+
+ lic_config.p_license = (unsigned char*)calloc(1, size);
+ if (lic_config.p_license == NULL) {
+ ERROR_MSG("Out of Memory");
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ lic_config.l_size = size;
+ memcpy(lic_config.p_license, license_data, size);
+
+ if (property_get("audio.qaf.manufacturer", value, "") && atoi(value)) {
+ lic_config.manufacturer_id = (unsigned long)atoi(value);
+ } else {
+ ERROR_MSG("audio.qaf.manufacturer id is not set");
+ ret = -EINVAL;
+ goto exit;
+ }
+ }
+
+ ret = qaf_mod->qaf_audio_session_open(&qaf_mod->session_handle,
+ (void *)(qaf_mod),
+ (void *)&lic_config);
+ if (ret < 0) {
+ ERROR_MSG("Error in session open %d", ret);
+ goto exit;
+ }
+
+ if (qaf_mod->session_handle == NULL) {
+ ERROR_MSG("Session handle is NULL.");
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ if (qaf_mod->qaf_register_event_callback)
+ qaf_mod->qaf_register_event_callback(qaf_mod->session_handle,
+ qaf_mod,
+ ¬ify_event_callback,
+ AUDIO_DATA_EVENT);
+
+ set_hdmi_configuration_to_module();
+
+exit:
+ if (license_data != NULL) {
+ free(license_data);
+ license_data = NULL;
+ }
+ if (lic_config.p_license != NULL) {
+ free(lic_config.p_license);
+ lic_config.p_license = NULL;
+ }
+
+ pthread_mutex_unlock(&p_qaf->lock);
+ return ret;
+}
+
+/* opens a stream in QAF module. */
+static int qaf_stream_open(struct stream_out *out,
+ struct audio_config *config,
+ audio_output_flags_t flags,
+ audio_devices_t devices)
+{
+ int status = -EINVAL;
+ mm_module_type mmtype = get_mm_module_for_format(config->format);
+ struct qaf_module* qaf_mod = NULL;
+ DEBUG_MSG("Flags 0x%x, Device 0x%x", flags, devices);
+
+ if (mmtype >= MAX_MM_MODULE_TYPE
+ || p_qaf->qaf_mod[mmtype].qaf_audio_session_open == NULL
+ || p_qaf->qaf_mod[mmtype].qaf_audio_stream_open == NULL) {
+ ERROR_MSG("Unsupported Stream");
+ return -ENOTSUP;
+ }
+
+ //Open the module session, if not opened already.
+ status = audio_extn_qaf_session_open(mmtype);
+ qaf_mod = &(p_qaf->qaf_mod[mmtype]);
+
+ if ((status != 0) || (qaf_mod->session_handle == NULL)) {
+ ERROR_MSG("Failed to open session.");
+ return status;
}
audio_stream_config_t input_config;
@@ -1043,186 +1697,163 @@
input_config.channels = popcount(config->channel_mask);
input_config.format = config->format;
- if ((config->format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC) {
- input_config.format = AUDIO_FORMAT_AAC;
- } else if((config->format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC_ADTS) {
- input_config.format = AUDIO_FORMAT_AAC_ADTS;
+ if (input_config.format != AUDIO_FORMAT_PCM_16_BIT) {
+ input_config.format &= AUDIO_FORMAT_MAIN_MASK;
}
- ALOGV("%s %d audio_stream_open sample_rate(%d) channels(%d) devices(%#x) flags(%#x) format(%#x)\
- ",__func__, __LINE__, input_config.sample_rate, input_config.channels, devices, flags, input_config.format);
+ DEBUG_MSG("stream_open sample_rate(%d) channels(%d) devices(%#x) flags(%#x) format(%#x)",
+ input_config.sample_rate, input_config.channels, devices, flags, input_config.format);
- /* 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);
- } else if (input_config.format == AUDIO_FORMAT_AC3 ||
- input_config.format == AUDIO_FORMAT_E_AC3 ||
- input_config.format == AUDIO_FORMAT_AC4 ||
- input_config.format == AUDIO_FORMAT_AAC ||
- input_config.format == AUDIO_FORMAT_AAC_ADTS) {
- if (qaf_mod->main_output_active == false) {
- if ((flags & AUDIO_OUTPUT_FLAG_MAIN) && (flags & AUDIO_OUTPUT_FLAG_ASSOCIATED)) {
- 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 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;
- }
- } 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;
- }
- } else if (flags & AUDIO_OUTPUT_FLAG_ASSOCIATED) {
- ALOGE("%s %d Error main input is not active", __func__, __LINE__);
+ //If PCM stream is already opened then fail this stream open.
+ if (qaf_mod->stream_in[QAF_IN_PCM]) {
+ ERROR_MSG("PCM input is already active.");
+ return -ENOTSUP;
+ }
+
+ //TODO: Flag can be system tone or external associated PCM.
+ status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle,
+ &out->qaf_stream_handle,
+ input_config,
+ devices,
+ AUDIO_STREAM_SYSTEM_TONE);
+ qaf_mod->stream_in[QAF_IN_PCM] = out;
+ } else {
+ if (!qaf_mod->stream_in[QAF_IN_MAIN]) {
+ if ((!(flags & AUDIO_OUTPUT_FLAG_MAIN)) && (flags & AUDIO_OUTPUT_FLAG_ASSOCIATED)) {
+ ERROR_MSG("Error main input is not active.");
return -EINVAL;
- } else {
- 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 Local playback with flag [%x] stream handle [%p] ", __func__, __LINE__, flags, out->qaf_stream_handle);
- qaf_mod->main_output_active = true;
- }
+ }
+
+ status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle,
+ &out->qaf_stream_handle,
+ input_config,
+ devices,
+ AUDIO_STREAM_MAIN);
+ if (status == 0) {
+ DEBUG_MSG("Open stream for Input with Main stream contents with flag [%x] and stream handle [%p]",
+ flags, out->qaf_stream_handle);
+ qaf_mod->stream_in[QAF_IN_MAIN] = out;
}
} else {
if (flags & AUDIO_OUTPUT_FLAG_MAIN) {
- ALOGE("%s %d Error main input is already active", __func__, __LINE__);
+ ERROR_MSG("Error main input is already active");
return -EINVAL;
- } else if (flags & AUDIO_OUTPUT_FLAG_ASSOCIATED) {
- if (qaf_mod->assoc_output_active) {
- ALOGE("%s %d Error assoc input is already active", __func__, __LINE__);
- return -EINVAL;
- } else {
- status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle, &out->qaf_stream_handle, input_config, devices, /*flags*/AUDIO_STREAM_ASSOCIATED);
- 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;
- }
+ } else if ((flags & AUDIO_OUTPUT_FLAG_ASSOCIATED)
+ && (!qaf_mod->stream_in[QAF_IN_ASSOC])) {
+ status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle,
+ &out->qaf_stream_handle,
+ input_config,
+ devices,
+ AUDIO_STREAM_ASSOCIATED);
+ if (status == 0) {
+ DEBUG_MSG("Open stream for Input with only Associated flag [%x] stream handle [%p]",
+ flags, out->qaf_stream_handle);
+ qaf_mod->stream_in[QAF_IN_ASSOC] = out;
}
} else {
- ALOGE("%s %d Error main input is already active", __func__, __LINE__);
- return -EINVAL;
+ ERROR_MSG("Invalid flag or associated is already active");
+ status = -EINVAL;
}
}
}
+ if (status != 0) {
+ //If no stream is active then close the session.
+ qaf_session_close(qaf_mod);
+ return status;
+ }
+
+ //If Device is HDMI, QAF passthrough is enabled and there is no previous QAF passthrough input stream.
+ if ((!p_qaf->passthrough_in)
+ && (devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
+ && audio_extn_qaf_passthrough_enabled(out)) {
+ //Assign the QAF passthrough input stream.
+ p_qaf->passthrough_in = out;
+
+ //If HDMI is connected and format is supported by HDMI then create QAF passthrough output stream.
+ if (p_qaf->hdmi_connect
+ && platform_is_edid_supported_format(p_qaf->adev->platform, out->format)) {
+ status = create_qaf_passthrough_stream();
+ if (status < 0) {
+ qaf_stream_close(out);
+ ERROR_MSG("QAF passthrough stream creation failed with error %d", status);
+ return status;
+ }
+ }
+ /*Else: since QAF passthrough input stream is already initialized,
+ * when hdmi is connected
+ * then qaf passthrough output stream will be created.
+ */
+ }
+
+ DEBUG_MSG();
return status;
}
-static int audio_extn_qaf_stream_open(struct stream_out *out)
-{
- int status = -ENOSYS;
- struct audio_config config;
- audio_devices_t devices;
-
- config.sample_rate = config.offload_info.sample_rate = QAF_OUTPUT_SAMPLING_RATE;
- config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
- config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
- config.offload_info.format = out->format;
- config.offload_info.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
- config.format = out->format;
- config.offload_info.channel_mask = config.channel_mask = out->channel_mask;
-
- devices = AUDIO_DEVICE_OUT_SPEAKER;
- status = qaf_stream_open(out, &config, out->flags, devices);
- ALOGV("%s %d status %d", __func__, __LINE__, status);
- return status;
-}
-
+/* Resume a QAF stream. */
static int qaf_out_resume(struct audio_stream_out* stream)
{
struct stream_out *out = (struct stream_out *)stream;
- int status = -ENOSYS;
- ALOGV("%s", __func__);
+ int status = 0;
+ DEBUG_MSG("Output Stream %p", out);
+
+
lock_output_stream(out);
- 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 &&
- (((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);
- if (!status)
- out->offload_state = OFFLOAD_STATE_PLAYING;
- pthread_mutex_unlock(&out->lock);
- return status;
- } else {
- if ((out->format == AUDIO_FORMAT_E_AC3) || (out->format == AUDIO_FORMAT_AC3)) {
- 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);
- }
- }
- } 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 (!status)
- out->offload_state = OFFLOAD_STATE_PLAYING;
- pthread_mutex_unlock(&out->lock);
- return status;
- }
- }
+
+ //If QAF passthrough is active then block the resume on module input streams.
+ if (p_qaf->passthrough_out) {
+ //If resume is received for the QAF passthrough stream then call the primary HAL api.
+ pthread_mutex_lock(&p_qaf->lock);
+ if (p_qaf->passthrough_in == out) {
+ status = p_qaf->passthrough_out->stream.resume(
+ (struct audio_stream_out*)p_qaf->passthrough_out);
+ if (!status) out->offload_state = OFFLOAD_STATE_PLAYING;
}
+ pthread_mutex_unlock(&p_qaf->lock);
+ } else {
+ //Flush the module input stream.
+ status = qaf_stream_start(out);
}
- status = qaf_stream_start(out);
- pthread_mutex_unlock(&out->lock);
- ALOGD("%s Exit", __func__);
+ unlock_output_stream(out);
+
+ DEBUG_MSG();
return status;
}
-static int qaf_deinit()
-{
- 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_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_lib != NULL) {
- dlclose(qaf_mod->qaf_lib);
- qaf_mod->qaf_lib = NULL;
- }
- free(qaf_mod);
- qaf_mod = NULL;
- }
- return 0;
-}
-
+/* Offload thread for QAF output streams. */
static void *qaf_offload_thread_loop(void *context)
{
- struct stream_out *out = (struct stream_out *) context;
+ struct stream_out *out = (struct stream_out *)context;
struct listnode *item;
int ret = 0;
struct str_parms *parms = NULL;
int value = 0;
char* kvpairs = NULL;
+ struct qaf_module *qaf_mod = NULL;
+
+ qaf_mod = get_qaf_module_for_input_stream(out);
+
+ if (!qaf_mod) return NULL;
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
set_sched_policy(0, SP_FOREGROUND);
prctl(PR_SET_NAME, (unsigned long)"Offload Callback", 0, 0, 0);
- ALOGV("%s", __func__);
lock_output_stream(out);
+
+ DEBUG_MSG();
for (;;) {
struct offload_cmd *cmd = NULL;
stream_callback_event_t event;
bool send_callback = false;
- ALOGV("%s qaf_offload_cmd_list %d",
- __func__, list_empty(&out->qaf_offload_cmd_list));
+ DEBUG_MSG("List Empty %d (1:TRUE, 0:FALSE)", list_empty(&out->qaf_offload_cmd_list));
if (list_empty(&out->qaf_offload_cmd_list)) {
- ALOGV("%s SLEEPING", __func__);
+ DEBUG_MSG("SLEEPING");
pthread_cond_wait(&out->qaf_offload_cond, &out->lock);
- ALOGV("%s RUNNING", __func__);
+ DEBUG_MSG("RUNNING");
continue;
}
@@ -1235,80 +1866,91 @@
break;
}
- pthread_mutex_unlock(&out->lock);
+ unlock_output_stream(out);
+
send_callback = false;
- switch(cmd->cmd) {
- case OFFLOAD_CMD_WAIT_FOR_BUFFER:
- ALOGV("wait for ms12 buffer availability");
- while (1) {
- kvpairs = qaf_mod->qaf_audio_stream_get_param(out->qaf_stream_handle, "buf_available");
- if (kvpairs) {
- parms = str_parms_create_str(kvpairs);
- ret = str_parms_get_int(parms, "buf_available", &value);
- if (ret >= 0) {
- if (value >= (int)out->compr_config.fragment_size) {
- ALOGV("%s buffer available", __func__);
- str_parms_destroy(parms);
- parms = NULL;
- break;
- } else {
- ALOGV("%s sleep", __func__);
- str_parms_destroy(parms);
- parms = NULL;
- usleep(10000);
+ switch (cmd->cmd) {
+ case OFFLOAD_CMD_WAIT_FOR_BUFFER: {
+ DEBUG_MSG("wait for buffer availability");
+
+ while (1) {
+ kvpairs = qaf_mod->qaf_audio_stream_get_param(out->qaf_stream_handle,
+ "buf_available");
+ if (kvpairs) {
+ parms = str_parms_create_str(kvpairs);
+ ret = str_parms_get_int(parms, "buf_available", &value);
+ if (ret >= 0) {
+ if (value >= (int)out->compr_config.fragment_size) {
+ DEBUG_MSG("buffer available");
+ str_parms_destroy(parms);
+ parms = NULL;
+ break;
+ } else {
+ DEBUG_MSG("sleep");
+ str_parms_destroy(parms);
+ parms = NULL;
+ usleep(10000);
+ }
}
+ free(kvpairs);
+ kvpairs = NULL;
}
- free(kvpairs);
- kvpairs = NULL;
}
+ send_callback = true;
+ event = STREAM_CBK_EVENT_WRITE_READY;
+ break;
}
- send_callback = true;
- event = STREAM_CBK_EVENT_WRITE_READY;
- break;
- default:
- ALOGV("%s unknown command received: %d", __func__, cmd->cmd);
+ default:
+ DEBUG_MSG("unknown command received: %d", cmd->cmd);
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);
}
while (!list_empty(&out->qaf_offload_cmd_list)) {
item = list_head(&out->qaf_offload_cmd_list);
list_remove(item);
- free(node_to_item(item, struct offload_cmd, node));
+ free (node_to_item( item, struct offload_cmd, node));
}
- pthread_mutex_unlock(&out->lock);
+ unlock_output_stream(out);
return NULL;
}
+/* Create the offload callback thread for QAF output stream. */
static int qaf_create_offload_callback_thread(struct stream_out *out)
{
- ALOGV("%s", __func__);
- pthread_cond_init(&out->qaf_offload_cond, (const pthread_condattr_t *) NULL);
+ DEBUG_MSG("Output Stream %p", out);
+ lock_output_stream(out);
+ pthread_cond_init(&out->qaf_offload_cond, (const pthread_condattr_t *)NULL);
list_init(&out->qaf_offload_cmd_list);
- pthread_create(&out->qaf_offload_thread, (const pthread_attr_t *) NULL,
- qaf_offload_thread_loop, out);
+ pthread_create(&out->qaf_offload_thread,
+ (const pthread_attr_t *)NULL,
+ qaf_offload_thread_loop,
+ out);
+ unlock_output_stream(out);
return 0;
}
+/* Destroy the offload callback thread of QAF output stream. */
static int qaf_destroy_offload_callback_thread(struct stream_out *out)
{
- ALOGV("%s", __func__);
- lock_output_stream(out);
+ DEBUG_MSG("Output Stream %p", out);
qaf_send_offload_cmd_l(out, OFFLOAD_CMD_EXIT);
- pthread_mutex_unlock(&out->lock);
- pthread_join(out->qaf_offload_thread, (void **) NULL);
+ pthread_join(out->qaf_offload_thread, (void **)NULL);
pthread_cond_destroy(&out->qaf_offload_cond);
-
return 0;
}
+/* Sets the stream set parameters (device routing information). */
static int qaf_out_set_parameters(struct audio_stream *stream, const char *kvpairs)
{
struct str_parms *parms, *new_parms;
@@ -1318,128 +1960,238 @@
struct stream_out *out = (struct stream_out *)stream;
int ret = 0;
int err = 0;
+ struct qaf_module *qaf_mod = NULL;
- 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 (qaf_mod->qaf_msmd_enabled) {
- if (qaf_mod->passthrough_enabled && qaf_mod->hdmi_connect)
- return 1;
+ DEBUG_MSG("usecase(%d: %s) kvpairs: %s", out->usecase, use_case_table[out->usecase], kvpairs);
- parms = str_parms_create_str(kvpairs);
- err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
+ parms = str_parms_create_str(kvpairs);
+ err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
+ if (err < 0)
+ return err;
+ val = atoi(value);
- /* usecase : hdmi sink which supports only 2-channel pcm */
- if (err >= 0) {
- val = atoi(value);
- if ((val & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
- ((qaf_mod->hdmi_sink_channels == 2) && !(qaf_mod->passthrough_enabled))) {
- new_parms = str_parms_create();
- 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);
- free(new_kv_pairs);
- str_parms_destroy(new_parms);
- }
+ qaf_mod = get_qaf_module_for_input_stream(out);
+ if (!qaf_mod) return (-EINVAL);
+
+ //TODO: HDMI is connected but user doesn't want HDMI output, close both HDMI outputs.
+
+ /* Setting new device information to the mm module input streams.
+ * This is needed if QAF module output streams are not created yet.
+ */
+ if (qaf_mod->stream_in[QAF_IN_MAIN] == out || qaf_mod->stream_in[QAF_IN_ASSOC] == out) {
+ qaf_mod->stream_in[QAF_IN_MAIN]->devices = val;
+ } else {
+ out->devices = val;
+ }
+
+ if (val == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) {
+ //If device is BT then open the BT stream if not already opened.
+ if ( audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl) == NULL
+ && audio_extn_bt_hal_get_device(qaf_mod->bt_hdl) != NULL) {
+ ret = audio_extn_bt_hal_open_output_stream(qaf_mod->bt_hdl,
+ QAF_OUTPUT_SAMPLING_RATE,
+ AUDIO_CHANNEL_OUT_STEREO,
+ CODEC_BACKEND_DEFAULT_BIT_WIDTH);
+ if (ret != 0) {
+ ERROR_MSG("BT Output stream open failure!");
}
- 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);
-
- parms = str_parms_create_str(kvpairs);
- if (!parms) {
- ALOGE("str_parms_create_str failed!");
- } else {
- err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
- if (err >= 0) {
- val = atoi(value);
- if (val == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) { //BT routing
- if (audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl) == NULL && audio_extn_bt_hal_get_device(qaf_mod->bt_hdl) != NULL) {
- ret = audio_extn_bt_hal_open_output_stream(qaf_mod->bt_hdl,
- QAF_OUTPUT_SAMPLING_RATE,
- AUDIO_CHANNEL_OUT_STEREO,
- CODEC_BACKEND_DEFAULT_BIT_WIDTH);
- if (ret != 0) {
- ALOGE("%s: BT Output stream open failure!", __FUNCTION__);
- }
- }
- } else if (val != 0) {
- if (audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl)!= NULL) {
- audio_extn_bt_hal_close_output_stream(qaf_mod->bt_hdl);
- }
- }
- }
- str_parms_destroy(parms);
- }
+ }
+ } else if (val != 0) {
+ //If device is not BT then close the BT stream if already opened.
+ if ( audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl) != NULL) {
+ audio_extn_bt_hal_close_output_stream(qaf_mod->bt_hdl);
}
}
- if (audio_extn_qaf_passthrough_enabled(out)) {
- parms = str_parms_create_str(kvpairs);
- if (!parms) {
- ALOGE("str_parms_create_str failed!");
- } else {
- err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
- if (err >= 0) {
- val = atoi(value);
- if ((val & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
- (qaf_mod->qaf_passthrough_out == NULL)) {
- audio_output_flags_t flags;
- struct audio_config config;
- audio_devices_t devices;
+ if (p_qaf->passthrough_in == out) { //Device routing is received for QAF passthrough stream.
- config.sample_rate = config.offload_info.sample_rate = QAF_OUTPUT_SAMPLING_RATE;
- config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
- config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
- config.offload_info.format = out->format;
- config.offload_info.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
- config.format = out->format;
- config.offload_info.channel_mask = config.channel_mask = out->channel_mask;
+ if (!(val & AUDIO_DEVICE_OUT_AUX_DIGITAL)) { //HDMI route is disabled.
- devices = AUDIO_DEVICE_OUT_AUX_DIGITAL;
- flags = out->flags;
+ //If QAF pasthrough output is enabled. Close it.
+ close_qaf_passthrough_stream();
- if (out->qaf_stream_handle) {
- qaf_out_pause((struct audio_stream_out*)out);
- qaf_out_flush((struct audio_stream_out*)out);
- qaf_out_drain((struct audio_stream_out*)out, (audio_drain_type_t)STREAM_CBK_EVENT_DRAIN_READY);
- qaf_stream_close(out);
- }
- create_output_stream(out, &config, flags, devices, QAF_DEFAULT_PASSTHROUGH_HANDLE);
- qaf_mod->main_output_active = true;
- }
+ //Send the routing information to mm module pcm output.
+ if (qaf_mod->stream_out[QAF_OUT_OFFLOAD]) {
+ ret = qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.common.set_parameters(
+ (struct audio_stream *)qaf_mod->stream_out[QAF_OUT_OFFLOAD], kvpairs);
}
- str_parms_destroy(parms);
+ //else: device info is updated in the input streams.
+ } else { //HDMI route is enabled.
+
+ //create the QAf passthrough stream, if not created already.
+ ret = create_qaf_passthrough_stream();
+
+ if (p_qaf->passthrough_out != NULL) { //If QAF passthrough out is enabled then send routing information.
+ ret = p_qaf->passthrough_out->stream.common.set_parameters(
+ (struct audio_stream *)p_qaf->passthrough_out, kvpairs);
+ }
}
+ } else {
+ //Send the routing information to mm module pcm output.
+ if (qaf_mod->stream_out[QAF_OUT_OFFLOAD]) {
+ ret = qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.common.set_parameters(
+ (struct audio_stream *)qaf_mod->stream_out[QAF_OUT_OFFLOAD], kvpairs);
+ }
+ //else: device info is updated in the input streams.
}
+ str_parms_destroy(parms);
return ret;
}
+/* Checks if a stream is QAF stream or not. */
+bool audio_extn_is_qaf_stream(struct stream_out *out)
+{
+ struct qaf_module *qaf_mod = get_qaf_module_for_input_stream(out);
+
+ if (qaf_mod) {
+ return true;
+ }
+ return false;
+}
+
+/* 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 index;
+ struct stream_out *new_out = NULL;
+ struct audio_adsp_event *adsp_event;
+ struct qaf_module *qaf_mod = get_qaf_module_for_input_stream(out);
+
+ if (!out || !qaf_mod || !payload) {
+ ERROR_MSG("Invalid Param");
+ 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) {
+ index = get_input_stream_index(out);
+ if (index < 0) {
+ ERROR_MSG("Invalid stream");
+ return ret;
+ }
+ adsp_event = (struct audio_adsp_event *)payload;
+
+ if (payload->adsp_event_params.payload_length <= AUDIO_MAX_ADSP_STREAM_CMD_PAYLOAD_LEN) {
+ pthread_mutex_lock(&p_qaf->lock);
+ memcpy(qaf_mod->adsp_hdlr_config[index].event_payload,
+ adsp_event->payload,
+ adsp_event->payload_length);
+ qaf_mod->adsp_hdlr_config[index].event_params.payload =
+ qaf_mod->adsp_hdlr_config[index].event_payload;
+ qaf_mod->adsp_hdlr_config[index].event_params.payload_length =
+ adsp_event->payload_length;
+ qaf_mod->adsp_hdlr_config[index].adsp_hdlr_config_valid = true;
+ pthread_mutex_unlock(&p_qaf->lock);
+ } else {
+ ERROR_MSG("Invalid adsp event length %d", adsp_event->payload_length);
+ return ret;
+ }
+ ret = 0;
+ }
+
+ /* apply param for all active out sessions */
+ for (index = 0; index < MAX_QAF_MODULE_OUT; index++) {
+ new_out = qaf_mod->stream_out[index];
+ 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)
+ ERROR_MSG("audio_extn_out_set_param_data error %d", ret);
+ unlock_output_stream(new_out);
+ }
+ 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, i;
+ struct stream_out *new_out;
+ struct audio_usecase *uc_info;
+ struct qaf_module *qaf_mod = get_qaf_module_for_input_stream(out);
+
+ if (!out || !qaf_mod || !payload) {
+ ERROR_MSG("Invalid Param");
+ return ret;
+ }
+
+ if (!p_qaf->hdmi_connect) {
+ ERROR_MSG("hdmi not connected");
+ return ret;
+ }
+
+ /* get session which is routed to hdmi*/
+ if (p_qaf->passthrough_out)
+ new_out = p_qaf->passthrough_out;
+ else {
+ for (i = 0; i < MAX_QAF_MODULE_OUT; i++) {
+ if (qaf_mod->stream_out[i]) {
+ new_out = qaf_mod->stream_out[i];
+ break;
+ }
+ }
+ }
+
+ if (!new_out) {
+ ERROR_MSG("No stream active.");
+ 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)
+ ERROR_MSG("audio_extn_out_get_param_data error %d", ret);
+ unlock_output_stream(new_out);
+
+ return ret;
+}
+
+/* To open a stream with QAF. */
int audio_extn_qaf_open_output_stream(struct audio_hw_device *dev,
- audio_io_handle_t handle,
- audio_devices_t devices,
- audio_output_flags_t flags,
- struct audio_config *config,
- struct audio_stream_out **stream_out,
- const char *address __unused)
+ audio_io_handle_t handle,
+ audio_devices_t devices,
+ audio_output_flags_t flags,
+ struct audio_config *config,
+ struct audio_stream_out **stream_out,
+ const char *address)
{
int ret = 0;
struct stream_out *out;
ret = adev_open_output_stream(dev, handle, devices, flags, config, stream_out, address);
if (*stream_out == NULL) {
- goto error_open;
- }
-
- if ( false == is_ms12_format(config->format) ) {
- ALOGV("%s: exiting qaf for non-ms12 format %x", __func__, config->format);
+ ERROR_MSG("Stream open failed %d", ret);
return ret;
}
- out = (struct stream_out *) *stream_out;
+ out = (struct stream_out *)*stream_out;
+
+ ret = qaf_stream_open(out, config, flags, devices);
+ if (ret == -ENOTSUP) {
+ //Stream not supported by QAF, Bypass QAF.
+ return 0;
+ } else if (ret < 0) {
+ ERROR_MSG("Error opening QAF stream err[%d]!", ret);
+ adev_close_output_stream(dev, *stream_out);
+ return ret;
+ }
/* Override function pointers based on qaf definitions */
out->stream.set_volume = qaf_out_set_volume;
@@ -1454,13 +2206,8 @@
out->stream.write = qaf_out_write;
out->stream.get_presentation_position = qaf_out_get_presentation_position;
out->platform_latency = 0;
- ret = qaf_stream_open(out, config, flags, devices);
- if (ret < 0) {
- ALOGE("%s, Error opening QAF stream err[%d]!", __func__, ret);
- adev_close_output_stream(dev, *stream_out);
- goto error_open;
- }
+ /*TODO: Need to handle this for DTS*/
if (out->usecase == USECASE_AUDIO_PLAYBACK_LOW_LATENCY) {
out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER;
out->config.period_size = QAF_DEEP_BUFFER_OUTPUT_PERIOD_SIZE;
@@ -1468,48 +2215,52 @@
out->config.start_threshold = QAF_DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4;
out->config.avail_min = QAF_DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4;
}
-
*stream_out = &out->stream;
if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
qaf_create_offload_callback_thread(out);
}
- ALOGV("%s: exit", __func__);
+
+ DEBUG_MSG("Exit");
return 0;
-error_open:
- *stream_out = NULL;
- ALOGD("%s: exit: ret %d", __func__, ret);
- return ret;
}
+/* Close a QAF stream. */
void audio_extn_qaf_close_output_stream(struct audio_hw_device *dev,
- struct audio_stream_out *stream)
+ struct audio_stream_out *stream)
{
struct stream_out *out = (struct stream_out *)stream;
+ struct qaf_module* qaf_mod = get_qaf_module_for_input_stream(out);
- 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);
- 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(dev, stream);
- qaf_mod->qaf_passthrough_out = NULL;
- qaf_mod->main_output_active = false;
- pthread_mutex_unlock(&qaf_mod->lock);
- return;
+ if (!qaf_mod) return;
+
+ DEBUG_MSG("stream_handle(%p) format = %x", out, out->format);
+
+ //If close is received for QAF passthrough stream then close the QAF passthrough output.
+ if (p_qaf->passthrough_in == out) {
+ if (p_qaf->passthrough_out) {
+ ALOGD("%s %d closing stream handle %p", __func__, __LINE__, p_qaf->passthrough_out);
+ pthread_mutex_lock(&p_qaf->lock);
+ adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
+ (struct audio_stream_out *)(p_qaf->passthrough_out));
+ pthread_mutex_unlock(&p_qaf->lock);
+ p_qaf->passthrough_out = NULL;
+ }
+
+ p_qaf->passthrough_in = NULL;
}
if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
qaf_destroy_offload_callback_thread(out);
}
- qaf_mod->stream_drain_main = NULL;
- lock_output_stream(out);
+
qaf_stream_close(out);
- pthread_mutex_unlock(&out->lock);
adev_close_output_stream(dev, stream);
- ALOGV("%s: exit", __func__);
+
+ DEBUG_MSG("Exit");
}
+/* Check if QAF is supported or not. */
bool audio_extn_qaf_is_enabled()
{
bool prop_enabled = false;
@@ -1519,322 +2270,413 @@
return (prop_enabled);
}
-int audio_extn_qaf_session_open(struct qaf *qaf_mod,
- device_license_config_t* lic_config)
+/* Query HDMI EDID and sets module output accordingly.*/
+void set_hdmi_configuration_to_module()
{
- ALOGV("%s %d", __func__, __LINE__);
- int status = -ENOSYS;
-
- pthread_mutex_init(&qaf_mod->lock, (const pthread_mutexattr_t *) NULL);
-
- if (!qaf_mod->qaf_audio_session_open)
- return -EINVAL;
-
- status = qaf_mod->qaf_audio_session_open(&qaf_mod->session_handle,
- (void *)(qaf_mod), (void *)lic_config);
- if(status < 0)
- return status;
-
- if (qaf_mod->session_handle == NULL) {
- ALOGE("%s %d QAF wrapper session handle is NULL", __func__, __LINE__);
- return -ENOMEM;
- }
- if (qaf_mod->qaf_register_event_callback)
- qaf_mod->qaf_register_event_callback(qaf_mod->session_handle,
- qaf_mod, ¬ify_event_callback,
- AUDIO_DATA_EVENT);
-
- if (property_get_bool("audio.qaf.msmd", false)) {
- qaf_mod->qaf_msmd_enabled = 1;
- }
-
- return status;
-}
-
-char* audio_extn_qaf_stream_get_param(struct stream_out *out __unused, const char *kv_pair __unused)
-{
- return NULL;
-}
-
-int audio_extn_qaf_set_parameters(struct audio_device *adev, struct str_parms *parms)
-{
- int status = 0, val = 0, channels = 0;
- char *format_params, *kv_parirs;
+ int channels = 0;
+ char *format_params;
struct str_parms *qaf_params;
- char value[32];
char prop_value[PROPERTY_VALUE_MAX];
bool passth_support = false;
- ALOGV("%s %d ", __func__, __LINE__);
- if (!qaf_mod || !qaf_mod->qaf_audio_session_set_param) {
+ DEBUG_MSG("Entry");
+
+ if (!p_qaf) {
+ return;
+ }
+
+ if (!p_qaf->hdmi_connect) {
+ DEBUG_MSG("HDMI is not connected.");
+ return;
+ }
+
+ p_qaf->hdmi_sink_channels = 0;
+
+ //QAF re-encoding and DSP offload passthrough is supported.
+ if (property_get_bool("audio.offload.passthrough", false)
+ && property_get_bool("audio.qaf.reencode", false)) {
+
+ //If MS12 session is active.
+ if (p_qaf->qaf_mod[MS12].session_handle && p_qaf->qaf_mod[MS12].qaf_audio_session_set_param) {
+
+ bool do_setparam = false;
+ qaf_params = str_parms_create();
+ property_get("audio.qaf.hdmi.out", prop_value, NULL);
+
+ if (platform_is_edid_supported_format(p_qaf->adev->platform, AUDIO_FORMAT_E_AC3)
+ && (strncmp(prop_value, "ddp", 3) == 0)) {
+ do_setparam = true;
+ if (qaf_params) {
+ str_parms_add_str(qaf_params,
+ AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
+ AUDIO_QAF_PARAMETER_VALUE_REENCODE_EAC3);
+ }
+ } else if (platform_is_edid_supported_format(p_qaf->adev->platform, AUDIO_FORMAT_AC3)) {
+ do_setparam = true;
+ if (qaf_params) {
+ str_parms_add_str(qaf_params,
+ AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
+ AUDIO_QAF_PARAMETER_VALUE_REENCODE_AC3);
+ }
+ }
+
+ if (do_setparam) {
+ if (p_qaf->qaf_msmd_enabled) {
+ str_parms_add_str(qaf_params,
+ AUDIO_QAF_PARAMETER_KEY_DEVICE,
+ AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK); //TODO: Need enhancement.
+ } else {
+ str_parms_add_str(qaf_params,
+ AUDIO_QAF_PARAMETER_KEY_DEVICE,
+ AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI);
+ }
+ format_params = str_parms_to_str(qaf_params);
+
+ p_qaf->qaf_mod[MS12].qaf_audio_session_set_param(p_qaf->qaf_mod[MS12].session_handle,
+ format_params);
+
+ passth_support = true;
+ }
+ str_parms_destroy(qaf_params);
+ }
+
+ //DTS_M8 session is active.
+ if (p_qaf->qaf_mod[DTS_M8].session_handle
+ && p_qaf->qaf_mod[DTS_M8].qaf_audio_session_set_param) {
+
+ bool do_setparam = false;
+ qaf_params = str_parms_create();
+#if 0 //TODO: Need to enable with DTS_M8 wrapper.
+ if (platform_is_edid_supported_format(p_qaf->adev->platform, AUDIO_FORMAT_DTS)) {
+ do_setparam = true;
+ if (qaf_params) {
+ str_parms_add_str(qaf_params,
+ AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
+ AUDIO_QAF_PARAMETER_VALUE_REENCODE_DTS);
+ }
+ }
+#endif
+
+ if (do_setparam) {
+ if (p_qaf->qaf_msmd_enabled) {
+ str_parms_add_str(qaf_params,
+ AUDIO_QAF_PARAMETER_KEY_DEVICE,
+ AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK); //TODO: Need enhancement.
+ } else {
+ str_parms_add_str(qaf_params,
+ AUDIO_QAF_PARAMETER_KEY_DEVICE,
+ AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI);
+ }
+ format_params = str_parms_to_str(qaf_params);
+
+ p_qaf->qaf_mod[DTS_M8].qaf_audio_session_set_param(p_qaf->qaf_mod[DTS_M8].session_handle,
+ format_params);
+
+ passth_support = true;
+ }
+ str_parms_destroy(qaf_params);
+ }
+ }
+
+ //Compressed passthrough is not enabled.
+ if (!passth_support) {
+
+ channels = platform_edid_get_max_channels(p_qaf->adev->platform);
+
+ qaf_params = str_parms_create();
+ switch (channels) {
+ case 8:
+ DEBUG_MSG("Switching Qaf output to 7.1 channels");
+ str_parms_add_str(qaf_params,
+ AUDIO_QAF_PARAMETER_KEY_CHANNELS,
+ AUDIO_QAF_PARAMETER_VALUE_8_CHANNELS);
+ if (p_qaf->qaf_msmd_enabled) {
+ str_parms_add_str(qaf_params,
+ AUDIO_QAF_PARAMETER_KEY_DEVICE,
+ AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK);
+ } else {
+ str_parms_add_str(qaf_params,
+ AUDIO_QAF_PARAMETER_KEY_DEVICE,
+ AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI);
+ }
+ p_qaf->hdmi_sink_channels = channels;
+ break;
+ case 6:
+ DEBUG_MSG("Switching Qaf output to 5.1 channels");
+ str_parms_add_str(qaf_params,
+ AUDIO_QAF_PARAMETER_KEY_CHANNELS,
+ AUDIO_QAF_PARAMETER_VALUE_6_CHANNELS);
+ if (p_qaf->qaf_msmd_enabled) {
+ str_parms_add_str(qaf_params,
+ AUDIO_QAF_PARAMETER_KEY_DEVICE,
+ AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK);
+ } else {
+ str_parms_add_str(qaf_params,
+ AUDIO_QAF_PARAMETER_KEY_DEVICE,
+ AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI);
+ }
+ p_qaf->hdmi_sink_channels = channels;
+ break;
+ default:
+ DEBUG_MSG("Switching Qaf output to default channels");
+ str_parms_add_str(qaf_params,
+ AUDIO_QAF_PARAMETER_KEY_CHANNELS,
+ AUDIO_QAF_PARAMETER_VALUE_DEFAULT_CHANNELS);
+ if (p_qaf->qaf_msmd_enabled) {
+ str_parms_add_str(qaf_params,
+ AUDIO_QAF_PARAMETER_KEY_DEVICE,
+ AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK);
+ } else {
+ str_parms_add_str(qaf_params,
+ AUDIO_QAF_PARAMETER_KEY_DEVICE,
+ AUDIO_QAF_PARAMETER_VALUE_DEVICE_SPEAKER);
+ }
+ p_qaf->hdmi_sink_channels = 2;
+ break;
+ }
+
+ format_params = str_parms_to_str(qaf_params);
+
+ if (p_qaf->qaf_mod[MS12].session_handle && p_qaf->qaf_mod[MS12].qaf_audio_session_set_param) {
+ p_qaf->qaf_mod[MS12].qaf_audio_session_set_param(p_qaf->qaf_mod[MS12].session_handle,
+ format_params);
+ }
+ if (p_qaf->qaf_mod[DTS_M8].session_handle
+ && p_qaf->qaf_mod[DTS_M8].qaf_audio_session_set_param) {
+ p_qaf->qaf_mod[DTS_M8].qaf_audio_session_set_param(p_qaf->qaf_mod[DTS_M8].session_handle,
+ format_params);
+ }
+
+ str_parms_destroy(qaf_params);
+ }
+ DEBUG_MSG("Exit");
+}
+
+/* QAF set parameter function. For Device connect and disconnect. */
+int audio_extn_qaf_set_parameters(struct audio_device *adev, struct str_parms *parms)
+{
+ int status = 0, val = 0, k;
+ char *format_params, *kv_parirs;
+ struct str_parms *qaf_params;
+ char value[32];
+
+ DEBUG_MSG("Entry");
+
+ if (!p_qaf) {
return -EINVAL;
}
status = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, value, sizeof(value));
+
if (status >= 0) {
val = atoi(value);
- if (val & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
- if (property_get_bool("audio.offload.passthrough", false) &&
- property_get_bool("audio.qaf.reencode", false)) {
+ if (val & AUDIO_DEVICE_OUT_AUX_DIGITAL) { //HDMI is connected.
- qaf_params = str_parms_create();
- property_get("audio.qaf.hdmi.out", prop_value, NULL);
- if (platform_is_edid_supported_format(adev->platform, AUDIO_FORMAT_E_AC3) &&
- (strncmp(prop_value, "ddp", 3) == 0)) {
- passth_support = true;
- if (qaf_params) {
- str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
- AUDIO_QAF_PARAMETER_VALUE_REENCODE_EAC3);
- }
- } else if (platform_is_edid_supported_format(adev->platform, AUDIO_FORMAT_AC3)) {
- passth_support = true;
- if (qaf_params) {
- str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
- AUDIO_QAF_PARAMETER_VALUE_REENCODE_AC3);
- }
+ p_qaf->hdmi_connect = 1;
+ p_qaf->hdmi_sink_channels = 0;
+
+ if (p_qaf->passthrough_in) { //If QAF passthrough is already initialized.
+ lock_output_stream(p_qaf->passthrough_in);
+ if (platform_is_edid_supported_format(adev->platform,
+ p_qaf->passthrough_in->format)) {
+ //If passthrough format is supported by HDMI then create the QAF passthrough output if not created already.
+ create_qaf_passthrough_stream();
+ //Ignoring the returned error, If error then QAF passthrough is disabled.
+ } else {
+ //If passthrough format is not supported by HDMI then close the QAF passthrough output if already created.
+ close_qaf_passthrough_stream();
}
-
- if (passth_support) {
- qaf_mod->passthrough_enabled = 1;
- if (qaf_mod->qaf_msmd_enabled) {
- str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
- AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK);
- } else {
- str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
- AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI);
- }
- format_params = str_parms_to_str(qaf_params);
-
- qaf_mod->qaf_audio_session_set_param(qaf_mod->session_handle, format_params);
- }
- str_parms_destroy(qaf_params);
+ unlock_output_stream(p_qaf->passthrough_in);
}
- if (!passth_support) {
- channels = platform_edid_get_max_channels(adev->platform);
+ set_hdmi_configuration_to_module();
- qaf_params = str_parms_create();
- switch (channels) {
- case 8:
- ALOGV("%s: Switching Qaf output to 7.1 channels", __func__);
- str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_CHANNELS,
- AUDIO_QAF_PARAMETER_VALUE_8_CHANNELS);
- if (qaf_mod->qaf_msmd_enabled) {
- str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
- AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK);
- } else {
- str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
- AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI);
- }
- qaf_mod->hdmi_sink_channels = channels;
- break;
- case 6:
- ALOGV("%s: Switching Qaf output to 5.1 channels", __func__);
- str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_CHANNELS,
- AUDIO_QAF_PARAMETER_VALUE_6_CHANNELS);
- if (qaf_mod->qaf_msmd_enabled) {
- str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
- AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK);
- } else {
- str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
- AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI);
- }
- qaf_mod->hdmi_sink_channels = channels;
- break;
- default:
- ALOGV("%s: Switching Qaf output to default channels", __func__);
- str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_CHANNELS,
- AUDIO_QAF_PARAMETER_VALUE_DEFAULT_CHANNELS);
- if (qaf_mod->qaf_msmd_enabled) {
- str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
- AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK);
- } else {
- str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
- AUDIO_QAF_PARAMETER_VALUE_DEVICE_SPEAKER);
- }
- qaf_mod->hdmi_sink_channels = 2;
- break;
- }
-
- format_params = str_parms_to_str(qaf_params);
- qaf_mod->qaf_audio_session_set_param(qaf_mod->session_handle, format_params);
- str_parms_destroy(qaf_params);
- }
- qaf_mod->hdmi_connect = 1;
} else if (val & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) {
- ALOGV("%s: Opening a2dp output...", __FUNCTION__);
- status = audio_extn_bt_hal_load(&qaf_mod->bt_hdl);
- if(status != 0) {
- ALOGE("%s:Error opening BT module", __FUNCTION__);
- return status;
+ for (k = 0; k < MAX_MM_MODULE_TYPE; k++) {
+ if (!p_qaf->qaf_mod[k].bt_hdl) {
+ DEBUG_MSG("Opening a2dp output...");
+ status = audio_extn_bt_hal_load(&p_qaf->qaf_mod[k].bt_hdl);
+ if (status != 0) {
+ ERROR_MSG("Error opening BT module");
+ return status;
+ }
+ }
}
}
+ //TODO else if: Need to consider other devices.
}
status = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, value, sizeof(value));
if (status >= 0) {
val = atoi(value);
- if (val & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
- qaf_params = str_parms_create();
- str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
- AUDIO_QAF_PARAMETER_VALUE_DEVICE_SPEAKER);
- str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
- AUDIO_QAF_PARAMETER_VALUE_PCM);
- qaf_mod->hdmi_sink_channels = 0;
+ if (val & AUDIO_DEVICE_OUT_AUX_DIGITAL) { //HDMI is disconnected.
- qaf_mod->passthrough_enabled = 0;
- qaf_mod->hdmi_connect = 0;
+ qaf_params = str_parms_create();
+ str_parms_add_str(qaf_params,
+ AUDIO_QAF_PARAMETER_KEY_DEVICE,
+ AUDIO_QAF_PARAMETER_VALUE_DEVICE_SPEAKER);
+ str_parms_add_str(qaf_params,
+ AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
+ AUDIO_QAF_PARAMETER_VALUE_PCM);
+ p_qaf->hdmi_sink_channels = 0;
+
+ p_qaf->passthrough_enabled = 0;
+ p_qaf->mch_pcm_hdmi_enabled = 0;
+ p_qaf->hdmi_connect = 0;
+
format_params = str_parms_to_str(qaf_params);
- qaf_mod->qaf_audio_session_set_param(qaf_mod->session_handle, format_params);
+
+ for (k = 0; k < MAX_MM_MODULE_TYPE; k++) {
+ if (p_qaf->qaf_mod[k].session_handle
+ && p_qaf->qaf_mod[k].qaf_audio_session_set_param) {
+ p_qaf->qaf_mod[k].qaf_audio_session_set_param(
+ p_qaf->qaf_mod[k].session_handle, format_params);
+ }
+ }
+ close_all_hdmi_output();
+
str_parms_destroy(qaf_params);
+ close_qaf_passthrough_stream();
} else if (val & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) {
- ALOGV("%s: Closing a2dp output...", __FUNCTION__);
- audio_extn_bt_hal_unload(qaf_mod->bt_hdl);
+ DEBUG_MSG("Closing a2dp output...");
+ for (k = 0; k < MAX_MM_MODULE_TYPE; k++) {
+ if (p_qaf->qaf_mod[k].bt_hdl) {
+ audio_extn_bt_hal_unload(p_qaf->qaf_mod[k].bt_hdl);
+ p_qaf->qaf_mod[k].bt_hdl = NULL;
+ }
+ }
+ }
+ //TODO else if: Need to consider other devices.
+ }
+
+ for (k = 0; k < MAX_MM_MODULE_TYPE; k++) {
+ kv_parirs = str_parms_to_str(parms);
+ if (p_qaf->qaf_mod[k].session_handle && p_qaf->qaf_mod[k].qaf_audio_session_set_param) {
+ p_qaf->qaf_mod[k].qaf_audio_session_set_param(
+ p_qaf->qaf_mod[k].session_handle, kv_parirs);
}
}
- kv_parirs = str_parms_to_str(parms);
- qaf_mod->qaf_audio_session_set_param(qaf_mod->session_handle, kv_parirs);
-
+ DEBUG_MSG("Exit");
return status;
}
-char* audio_extn_qaf_get_param(struct audio_device *adev __unused, const char *kv_pair __unused)
+/* Create the QAF. */
+int audio_extn_qaf_init(struct audio_device *adev)
{
+ DEBUG_MSG("Entry");
+
+ p_qaf = calloc(1, sizeof(struct qaf));
+ if (p_qaf == NULL) {
+ ERROR_MSG("Out of memory");
+ return -ENOMEM;
+ }
+
+ p_qaf->adev = adev;
+
+ if (property_get_bool("audio.qaf.msmd", false)) {
+ p_qaf->qaf_msmd_enabled = 1;
+ }
+ pthread_mutex_init(&p_qaf->lock, (const pthread_mutexattr_t *) NULL);
+
+ int i = 0;
+
+ for (i = 0; i < MAX_MM_MODULE_TYPE; i++) {
+ char value[PROPERTY_VALUE_MAX] = {0};
+ char lib_name[PROPERTY_VALUE_MAX] = {0};
+ struct qaf_module *qaf_mod = &(p_qaf->qaf_mod[i]);
+
+ if (i == MS12) {
+ property_get("audio.qaf.library", value, NULL);
+ } else if (i == DTS_M8) {
+ property_get("audio.qaf.m8.library", value, NULL);
+ } else {
+ continue;
+ }
+
+ snprintf(lib_name, PROPERTY_VALUE_MAX, "%s", value);
+
+ qaf_mod->qaf_lib = dlopen(lib_name, RTLD_NOW);
+ if (qaf_mod->qaf_lib == NULL) {
+ ERROR_MSG("DLOPEN failed for %s", lib_name);
+ continue;
+ }
+
+ DEBUG_MSG("DLOPEN successful for %s", lib_name);
+ qaf_mod->qaf_audio_session_open =
+ (int (*)(audio_session_handle_t* session_handle, void *p_data, void* license_data))dlsym(qaf_mod->qaf_lib,
+ "audio_session_open");
+ qaf_mod->qaf_audio_session_close =
+ (int (*)(audio_session_handle_t session_handle))dlsym(qaf_mod->qaf_lib,
+ "audio_session_close");
+ qaf_mod->qaf_audio_stream_open =
+ (int (*)(audio_session_handle_t session_handle, audio_stream_handle_t* stream_handle,
+ audio_stream_config_t input_config, audio_devices_t devices, stream_type_t flags))dlsym(qaf_mod->qaf_lib,
+ "audio_stream_open");
+ qaf_mod->qaf_audio_stream_close =
+ (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
+ "audio_stream_close");
+ qaf_mod->qaf_audio_stream_set_param =
+ (int (*)(audio_stream_handle_t stream_handle, const char* kv_pairs))dlsym(qaf_mod->qaf_lib,
+ "audio_stream_set_param");
+ qaf_mod->qaf_audio_session_set_param =
+ (int (*)(audio_session_handle_t handle, const char* kv_pairs))dlsym(qaf_mod->qaf_lib,
+ "audio_session_set_param");
+ qaf_mod->qaf_audio_stream_get_param =
+ (char* (*)(audio_stream_handle_t stream_handle, const char* key))dlsym(qaf_mod->qaf_lib,
+ "audio_stream_get_param");
+ qaf_mod->qaf_audio_session_get_param =
+ (char* (*)(audio_session_handle_t handle, const char* key))dlsym(qaf_mod->qaf_lib,
+ "audio_session_get_param");
+ qaf_mod->qaf_audio_stream_start =
+ (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
+ "audio_stream_start");
+ qaf_mod->qaf_audio_stream_stop =
+ (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
+ "audio_stream_stop");
+ qaf_mod->qaf_audio_stream_pause =
+ (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
+ "audio_stream_pause");
+ qaf_mod->qaf_audio_stream_flush =
+ (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
+ "audio_stream_flush");
+ qaf_mod->qaf_audio_stream_write =
+ (int (*)(audio_stream_handle_t stream_handle, const void* buf, int size))dlsym(qaf_mod->qaf_lib,
+ "audio_stream_write");
+ qaf_mod->qaf_register_event_callback =
+ (void (*)(audio_session_handle_t session_handle, void *priv_data, notify_event_callback_t event_callback,
+ audio_event_id_t event_id))dlsym(qaf_mod->qaf_lib,
+ "register_event_callback");
+ }
+
+ DEBUG_MSG("Exit");
return 0;
}
-int audio_extn_qaf_init(struct audio_device *adev)
-{
- char value[PROPERTY_VALUE_MAX] = {0};
- char lib_name[PROPERTY_VALUE_MAX] = {0};
- unsigned char* license_data = NULL;
- device_license_config_t* lic_config = NULL;
- ALOGV("%s %d", __func__, __LINE__);
- int ret = 0, size = 0;
-
- qaf_mod = malloc(sizeof(struct qaf));
- if(qaf_mod == NULL) {
- ALOGE("%s, out of memory", __func__);
- ret = -ENOMEM;
- goto done;
- }
- memset(qaf_mod, 0, sizeof(struct qaf));
- lic_config = (device_license_config_t*) calloc(1, sizeof(device_license_config_t));
- if(lic_config == NULL) {
- ALOGE("%s, out of memory", __func__);
- ret = -ENOMEM;
- goto done;
- }
- qaf_mod->adev = adev;
- property_get("audio.qaf.library", value, NULL);
- snprintf(lib_name, PROPERTY_VALUE_MAX, "%s", value);
-
- qaf_mod->qaf_lib = dlopen(lib_name, RTLD_NOW);
- if (qaf_mod->qaf_lib == NULL) {
- ALOGE("%s: DLOPEN failed for %s", __func__, lib_name);
- ret = -EINVAL;
- goto done;
- }
-
- ALOGV("%s: DLOPEN successful for %s", __func__, lib_name);
- qaf_mod->qaf_audio_session_open =
- (int (*)(audio_session_handle_t* session_handle, void *p_data, void* license_data))dlsym(qaf_mod->qaf_lib,
- "audio_session_open");
- qaf_mod->qaf_audio_session_close =
- (int (*)(audio_session_handle_t session_handle))dlsym(qaf_mod->qaf_lib,
- "audio_session_close");
- qaf_mod->qaf_audio_stream_open =
- (int (*)(audio_session_handle_t session_handle, audio_stream_handle_t* stream_handle,
- audio_stream_config_t input_config, audio_devices_t devices, stream_type_t flags))dlsym(qaf_mod->qaf_lib,
- "audio_stream_open");
- qaf_mod->qaf_audio_stream_close =
- (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
- "audio_stream_close");
- qaf_mod->qaf_audio_stream_set_param =
- (int (*)(audio_stream_handle_t stream_handle, const char* kv_pairs))dlsym(qaf_mod->qaf_lib,
- "audio_stream_set_param");
- qaf_mod->qaf_audio_session_set_param =
- (int (*)(audio_session_handle_t handle, const char* kv_pairs))dlsym(qaf_mod->qaf_lib,
- "audio_session_set_param");
- qaf_mod->qaf_audio_stream_get_param =
- (char* (*)(audio_stream_handle_t stream_handle, const char* key))dlsym(qaf_mod->qaf_lib,
- "audio_stream_get_param");
- qaf_mod->qaf_audio_session_get_param =
- (char* (*)(audio_session_handle_t handle, const char* key))dlsym(qaf_mod->qaf_lib,
- "audio_session_get_param");
- qaf_mod->qaf_audio_stream_start =
- (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
- "audio_stream_start");
- qaf_mod->qaf_audio_stream_stop =
- (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
- "audio_stream_stop");
- qaf_mod->qaf_audio_stream_pause =
- (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
- "audio_stream_pause");
- qaf_mod->qaf_audio_stream_flush =
- (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
- "audio_stream_flush");
- qaf_mod->qaf_audio_stream_write =
- (int (*)(audio_stream_handle_t stream_handle, const void* buf, int size))dlsym(qaf_mod->qaf_lib,
- "audio_stream_write");
- qaf_mod->qaf_register_event_callback =
- (void (*)(audio_session_handle_t session_handle, void *priv_data, notify_event_callback_t event_callback,
- audio_event_id_t event_id))dlsym(qaf_mod->qaf_lib,
- "register_event_callback");
-
- license_data = platform_get_license((struct audio_hw_device *)(qaf_mod->adev->platform), &size);
- if (!license_data) {
- ALOGE("License is not present");
- ret = -EINVAL;
- goto done;
- }
- lic_config->p_license = (unsigned char* ) calloc(1, size);
- if(lic_config->p_license == NULL) {
- ALOGE("%s, out of memory", __func__);
- ret = -ENOMEM;
- goto done;
- }
- lic_config->l_size = size;
- memcpy(lic_config->p_license, license_data, size);
-
- if (property_get("audio.qaf.manufacturer", value, "") && atoi(value)) {
- lic_config->manufacturer_id = (unsigned long) atoi (value);
- } else {
- ALOGE("audio.qaf.manufacturer id is not set");
- ret = -EINVAL;
- goto done;
- }
-
- ret = audio_extn_qaf_session_open(qaf_mod, lic_config);
-done:
- if (license_data != NULL) {
- free(license_data);
- license_data = NULL;
- }
- if (lic_config->p_license != NULL) {
- free(lic_config->p_license);
- lic_config->p_license = NULL;
- }
- if (lic_config != NULL) {
- free(lic_config);
- lic_config = NULL;
- }
- if (ret != 0) {
- if (qaf_mod->qaf_lib != NULL) {
- dlclose(qaf_mod->qaf_lib);
- qaf_mod->qaf_lib = NULL;
- }
- if (qaf_mod != NULL) {
- free(qaf_mod);
- qaf_mod = NULL;
- }
- }
- return ret;
-}
-
+/* Tear down the qaf extension. */
void audio_extn_qaf_deinit()
{
- qaf_session_close();
- qaf_deinit();
+ int i;
+ DEBUG_MSG("Entry");
+
+ if (p_qaf != NULL) {
+ for (i = 0; i < MAX_MM_MODULE_TYPE; i++) {
+ qaf_session_close(&p_qaf->qaf_mod[i]);
+
+ if (p_qaf->qaf_mod[i].qaf_lib != NULL) {
+ dlclose(p_qaf->qaf_mod[i].qaf_lib);
+ p_qaf->qaf_mod[i].qaf_lib = NULL;
+ }
+ }
+ if (p_qaf->passthrough_out) {
+ adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
+ (struct audio_stream_out *)(p_qaf->passthrough_out));
+ p_qaf->passthrough_out = NULL;
+ }
+
+ pthread_mutex_destroy(&p_qaf->lock);
+ free(p_qaf);
+ p_qaf = NULL;
+ }
+ DEBUG_MSG("Exit");
}
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index b8be7aa..27bbae8 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -70,6 +70,10 @@
#define BASE_TABLE_SIZE 64
#define MAX_BASEINDEX_LEN 256
+#ifndef SND_AUDIOCODEC_TRUEHD
+#define SND_AUDIOCODEC_TRUEHD 0x00000023
+#endif
+
#ifdef AUDIO_EXTERNAL_HDMI_ENABLED
#define PROFESSIONAL (1<<0) /* 0 = consumer, 1 = professional */
#define NON_LPCM (1<<1) /* 0 = audio, 1 = non-audio */
@@ -130,6 +134,7 @@
STRING_TO_ENUM(AUDIO_FORMAT_E_AC3),
STRING_TO_ENUM(AUDIO_FORMAT_DTS),
STRING_TO_ENUM(AUDIO_FORMAT_DTS_HD),
+ STRING_TO_ENUM(AUDIO_FORMAT_DOLBY_TRUEHD),
#ifdef AUDIO_EXTN_FORMATS_ENABLED
STRING_TO_ENUM(AUDIO_FORMAT_E_AC3_JOC),
STRING_TO_ENUM(AUDIO_FORMAT_WMA),
@@ -900,7 +905,8 @@
app_type_cfg[len++] = app_type;
app_type_cfg[len++] = acdb_dev_id;
if (((usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
- (usecase->stream.out->format == AUDIO_FORMAT_E_AC3_JOC))
+ (usecase->stream.out->format == AUDIO_FORMAT_E_AC3_JOC) ||
+ (usecase->stream.out->format == AUDIO_FORMAT_DOLBY_TRUEHD))
&& audio_extn_passthru_is_passthrough_stream(usecase->stream.out)) {
app_type_cfg[len++] = sample_rate * 4;
} else {
@@ -1246,6 +1252,9 @@
case AUDIO_FORMAT_DTS_HD:
id = SND_AUDIOCODEC_DTS;
break;
+ case AUDIO_FORMAT_DOLBY_TRUEHD:
+ id = SND_AUDIOCODEC_TRUEHD;
+ break;
case AUDIO_FORMAT_DSD:
id = SND_AUDIOCODEC_DSD;
break;
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 7b69ca2..de8b388 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -293,6 +293,7 @@
STRING_TO_ENUM(AUDIO_FORMAT_AC3),
STRING_TO_ENUM(AUDIO_FORMAT_E_AC3),
STRING_TO_ENUM(AUDIO_FORMAT_E_AC3_JOC),
+ STRING_TO_ENUM(AUDIO_FORMAT_DOLBY_TRUEHD),
STRING_TO_ENUM(AUDIO_FORMAT_DTS),
STRING_TO_ENUM(AUDIO_FORMAT_DTS_HD),
};
@@ -511,6 +512,7 @@
format == AUDIO_FORMAT_PCM_16_BIT ||
format == AUDIO_FORMAT_AC3 ||
format == AUDIO_FORMAT_E_AC3 ||
+ format == AUDIO_FORMAT_DOLBY_TRUEHD ||
format == AUDIO_FORMAT_DTS ||
format == AUDIO_FORMAT_DTS_HD ||
format == AUDIO_FORMAT_FLAC ||
@@ -1313,6 +1315,11 @@
out->supported_formats[i++] = AUDIO_FORMAT_E_AC3_JOC;
}
+ if (platform_is_edid_supported_format(out->dev->platform, AUDIO_FORMAT_DOLBY_TRUEHD)) {
+ ALOGV(":%s HDMI supports TRUE HD format", __func__);
+ out->supported_formats[i++] = AUDIO_FORMAT_DOLBY_TRUEHD;
+ }
+
if (platform_is_edid_supported_format(out->dev->platform, AUDIO_FORMAT_DTS)) {
ALOGV(":%s HDMI supports DTS format", __func__);
out->supported_formats[i++] = AUDIO_FORMAT_DTS;
@@ -2105,9 +2112,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 +2369,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 +3438,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 +3938,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 +4383,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 +4418,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 +5119,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 +5374,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/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 935bae3..2ab9408 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -5457,12 +5457,20 @@
channels = max_supported_channels;
} else {
- /*During pass through set default bit width and channels*/
- channels = DEFAULT_HDMI_OUT_CHANNELS;
+ /*During pass through set default bit width */
+ if (usecase->stream.out->format == AUDIO_FORMAT_DOLBY_TRUEHD)
+ channels = 8;
+ else
+ channels = DEFAULT_HDMI_OUT_CHANNELS;
+
if ((usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
- (usecase->stream.out->format == AUDIO_FORMAT_E_AC3_JOC))
+ (usecase->stream.out->format == AUDIO_FORMAT_E_AC3_JOC) ||
+ (usecase->stream.out->format == AUDIO_FORMAT_DOLBY_TRUEHD))
sample_rate = sample_rate * 4 ;
+ if (!edid_is_supported_sr(edid_info, sample_rate))
+ sample_rate = edid_get_highest_supported_sr(edid_info);
+
bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
/* We force route so that the BE format can be set to Compr */
}
@@ -6301,6 +6309,10 @@
ALOGV("%s:E_AC3", __func__);
format = DOLBY_DIGITAL_PLUS;
break;
+ case AUDIO_FORMAT_DOLBY_TRUEHD:
+ ALOGV("%s:MAT", __func__);
+ format = MAT;
+ break;
case AUDIO_FORMAT_DTS:
ALOGV("%s:DTS", __func__);
format = DTS;
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 1d32409..8f7e125 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -5175,12 +5175,20 @@
channels = max_supported_channels;
} else {
- /*During pass through set default bit width and channels*/
- channels = DEFAULT_HDMI_OUT_CHANNELS;
+ /*During pass through set default bit width */
+ if (usecase->stream.out->format == AUDIO_FORMAT_DOLBY_TRUEHD)
+ channels = 8;
+ else
+ channels = DEFAULT_HDMI_OUT_CHANNELS;
+
if ((usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
- (usecase->stream.out->format == AUDIO_FORMAT_E_AC3_JOC))
+ (usecase->stream.out->format == AUDIO_FORMAT_E_AC3_JOC) ||
+ (usecase->stream.out->format == AUDIO_FORMAT_DOLBY_TRUEHD))
sample_rate = sample_rate * 4 ;
+ if (!edid_is_supported_sr(edid_info, sample_rate))
+ sample_rate = edid_get_highest_supported_sr(edid_info);
+
bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
/* We force route so that the BE format can be set to Compr */
}
@@ -5970,6 +5978,10 @@
ALOGV("%s:E_AC3", __func__);
format = DOLBY_DIGITAL_PLUS;
break;
+ case AUDIO_FORMAT_DOLBY_TRUEHD:
+ ALOGV("%s:MAT", __func__);
+ format = MAT;
+ break;
case AUDIO_FORMAT_DTS:
ALOGV("%s:DTS", __func__);
format = DTS;
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..9fe713d 100644
--- a/qahw_api/test/qahw_playback_test.c
+++ b/qahw_api/test/qahw_playback_test.c
@@ -77,7 +77,8 @@
FILE_EAC3_JOC,
FILE_DTS,
FILE_MP2,
- FILE_APTX
+ FILE_APTX,
+ FILE_TRUEHD
};
typedef enum {
@@ -136,6 +137,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 +195,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 +245,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 +326,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 +352,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 +663,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);
@@ -934,6 +963,9 @@
case FILE_APTX:
stream_info->config.offload_info.format = AUDIO_FORMAT_APTX;
break;
+ case FILE_TRUEHD:
+ stream_info->config.offload_info.format = AUDIO_FORMAT_DOLBY_TRUEHD;
+ break;
default:
fprintf(log_file, "Does not support given filetype\n");
fprintf(stderr, "Does not support given filetype\n");
@@ -1031,6 +1063,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 +1382,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 +1577,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 +1604,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 +1633,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 +1696,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 +1750,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) {