audio: qahw_api: Initial version of QTI audio HAL
-Initial version of QTI Audio HAL Wrapper.
Change-Id: Ia11c9d6b736cb5e9fa732601c3a3efd8d75ddd98
diff --git a/qahw_api/src/qahw.c b/qahw_api/src/qahw.c
new file mode 100644
index 0000000..06bcee1
--- /dev/null
+++ b/qahw_api/src/qahw.c
@@ -0,0 +1,1513 @@
+/*
+* Copyright (c) 2016, 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 "qahw"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <utils/Log.h>
+#include <stdlib.h>
+#include <cutils/list.h>
+
+#include <hardware/audio.h>
+#include "qahw_api.h"
+
+#define NO_ERROR 0
+#define MAX_MODULE_NAME_LENGTH 100
+
+/*
+ * The current HAL API version.
+ */
+#define QAHW_MODULE_API_VERSION_CURRENT QAHW_MODULE_API_VERSION_0_0
+
+typedef struct {
+ audio_hw_device_t *audio_device;
+ char module_name[MAX_MODULE_NAME_LENGTH];
+ struct listnode module_list;
+ struct listnode in_list;
+ struct listnode out_list;
+ pthread_mutex_t lock;
+ uint32_t ref_count;
+} qahw_module_t;
+
+typedef struct {
+ qahw_module_t *module;
+ struct listnode module_list;
+ pthread_mutex_t lock;
+} qahw_module_instances_t;
+
+typedef struct {
+ audio_stream_out_t *stream;
+ qahw_module_t *module;
+ struct listnode list;
+ pthread_mutex_t lock;
+} qahw_stream_out_t;
+
+typedef struct {
+ audio_stream_in_t *stream;
+ qahw_module_t *module;
+ struct listnode list;
+ pthread_mutex_t lock;
+} qahw_stream_in_t;
+
+typedef enum {
+ STREAM_DIR_IN,
+ STREAM_DIR_OUT,
+} qahw_stream_direction_t;
+
+static struct listnode qahw_module_list;
+static int qahw_list_count;
+static pthread_mutex_t qahw_module_init_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/** Start of internal functions */
+/******************************************************************************/
+
+/* call this function without anylock held */
+static bool is_valid_qahw_stream(void *qahw_stream,
+ qahw_stream_direction_t dir)
+{
+
+ int is_valid = false;
+ struct listnode *module_node = NULL;
+ struct listnode *stream_node = NULL;
+ struct listnode *list_node = NULL;
+ void *stream = NULL;
+ qahw_module_t *qahw_module = NULL;
+
+ if (qahw_stream == NULL) {
+ ALOGE("%s:: Invalid stream", __func__);
+ goto exit;
+ }
+
+ if ((dir != STREAM_DIR_OUT) && (dir != STREAM_DIR_IN)) {
+ ALOGE("%s:: Invalid stream direction %d", __func__, dir);
+ goto exit;
+ }
+
+ /* go through all the modules and check for valid stream */
+ pthread_mutex_lock(&qahw_module_init_lock);
+ list_for_each(module_node, &qahw_module_list) {
+ qahw_module = node_to_item(module_node, qahw_module_t, module_list);
+ pthread_mutex_lock(&qahw_module->lock);
+ if(dir == STREAM_DIR_OUT)
+ list_node = &qahw_module->out_list;
+ else
+ list_node = &qahw_module->in_list;
+ list_for_each(stream_node, list_node) {
+ if(dir == STREAM_DIR_OUT)
+ stream = (void *)node_to_item(stream_node,
+ qahw_stream_out_t,
+ list);
+ else
+ stream = (void *)node_to_item(stream_node,
+ qahw_stream_in_t,
+ list);
+ if(stream == qahw_stream) {
+ is_valid = true;
+ break;
+ }
+ }
+ pthread_mutex_unlock(&qahw_module->lock);
+ if(is_valid)
+ break;
+ }
+ pthread_mutex_unlock(&qahw_module_init_lock);
+
+exit:
+ return is_valid;
+}
+
+/* call this fucntion with ahw_module_init_lock held*/
+static qahw_module_t* get_qahw_module_by_ptr(qahw_module_t *qahw_module)
+{
+ struct listnode *node = NULL;
+ qahw_module_t *module = NULL, *module_temp = NULL;
+
+ if (qahw_module == NULL)
+ goto exit;
+
+ list_for_each(node, &qahw_module_list) {
+ module_temp = node_to_item(node, qahw_module_t, module_list);
+ if (module_temp == qahw_module) {
+ module = module_temp;
+ break;
+ }
+ }
+exit:
+ return module;
+}
+
+/* call this function with qahw_module_init_lock held*/
+static qahw_module_t* get_qahw_module_by_name(const char *qahw_name)
+{
+ struct listnode *node = NULL;
+ qahw_module_t *module = NULL, *module_temp = NULL;
+
+ if (qahw_name == NULL)
+ goto exit;
+
+ list_for_each(node, &qahw_module_list) {
+ module_temp = node_to_item(node, qahw_module_t, module_list);
+ if(!strncmp(qahw_name, module_temp->module_name, MAX_MODULE_NAME_LENGTH)) {
+ module = module_temp;
+ break;
+ }
+ }
+exit:
+ return module;
+}
+/* End of of internal functions */
+
+/*
+ * Return the sampling rate in Hz - eg. 44100.
+ */
+uint32_t qahw_out_get_sample_rate(const qahw_stream_handle_t *out_handle)
+{
+ uint32_t rate = 0;
+ qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+ audio_stream_out_t *out = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+ ALOGV("%s::Invalid out handle %p", __func__, out_handle);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_stream_out->lock);
+ out = qahw_stream_out->stream;
+ if (out->common.get_sample_rate)
+ rate = out->common.get_sample_rate(&out->common);
+ else
+ ALOGW("%s not supported", __func__);
+ pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+ return rate;
+}
+
+/*
+ * currently unused - use set_parameters with key
+ * AUDIO_PARAMETER_STREAM_SAMPLING_RATE
+ */
+int qahw_out_set_sample_rate(qahw_stream_handle_t *out_handle, uint32_t rate)
+{
+ int32_t rc = -EINVAL;
+ qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+ audio_stream_out_t *out = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+ ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+ goto exit;
+ }
+ pthread_mutex_lock(&qahw_stream_out->lock);
+ out = qahw_stream_out->stream;
+ if (out->common.set_sample_rate) {
+ rc = out->common.set_sample_rate(&out->common, rate);
+ } else {
+ rc = -ENOSYS;
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_out->lock);
+exit:
+ return rc;
+}
+
+size_t qahw_out_get_buffer_size(const qahw_stream_handle_t *out_handle)
+{
+ size_t buf_size = 0;
+ qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+ audio_stream_out_t *out = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+ ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+ goto exit;
+ }
+ pthread_mutex_lock(&qahw_stream_out->lock);
+ out = qahw_stream_out->stream;
+ if (out->common.get_buffer_size) {
+ buf_size = out->common.get_buffer_size(&out->common);
+ } else {
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+ return buf_size;
+}
+
+audio_channel_mask_t qahw_out_get_channels(const qahw_stream_handle_t *out_handle)
+{
+ audio_channel_mask_t ch_mask = 0;
+ qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+ audio_stream_out_t *out = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+ ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+ goto exit;
+ }
+ pthread_mutex_lock(&qahw_stream_out->lock);
+ out = qahw_stream_out->stream;
+ if (out->common.get_channels) {
+ ch_mask = out->common.get_channels(&out->common);
+ } else {
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+ return ch_mask;
+}
+
+audio_format_t qahw_out_get_format(const qahw_stream_handle_t *out_handle)
+{
+ audio_format_t format = AUDIO_FORMAT_INVALID;
+ qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+ audio_stream_out_t *out = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+ ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+ goto exit;
+ }
+ pthread_mutex_lock(&qahw_stream_out->lock);
+ out = qahw_stream_out->stream;
+ if (out->common.get_format) {
+ format = out->common.get_format(&out->common);
+ } else {
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+ return format;
+}
+
+int qahw_out_standby(qahw_stream_handle_t *out_handle)
+{
+ int32_t rc = -EINVAL;
+ qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+ audio_stream_out_t *out = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+ ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_stream_out->lock);
+ out = qahw_stream_out->stream;
+ if (out->common.standby) {
+ rc = out->common.standby(&out->common);
+ } else {
+ rc = -ENOSYS;
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+ return rc;
+}
+
+int qahw_out_set_parameters(qahw_stream_handle_t *out_handle, const char *kv_pairs)
+{
+ int rc = NO_ERROR;
+ qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+ audio_stream_out_t *out = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+ ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_stream_out->lock);
+ out = qahw_stream_out->stream;
+ if (out->common.set_parameters) {
+ rc = out->common.set_parameters(&out->common, kv_pairs);
+ } else {
+ rc = -ENOSYS;
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+ return rc;
+}
+
+char *qahw_out_get_parameters(const qahw_stream_handle_t *out_handle,
+ const char *keys)
+{
+ char *str_param = NULL;
+ qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+ audio_stream_out_t *out = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+ ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_stream_out->lock);
+ out = qahw_stream_out->stream;
+ if (out->common.get_parameters) {
+ str_param = out->common.get_parameters(&out->common, keys);
+ } else {
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+ return str_param;
+}
+
+uint32_t qahw_out_get_latency(const qahw_stream_handle_t *out_handle)
+{
+ uint32_t latency = 0;
+ qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+ audio_stream_out_t *out = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+ ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_stream_out->lock);
+ out = qahw_stream_out->stream;
+ if (out->get_latency) {
+ latency = out->get_latency(out);
+ } else {
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+ return latency;
+}
+
+int qahw_out_set_volume(qahw_stream_handle_t *out_handle, float left, float right)
+{
+ int rc = -EINVAL;
+ qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+ audio_stream_out_t *out = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+ ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_stream_out->lock);
+ out = qahw_stream_out->stream;
+ if (out->set_volume) {
+ rc = out->set_volume(out, left, right);
+ } else {
+ rc = -ENOSYS;
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+ return rc;
+}
+
+ssize_t qahw_out_write(qahw_stream_handle_t *out_handle,
+ qahw_out_buffer_t *out_buf)
+{
+ int rc = -EINVAL;
+ qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+ audio_stream_out_t *out = NULL;
+
+ if ((out_buf == NULL) || (out_buf->buffer == NULL)) {
+ ALOGE("%s::Invalid meta data %p", __func__, out_buf);
+ goto exit;
+ }
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+ ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+ goto exit;
+ }
+
+ /*TBD:: validate other meta data parameters */
+
+ pthread_mutex_lock(&qahw_stream_out->lock);
+ out = qahw_stream_out->stream;
+ if (out->write) {
+ rc = out->write(out, out_buf->buffer, out_buf->bytes);
+ } else {
+ rc = -ENOSYS;
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_out->lock);
+exit:
+ return rc;
+}
+
+int qahw_out_get_render_position(const qahw_stream_handle_t *out_handle,
+ uint32_t *dsp_frames)
+{
+ int rc = -EINVAL;
+ qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+ audio_stream_out_t *out = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+ ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_stream_out->lock);
+ out = qahw_stream_out->stream;
+ if (out->get_render_position) {
+ rc = out->get_render_position(out, dsp_frames);
+ } else {
+ rc = -ENOSYS;
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_out->lock);
+exit:
+ return rc;
+}
+
+int qahw_out_set_callback(qahw_stream_handle_t *out_handle,
+ qahw_stream_callback_t callback,
+ void *cookie)
+{
+ /*TBD:load hal func pointer and call */
+ int rc = -EINVAL;
+ qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+ audio_stream_out_t *out = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+ ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_stream_out->lock);
+ out = qahw_stream_out->stream;
+ if (out->set_callback) {
+ rc = out->set_callback(out, (stream_callback_t)callback, cookie);
+ } else {
+ rc = -ENOSYS;
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+ return rc;
+}
+
+int qahw_out_pause(qahw_stream_handle_t *out_handle)
+{
+ /*TBD:load hal func pointer and call */
+ int rc = -EINVAL;
+ qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+ audio_stream_out_t *out = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+ ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_stream_out->lock);
+ out = qahw_stream_out->stream;
+ if (out->pause) {
+ rc = out->pause(out);
+ } else {
+ rc = -ENOSYS;
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+ return rc;
+}
+
+int qahw_out_resume(qahw_stream_handle_t *out_handle)
+{
+ /*TBD:load hal func pointer and call */
+ int rc = -EINVAL;
+ qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+ audio_stream_out_t *out = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+ ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_stream_out->lock);
+ out = qahw_stream_out->stream;
+ if (out->resume) {
+ rc = out->resume(out);
+ } else {
+ rc = -ENOSYS;
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+ return rc;
+}
+
+int qahw_out_drain(qahw_stream_handle_t *out_handle, qahw_drain_type_t type )
+{
+ /*TBD:load hal func pointer and call */
+ int rc = -EINVAL;
+ qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+ audio_stream_out_t *out = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+ ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_stream_out->lock);
+ out = qahw_stream_out->stream;
+ if (out->drain) {
+ rc = out->drain(out,(audio_drain_type_t)type);
+ } else {
+ rc = -ENOSYS;
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+ return rc;
+}
+
+int qahw_out_flush(qahw_stream_handle_t *out_handle)
+{
+ int rc = -EINVAL;
+ qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+ audio_stream_out_t *out = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+ ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_stream_out->lock);
+ out = qahw_stream_out->stream;
+ if (out->flush) {
+ rc = out->flush(out);
+ } else {
+ rc = -ENOSYS;
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+ return rc;
+}
+
+int qahw_out_get_presentation_position(const qahw_stream_handle_t *out_handle,
+ uint64_t *frames, struct timespec *timestamp)
+{
+ int rc = -EINVAL;
+ qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+ audio_stream_out_t *out = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+ ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_stream_out->lock);
+ out = qahw_stream_out->stream;
+ if (out->get_presentation_position) {
+ rc = out->get_presentation_position(out, frames, timestamp);
+ } else {
+ rc = -ENOSYS;
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+ return rc;
+}
+
+/* Input stream specific APIs */
+uint32_t qahw_in_get_sample_rate(const qahw_stream_handle_t *in_handle)
+{
+ uint32_t rate = 0;
+ qahw_stream_in_t *qahw_stream_in = (qahw_stream_in_t *)in_handle;
+ audio_stream_in_t *in = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_in, STREAM_DIR_IN)) {
+ ALOGV("%s::Invalid in handle %p", __func__, in_handle);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_stream_in->lock);
+ in = qahw_stream_in->stream;
+ if (in->common.get_sample_rate) {
+ rate = in->common.get_sample_rate(&in->common);
+ } else {
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_in->lock);
+
+exit:
+ return rate;
+}
+
+/*
+ * currently unused - use set_parameters with key
+ * AUDIO_PARAMETER_STREAM_SAMPLING_RATE
+ */
+int qahw_in_set_sample_rate(qahw_stream_handle_t *in_handle, uint32_t rate)
+{
+ int rc = -EINVAL;
+ qahw_stream_in_t *qahw_stream_in = (qahw_stream_in_t *)in_handle;
+ audio_stream_in_t *in = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_in, STREAM_DIR_IN)) {
+ ALOGV("%s::Invalid in handle %p", __func__, in_handle);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_stream_in->lock);
+ in = qahw_stream_in->stream;
+ if (in->common.set_sample_rate) {
+ rc = in->common.set_sample_rate(&in->common, rate);
+ } else {
+ rc = -ENOSYS;
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_in->lock);
+
+exit:
+ return rc;
+}
+
+size_t qahw_in_get_buffer_size(const qahw_stream_handle_t *in_handle)
+{
+ size_t buf_size = 0;
+ qahw_stream_in_t *qahw_stream_in = (qahw_stream_in_t *)in_handle;
+ audio_stream_in_t *in = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_in, STREAM_DIR_IN)) {
+ ALOGV("%s::Invalid in handle %p", __func__, in_handle);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_stream_in->lock);
+ in = qahw_stream_in->stream;
+ if (in->common.get_sample_rate) {
+ buf_size = in->common.get_buffer_size(&in->common);
+ } else {
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_in->lock);
+
+exit:
+ return buf_size;
+}
+
+
+audio_channel_mask_t qahw_in_get_channels(const qahw_stream_handle_t *in_handle)
+{
+ audio_channel_mask_t ch_mask = 0;;
+ qahw_stream_in_t *qahw_stream_in = (qahw_stream_in_t *)in_handle;
+ audio_stream_in_t *in = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_in, STREAM_DIR_IN)) {
+ ALOGV("%s::Invalid in handle %p", __func__, in_handle);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_stream_in->lock);
+ in = qahw_stream_in->stream;
+ if (in->common.get_channels) {
+ ch_mask = in->common.get_channels(&in->common);
+ } else {
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_in->lock);
+
+exit:
+ return ch_mask;
+}
+
+audio_format_t qahw_in_get_format(const qahw_stream_handle_t *in_handle)
+{
+ audio_format_t format = AUDIO_FORMAT_INVALID;
+ qahw_stream_in_t *qahw_stream_in = (qahw_stream_in_t *)in_handle;
+ audio_stream_in_t *in = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_in, STREAM_DIR_IN)) {
+ ALOGV("%s::Invalid in handle %p", __func__, in_handle);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_stream_in->lock);
+ in = qahw_stream_in->stream;
+ if (in->common.get_format) {
+ format = in->common.get_format(&in->common);
+ } else {
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_in->lock);
+
+exit:
+ return format;
+}
+
+/*
+ * currently unused - use set_parameters with key
+ * AUDIO_PARAMETER_STREAM_FORMAT
+ */
+int qahw_in_set_format(qahw_stream_handle_t *in_handle, audio_format_t format)
+{
+ int rc = -EINVAL;
+ qahw_stream_in_t *qahw_stream_in = (qahw_stream_in_t *)in_handle;
+ audio_stream_in_t *in = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_in, STREAM_DIR_IN)) {
+ ALOGV("%s::Invalid in handle %p", __func__, in_handle);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_stream_in->lock);
+ in = qahw_stream_in->stream;
+ if (in->common.set_format) {
+ rc = in->common.set_format(&in->common, format);
+ } else {
+ rc = -ENOSYS;
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_in->lock);
+
+exit:
+ return rc;
+}
+
+int qahw_in_standby(qahw_stream_handle_t *in_handle)
+{
+ int rc = -EINVAL;
+ qahw_stream_in_t *qahw_stream_in = (qahw_stream_in_t *)in_handle;
+ audio_stream_in_t *in = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_in, STREAM_DIR_IN)) {
+ ALOGV("%s::Invalid in handle %p", __func__, in_handle);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_stream_in->lock);
+ in = qahw_stream_in->stream;
+ if (in->common.standby) {
+ rc = in->common.standby(&in->common);
+ } else {
+ rc = -ENOSYS;
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_in->lock);
+
+exit:
+ return rc;
+}
+
+/*
+ * set/get audio stream parameters. The function accepts a list of
+ * parameter key value pairs in the form: key1=value1;key2=value2;...
+ *
+ * Some keys are reserved for standard parameters (See AudioParameter class)
+ *
+ * If the implementation does not accept a parameter change while
+ * the output is active but the parameter is acceptable otherwise, it must
+ * return -ENOSYS.
+ *
+ * The audio flinger will put the stream in standby and then change the
+ * parameter value.
+ */
+int qahw_in_set_parameters(qahw_stream_handle_t *in_handle, const char *kv_pairs)
+{
+ int rc = -EINVAL;
+ qahw_stream_in_t *qahw_stream_in = (qahw_stream_in_t *)in_handle;
+ audio_stream_in_t *in = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_in, STREAM_DIR_IN)) {
+ ALOGV("%s::Invalid in handle %p", __func__, in_handle);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_stream_in->lock);
+ in = qahw_stream_in->stream;
+ if (in->common.set_parameters) {
+ rc = in->common.set_parameters(&in->common, kv_pairs);
+ } else {
+ rc = -ENOSYS;
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_in->lock);
+exit:
+ return rc;
+}
+
+/*
+ * Returns a pointer to a heap allocated string. The caller is responsible
+ * for freeing the memory for it using free().
+ */
+char * qahw_in_get_parameters(const qahw_stream_handle_t *in_handle,
+ const char *keys)
+{
+ char *str_param = NULL;
+ qahw_stream_in_t *qahw_stream_in = (qahw_stream_in_t *)in_handle;
+ audio_stream_in_t *in = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_in, STREAM_DIR_IN)) {
+ ALOGV("%s::Invalid in handle %p", __func__, in_handle);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_stream_in->lock);
+ in = qahw_stream_in->stream;
+ if (in->common.get_parameters) {
+ str_param = in->common.get_parameters(&in->common, keys);
+ } else {
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_in->lock);
+
+exit:
+ return str_param;
+}
+
+/*
+ * Read audio buffer in from audio driver. Returns number of bytes read, or a
+ * negative status_t. If at least one frame was read prior to the error,
+ * read should return that byte count and then return an error in the subsequent call.
+ */
+ssize_t qahw_in_read(qahw_stream_handle_t *in_handle,
+ qahw_in_buffer_t *in_buf)
+{
+ int rc = -EINVAL;
+ qahw_stream_in_t *qahw_stream_in = (qahw_stream_in_t *)in_handle;
+ audio_stream_in_t *in = NULL;
+
+ if ((in_buf == NULL) || (in_buf->buffer == NULL)) {
+ ALOGE("%s::Invalid meta data %p", __func__, in_buf);
+ goto exit;
+ }
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_in, STREAM_DIR_IN)) {
+ ALOGV("%s::Invalid in handle %p", __func__, in_handle);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_stream_in->lock);
+ in = qahw_stream_in->stream;
+ /*TBD:: call HAL timestamp read API*/
+ if (in->read) {
+ rc = in->read(in, in_buf->buffer, in_buf->bytes);
+ in_buf->offset = 0;
+ } else {
+ rc = -ENOSYS;
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_in->lock);
+
+exit:
+ return rc;
+}
+
+/*
+ * Return the amount of input frames lost in the audio driver since the
+ * last call of this function.
+ * Audio driver is expected to reset the value to 0 and restart counting
+ * upon returning the current value by this function call.
+ * Such loss typically occurs when the user space process is blocked
+ * longer than the capacity of audio driver buffers.
+ *
+ * Unit: the number of input audio frames
+ */
+uint32_t qahw_in_get_input_frames_lost(qahw_stream_handle_t *in_handle)
+{
+ uint32_t rc = 0;
+ qahw_stream_in_t *qahw_stream_in = (qahw_stream_in_t *)in_handle;
+ audio_stream_in_t *in = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_in, STREAM_DIR_IN)) {
+ ALOGV("%s::Invalid in handle %p", __func__, in_handle);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_stream_in->lock);
+ in = qahw_stream_in->stream;
+ if (in->get_input_frames_lost) {
+ rc = in->get_input_frames_lost(in);
+ } else {
+ rc = -ENOSYS;
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_in->lock);
+
+exit:
+ return rc;
+}
+
+/*
+ * Return a recent count of the number of audio frames received and
+ * the clock time associated with that frame count.
+ *
+ * frames is the total frame count received. This should be as early in
+ * the capture pipeline as possible. In general,
+ * frames should be non-negative and should not go "backwards".
+ *
+ * time is the clock MONOTONIC time when frames was measured. In general,
+ * time should be a positive quantity and should not go "backwards".
+ *
+ * The status returned is 0 on success, -ENOSYS if the device is not
+ * ready/available, or -EINVAL if the arguments are null or otherwise invalid.
+ */
+int qahw_in_get_capture_position(const qahw_stream_handle_t *in_handle __unused,
+ int64_t *frames __unused, int64_t *time __unused)
+{
+ /*TBD:: do we need this*/
+ return -ENOSYS;
+}
+
+/*
+ * check to see if the audio hardware interface has been initialized.
+ * returns 0 on success, -ENODEV on failure.
+ */
+int qahw_init_check(const qahw_module_handle_t *hw_module)
+{
+ int rc = -EINVAL;
+ qahw_module_t *qahw_module = (qahw_module_t *)hw_module;
+ qahw_module_t *qahw_module_temp;
+
+ pthread_mutex_lock(&qahw_module_init_lock);
+ qahw_module_temp = get_qahw_module_by_ptr(qahw_module);
+ pthread_mutex_unlock(&qahw_module_init_lock);
+ if (qahw_module_temp == NULL) {
+ ALOGE("%s:: invalid hw module %p", __func__, qahw_module);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_module->lock);
+ if (qahw_module->audio_device->init_check) {
+ rc = qahw_module->audio_device->init_check(qahw_module->audio_device);
+ } else {
+ rc = -ENOSYS;
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_module->lock);
+
+exit:
+ return rc;
+}
+/* set the audio volume of a voice call. Range is between 0.0 and 1.0 */
+int qahw_set_voice_volume(qahw_module_handle_t *hw_module, float volume)
+{
+ int rc = -EINVAL;
+ qahw_module_t *qahw_module = (qahw_module_t *)hw_module;
+ qahw_module_t *qahw_module_temp;
+
+ pthread_mutex_lock(&qahw_module_init_lock);
+ qahw_module_temp = get_qahw_module_by_ptr(qahw_module);
+ pthread_mutex_unlock(&qahw_module_init_lock);
+ if (qahw_module_temp == NULL) {
+ ALOGE("%s:: invalid hw module %p", __func__, qahw_module);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_module->lock);
+ if (qahw_module->audio_device->set_voice_volume) {
+ rc = qahw_module->audio_device->set_voice_volume(qahw_module->audio_device,
+ volume);
+ } else {
+ rc = -ENOSYS;
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_module->lock);
+
+exit:
+ return rc;
+}
+
+/*
+ * set_mode is called when the audio mode changes. AUDIO_MODE_NORMAL mode
+ * is for standard audio playback, AUDIO_MODE_RINGTONE when a ringtone is
+ * playing, and AUDIO_MODE_IN_CALL when a call is in progress.
+ */
+int qahw_set_mode(qahw_module_handle_t *hw_module, audio_mode_t mode)
+{
+ int rc = -EINVAL;
+ qahw_module_t *qahw_module = (qahw_module_t *)hw_module;
+ qahw_module_t *qahw_module_temp;
+
+ pthread_mutex_lock(&qahw_module_init_lock);
+ qahw_module_temp = get_qahw_module_by_ptr(qahw_module);
+ pthread_mutex_unlock(&qahw_module_init_lock);
+ if (qahw_module_temp == NULL) {
+ ALOGE("%s:: invalid hw module %p", __func__, qahw_module);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_module->lock);
+ if (qahw_module->audio_device->set_mode) {
+ rc = qahw_module->audio_device->set_mode(qahw_module->audio_device,
+ mode);
+ } else {
+ rc = -ENOSYS;
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_module->lock);
+
+exit:
+ return rc;
+}
+
+/* set/get global audio parameters */
+int qahw_set_parameters(qahw_module_handle_t *hw_module, const char *kv_pairs)
+{
+ int rc = -EINVAL;
+ qahw_module_t *qahw_module = (qahw_module_t *)hw_module;
+ qahw_module_t *qahw_module_temp;
+ audio_hw_device_t *audio_device;
+
+ pthread_mutex_lock(&qahw_module_init_lock);
+ qahw_module_temp = get_qahw_module_by_ptr(qahw_module);
+ pthread_mutex_unlock(&qahw_module_init_lock);
+ if (qahw_module_temp == NULL) {
+ ALOGE("%s:: invalid hw module %p", __func__, qahw_module);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_module->lock);
+ audio_device = qahw_module->audio_device;
+ if (qahw_module->audio_device->set_parameters) {
+ rc = audio_device->set_parameters(qahw_module->audio_device, kv_pairs);
+ } else {
+ rc = -ENOSYS;
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_module->lock);
+
+exit:
+ return rc;
+}
+
+/*
+ * Returns a pointer to a heap allocated string. The caller is responsible
+ * for freeing the memory for it using free().
+ */
+char * qahw_get_parameters(const qahw_module_handle_t *hw_module,
+ const char *keys)
+{
+ char *str_param = NULL;
+ qahw_module_t *qahw_module = (qahw_module_t *)hw_module;
+ qahw_module_t *qahw_module_temp;
+ audio_hw_device_t *audio_device;
+
+ pthread_mutex_lock(&qahw_module_init_lock);
+ qahw_module_temp = get_qahw_module_by_ptr(qahw_module);
+ pthread_mutex_unlock(&qahw_module_init_lock);
+ if (qahw_module_temp == NULL) {
+ ALOGE("%s:: invalid hw module %p", __func__, qahw_module);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_module->lock);
+ audio_device = qahw_module->audio_device;
+ if (qahw_module->audio_device->get_parameters) {
+ str_param = audio_device->get_parameters(qahw_module->audio_device, keys);
+ } else {
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_module->lock);
+
+exit:
+ return str_param;
+}
+
+/* Returns audio input buffer size according to parameters passed or
+ * 0 if one of the parameters is not supported.
+ * See also get_buffer_size which is for a particular stream.
+ */
+size_t qahw_get_input_buffer_size(const qahw_module_handle_t *hw_module,
+ const struct audio_config *config)
+{
+ size_t rc = 0;
+ qahw_module_t *qahw_module = (qahw_module_t *)hw_module;
+ qahw_module_t *qahw_module_temp;
+ audio_hw_device_t *audio_device;
+
+ pthread_mutex_lock(&qahw_module_init_lock);
+ qahw_module_temp = get_qahw_module_by_ptr(qahw_module);
+ pthread_mutex_unlock(&qahw_module_init_lock);
+ if (qahw_module_temp == NULL) {
+ ALOGE("%s:: invalid hw module %p", __func__, qahw_module);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_module->lock);
+ audio_device = qahw_module->audio_device;
+ if (qahw_module->audio_device->get_input_buffer_size) {
+ rc = audio_device->get_input_buffer_size(qahw_module->audio_device,
+ config);
+ } else {
+ rc = -ENOSYS;
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_module->lock);
+
+exit:
+ return rc;
+}
+
+/*
+ * This method creates and opens the audio hardware output stream.
+ * The "address" parameter qualifies the "devices" audio device type if needed.
+ * The format format depends on the device type:
+ * - Bluetooth devices use the MAC address of the device in the form "00:11:22:AA:BB:CC"
+ * - USB devices use the ALSA card and device numbers in the form "card=X;device=Y"
+ * - Other devices may use a number or any other string.
+ */
+int qahw_open_output_stream(qahw_module_handle_t *hw_module,
+ audio_io_handle_t handle,
+ audio_devices_t devices,
+ audio_output_flags_t flags,
+ struct audio_config *config,
+ qahw_stream_handle_t **out_handle,
+ const char *address)
+{
+ int rc = -EINVAL;
+ qahw_module_t *qahw_module = (qahw_module_t *)hw_module;
+ qahw_module_t *qahw_module_temp = NULL;
+ audio_hw_device_t *audio_device = NULL;
+ qahw_stream_out_t *qahw_stream_out = NULL;
+
+ pthread_mutex_lock(&qahw_module_init_lock);
+ qahw_module_temp = get_qahw_module_by_ptr(qahw_module);
+ pthread_mutex_unlock(&qahw_module_init_lock);
+ if (qahw_module_temp == NULL) {
+ ALOGE("%s:: invalid hw module %p", __func__, qahw_module);
+ return rc;
+ }
+
+ pthread_mutex_lock(&qahw_module->lock);
+ audio_device = qahw_module->audio_device;
+ qahw_stream_out = (qahw_stream_out_t *)calloc(1, sizeof(qahw_stream_out_t));
+ if (qahw_stream_out == NULL) {
+ ALOGE("%s:: calloc failed for out stream_out_t",__func__);
+ rc = -ENOMEM;
+ goto exit;
+ }
+
+ rc = audio_device->open_output_stream(audio_device,
+ handle,
+ devices,
+ flags,
+ config,
+ &qahw_stream_out->stream,
+ address);
+ if (rc) {
+ ALOGE("%s::open output stream failed %d",__func__, rc);
+ free(qahw_stream_out);
+ } else {
+ qahw_stream_out->module = hw_module;
+ *out_handle = (void *)qahw_stream_out;
+ pthread_mutex_init(&qahw_stream_out->lock, (const pthread_mutexattr_t *)NULL);
+ list_add_tail(&qahw_module->out_list, &qahw_stream_out->list);
+ }
+
+exit:
+ pthread_mutex_unlock(&qahw_module->lock);
+ return rc;
+}
+
+int qahw_close_output_stream(qahw_stream_handle_t *out_handle)
+{
+
+ int rc = 0;
+ qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+ qahw_module_t *qahw_module = NULL;
+ audio_hw_device_t *audio_device = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+ ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ ALOGV("%s::calling device close_output_stream %p", __func__, out_handle);
+ pthread_mutex_lock(&qahw_stream_out->lock);
+ qahw_module = qahw_stream_out->module;
+ audio_device = qahw_module->audio_device;
+ audio_device->close_output_stream(audio_device,
+ qahw_stream_out->stream);
+
+ pthread_mutex_lock(&qahw_module->lock);
+ list_remove(&qahw_stream_out->list);
+ pthread_mutex_unlock(&qahw_module->lock);
+
+ pthread_mutex_unlock(&qahw_stream_out->lock);
+
+ pthread_mutex_destroy(&qahw_stream_out->lock);
+ free(qahw_stream_out);
+
+exit:
+ return rc;
+}
+
+/* This method creates and opens the audio hardware input stream */
+int qahw_open_input_stream(qahw_module_handle_t *hw_module,
+ audio_io_handle_t handle,
+ audio_devices_t devices,
+ struct audio_config *config,
+ qahw_stream_handle_t **in_handle,
+ audio_input_flags_t flags,
+ const char *address,
+ audio_source_t source)
+{
+ int rc = -EINVAL;
+ qahw_module_t *qahw_module = (qahw_module_t *)hw_module;
+ qahw_module_t *qahw_module_temp = NULL;
+ audio_hw_device_t *audio_device = NULL;
+ qahw_stream_in_t *qahw_stream_in = NULL;
+
+ pthread_mutex_lock(&qahw_module_init_lock);
+ qahw_module_temp = get_qahw_module_by_ptr(qahw_module);
+ pthread_mutex_unlock(&qahw_module_init_lock);
+ if (qahw_module_temp == NULL) {
+ ALOGE("%s:: invalid hw module %p", __func__, qahw_module);
+ return rc;
+ }
+
+ pthread_mutex_lock(&qahw_module->lock);
+ audio_device = qahw_module->audio_device;
+ qahw_stream_in = (qahw_stream_in_t *)calloc(1, sizeof(qahw_stream_in_t));
+ if (qahw_stream_in == NULL) {
+ ALOGE("%s:: calloc failed for in stream_in_t",__func__);
+ rc = -ENOMEM;
+ goto exit;
+ }
+
+ rc = audio_device->open_input_stream(audio_device,
+ handle,
+ devices,
+ config,
+ &qahw_stream_in->stream,
+ flags,
+ address,
+ source);
+ if (rc) {
+ ALOGE("%s::open input stream failed %d",__func__, rc);
+ free(qahw_stream_in);
+ } else {
+ qahw_stream_in->module = hw_module;
+ *in_handle = (void *)qahw_stream_in;
+ pthread_mutex_init(&qahw_stream_in->lock, (const pthread_mutexattr_t *)NULL);
+ list_add_tail(&qahw_module->in_list, &qahw_stream_in->list);
+ }
+
+exit:
+ pthread_mutex_unlock(&qahw_module->lock);
+ return rc;
+}
+
+int qahw_close_input_stream(qahw_stream_handle_t *in_handle)
+{
+ int rc = 0;
+ qahw_stream_in_t *qahw_stream_in = (qahw_stream_in_t *)in_handle;
+ qahw_module_t *qahw_module = NULL;
+ audio_hw_device_t *audio_device = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_in, STREAM_DIR_IN)) {
+ ALOGV("%s::Invalid in handle %p", __func__, in_handle);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ ALOGV("%s:: calling device close_input_stream %p", __func__, in_handle);
+ pthread_mutex_lock(&qahw_stream_in->lock);
+ qahw_module = qahw_stream_in->module;
+ audio_device = qahw_module->audio_device;
+ audio_device->close_input_stream(audio_device,
+ qahw_stream_in->stream);
+
+ pthread_mutex_lock(&qahw_module->lock);
+ list_remove(&qahw_stream_in->list);
+ pthread_mutex_unlock(&qahw_module->lock);
+
+ pthread_mutex_unlock(&qahw_stream_in->lock);
+
+ pthread_mutex_destroy(&qahw_stream_in->lock);
+ free(qahw_stream_in);
+
+exit:
+ return rc;
+}
+
+/*returns current QTI HAL verison */
+int qahw_get_version() {
+ return QAHW_MODULE_API_VERSION_CURRENT;
+}
+
+/* convenience API for opening and closing an audio HAL module */
+
+qahw_module_handle_t *qahw_load_module(const char *hw_module_id)
+{
+ int rc = -EINVAL;
+ qahw_module_handle_t *qahw_mod_handle = NULL;
+ qahw_module_t *qahw_module = NULL;
+ char *ahal_name = NULL;
+ const hw_module_t* module = NULL;
+ audio_hw_device_t* audio_device = NULL;
+
+ if (hw_module_id == NULL) {
+ ALOGE("%s::module id is NULL",__func__);
+ goto exit;
+ }
+
+ if (!strcmp(hw_module_id, QAHW_MODULE_ID_PRIMARY)) {
+ ahal_name = "primary";
+ } else if (!strcmp(hw_module_id, QAHW_MODULE_ID_A2DP)) {
+ ahal_name = "a2dp";
+ } else if (!strcmp(hw_module_id, QAHW_MODULE_ID_USB)) {
+ ahal_name = "usb";
+ } else {
+ ALOGE("%s::Invalid Module id %s", __func__, hw_module_id);
+ goto exit;
+ }
+
+ /* return exiting module ptr if already loaded */
+ pthread_mutex_lock(&qahw_module_init_lock);
+ if (qahw_list_count > 0) {
+ qahw_module = get_qahw_module_by_name(hw_module_id);
+ if(qahw_module != NULL) {
+ qahw_mod_handle = (void *)qahw_module;
+ pthread_mutex_lock(&qahw_module->lock);
+ qahw_module->ref_count++;
+ pthread_mutex_unlock(&qahw_module->lock);
+ goto error_exit;
+ }
+ }
+
+ rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, ahal_name, &module);
+ if(rc) {
+ ALOGE("%s::HAL Loading failed %d", __func__, rc);
+ goto error_exit;
+ }
+
+ rc = audio_hw_device_open(module, &audio_device);
+ if(rc) {
+ ALOGE("%s::HAL Device open failed %d", __func__, rc);
+ goto error_exit;
+ }
+
+ qahw_module = (qahw_module_t *)calloc(1, sizeof(qahw_module_t));
+ if(qahw_module == NULL) {
+ ALOGE("%s::calloc failed", __func__);
+ audio_hw_device_close(audio_device);
+ goto error_exit;
+ }
+ ALOGD("%s::Loaded HAL %s module %p", __func__, ahal_name, qahw_module);
+
+ if (!qahw_list_count)
+ list_init(&qahw_module_list);
+ qahw_list_count++;
+
+ pthread_mutex_init(&qahw_module->lock, (const pthread_mutexattr_t *) NULL);
+ pthread_mutex_lock(&qahw_module->lock);
+ qahw_module->ref_count++;
+ pthread_mutex_unlock(&qahw_module->lock);
+
+ list_init(&qahw_module->out_list);
+ list_init(&qahw_module->in_list);
+
+ /* update qahw_module */
+ qahw_module->audio_device = audio_device;
+ strlcpy(&qahw_module->module_name[0], hw_module_id, MAX_MODULE_NAME_LENGTH);
+
+ qahw_mod_handle = (void *)qahw_module;
+
+ /* Add module list to global module list */
+ list_add_tail(&qahw_module_list, &qahw_module->module_list);
+
+
+error_exit:
+ pthread_mutex_unlock(&qahw_module_init_lock);
+
+exit:
+ return qahw_mod_handle;
+}
+
+int qahw_unload_module(qahw_module_handle_t *hw_module)
+{
+ int rc = -EINVAL;
+ bool is_empty = false;
+ qahw_module_t *qahw_module = (qahw_module_t *)hw_module;
+ qahw_module_t *qahw_module_temp = NULL;
+
+ /* close HW device if its valid and all the streams on
+ * it is closed
+ */
+ pthread_mutex_lock(&qahw_module_init_lock);
+ qahw_module_temp = get_qahw_module_by_ptr(qahw_module);
+ if (qahw_module_temp == NULL) {
+ ALOGE("%s:: invalid hw module %p", __func__, qahw_module);
+ goto error_exit;
+ }
+
+ pthread_mutex_lock(&qahw_module->lock);
+ qahw_module->ref_count--;
+ if (qahw_module->ref_count > 0) {
+ rc = 0;
+ ALOGE("%s:: skipping module unload of %p count %d", __func__,
+ qahw_module,
+ qahw_module->ref_count);
+ pthread_mutex_unlock(&qahw_module->lock);
+ goto error_exit;
+ }
+
+ is_empty = (list_empty(&qahw_module->out_list) &&
+ list_empty(&qahw_module->in_list));
+ if (is_empty) {
+ rc = audio_hw_device_close(qahw_module->audio_device);
+ if(rc) {
+ ALOGE("%s::HAL Device close failed Error %d Module %p",__func__,
+ rc, qahw_module);
+ rc = 0;
+ }
+ qahw_list_count--;
+ list_remove(&qahw_module->module_list);
+ pthread_mutex_unlock(&qahw_module->lock);
+ pthread_mutex_destroy(&qahw_module->lock);
+ free(qahw_module);
+ } else {
+ pthread_mutex_unlock(&qahw_module->lock);
+ ALOGE("%s::failed as all the streams on this module"
+ "is not closed", __func__);
+ rc = -EINVAL;
+ }
+
+error_exit:
+ pthread_mutex_unlock(&qahw_module_init_lock);
+
+exit:
+ return rc;
+}
+
+__END_DECLS