| /* |
| * Copyright (c) 2016-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 "qahw" |
| /*#define LOG_NDEBUG 0*/ |
| #define LOG_NDDEBUG 0 |
| |
| #include <dlfcn.h> |
| #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 uint64_t (*qahwi_out_write_v2_t)(audio_stream_out_t *out, const void* buffer, |
| size_t bytes, int64_t* timestamp); |
| |
| typedef int (*qahwi_get_param_data_t) (const audio_hw_device_t *, |
| qahw_param_id, qahw_param_payload *); |
| |
| typedef int (*qahwi_set_param_data_t) (audio_hw_device_t *, |
| qahw_param_id, qahw_param_payload *); |
| |
| typedef uint64_t (*qahwi_in_read_v2_t)(audio_stream_in_t *in, void* buffer, |
| size_t bytes, int64_t *timestamp); |
| |
| typedef int (*qahwi_out_set_param_data_t)(struct audio_stream_out *out, |
| qahw_param_id param_id, |
| qahw_param_payload *payload); |
| |
| typedef int (*qahwi_out_get_param_data_t)(struct audio_stream_out *out, |
| qahw_param_id param_id, |
| qahw_param_payload *payload); |
| |
| 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; |
| const hw_module_t* module; |
| qahwi_get_param_data_t qahwi_get_param_data; |
| qahwi_set_param_data_t qahwi_set_param_data; |
| } 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; |
| qahwi_out_set_param_data_t qahwi_out_get_param_data; |
| qahwi_out_get_param_data_t qahwi_out_set_param_data; |
| qahwi_out_write_v2_t qahwi_out_write_v2; |
| } qahw_stream_out_t; |
| |
| typedef struct { |
| audio_stream_in_t *stream; |
| qahw_module_t *module; |
| struct listnode list; |
| pthread_mutex_t lock; |
| qahwi_in_read_v2_t qahwi_in_read_v2; |
| } 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; |
| } |
| |
| /* API to get playback stream specific config parameters */ |
| int qahw_out_set_param_data(qahw_stream_handle_t *out_handle, |
| qahw_param_id param_id, |
| qahw_param_payload *payload) |
| { |
| int rc = -EINVAL; |
| qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle; |
| audio_stream_out_t *out = NULL; |
| |
| if (!payload) { |
| ALOGE("%s::Invalid param", __func__); |
| 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; |
| } |
| |
| pthread_mutex_lock(&qahw_stream_out->lock); |
| out = qahw_stream_out->stream; |
| if (qahw_stream_out->qahwi_out_set_param_data) { |
| rc = qahw_stream_out->qahwi_out_set_param_data(out, param_id, payload); |
| } else { |
| rc = -ENOSYS; |
| ALOGW("%s not supported", __func__); |
| } |
| pthread_mutex_unlock(&qahw_stream_out->lock); |
| |
| exit: |
| return rc; |
| } |
| |
| /* API to get playback stream specific config parameters */ |
| int qahw_out_get_param_data(qahw_stream_handle_t *out_handle, |
| qahw_param_id param_id, |
| qahw_param_payload *payload) |
| { |
| 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 (qahw_stream_out->qahwi_out_get_param_data) { |
| rc = qahw_stream_out->qahwi_out_get_param_data(out, param_id, payload); |
| } else { |
| rc = -ENOSYS; |
| ALOGW("%s not supported", __func__); |
| } |
| pthread_mutex_unlock(&qahw_stream_out->lock); |
| |
| exit: |
| return rc; |
| } |
| |
| 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 (qahw_stream_out->qahwi_out_write_v2) { |
| rc = qahw_stream_out->qahwi_out_write_v2(out, out_buf->buffer, |
| out_buf->bytes, out_buf->timestamp); |
| out_buf->offset = 0; |
| } else 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; |
| if (qahw_stream_in->qahwi_in_read_v2) { |
| rc = qahw_stream_in->qahwi_in_read_v2(in, in_buf->buffer, |
| in_buf->bytes, in_buf->timestamp); |
| in_buf->offset = 0; |
| } else 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; |
| } |
| |
| int qahw_set_mic_mute(qahw_module_handle_t *hw_module, bool state) |
| { |
| 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_mic_mute) { |
| rc = qahw_module->audio_device->set_mic_mute(qahw_module->audio_device, |
| state); |
| } else { |
| rc = -ENOSYS; |
| ALOGW("%s not supported", __func__); |
| } |
| pthread_mutex_unlock(&qahw_module->lock); |
| |
| exit: |
| return rc; |
| } |
| |
| int qahw_get_mic_mute(qahw_module_handle_t *hw_module, bool *state) |
| { |
| 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_mic_mute) { |
| rc = audio_device->get_mic_mute(qahw_module->audio_device, state); |
| } 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; |
| } |
| |
| /* Api to implement get parameters based on keyword param_id |
| * and store data in payload. |
| */ |
| int qahw_get_param_data(const qahw_module_handle_t *hw_module, |
| qahw_param_id param_id, |
| qahw_param_payload *payload) |
| { |
| int ret = 0; |
| 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->qahwi_get_param_data){ |
| ret = qahw_module->qahwi_get_param_data (qahw_module->audio_device, |
| param_id, payload); |
| } else { |
| ret = -ENOSYS; |
| ALOGE("%s not supported\n",__func__); |
| } |
| pthread_mutex_unlock(&qahw_module->lock); |
| |
| exit: |
| return ret; |
| } |
| |
| /* Api to implement set parameters based on keyword param_id |
| * and data present in payload. |
| */ |
| int qahw_set_param_data(const qahw_module_handle_t *hw_module, |
| qahw_param_id param_id, |
| qahw_param_payload *payload) |
| { |
| int ret = 0; |
| 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->qahwi_set_param_data){ |
| ret = qahw_module->qahwi_set_param_data (qahw_module->audio_device, |
| param_id, payload); |
| } else { |
| ret = -ENOSYS; |
| ALOGE("%s not supported\n",__func__); |
| } |
| pthread_mutex_unlock(&qahw_module->lock); |
| |
| exit: |
| return ret; |
| } |
| |
| /* Creates an audio patch between several source and sink ports. |
| * The handle is allocated by the HAL and should be unique for this |
| * audio HAL module. |
| */ |
| int qahw_create_audio_patch(qahw_module_handle_t *hw_module, |
| unsigned int num_sources, |
| const struct audio_port_config *sources, |
| unsigned int num_sinks, |
| const struct audio_port_config *sinks, |
| audio_patch_handle_t *handle) |
| { |
| int ret = 0; |
| 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->create_audio_patch) { |
| ret = qahw_module->audio_device->create_audio_patch( |
| qahw_module->audio_device, |
| num_sources, |
| sources, |
| num_sinks, |
| sinks, |
| handle); |
| } else { |
| ret = -ENOSYS; |
| ALOGE("%s not supported\n",__func__); |
| } |
| pthread_mutex_unlock(&qahw_module->lock); |
| |
| exit: |
| return ret; |
| } |
| |
| /* Release an audio patch */ |
| int qahw_release_audio_patch(qahw_module_handle_t *hw_module, |
| audio_patch_handle_t handle) |
| { |
| int ret = 0; |
| 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->release_audio_patch) { |
| ret = qahw_module->audio_device->release_audio_patch( |
| qahw_module->audio_device, |
| handle); |
| } else { |
| ret = -ENOSYS; |
| ALOGE("%s not supported\n",__func__); |
| } |
| pthread_mutex_unlock(&qahw_module->lock); |
| |
| exit: |
| return ret; |
| } |
| |
| /* Fills the list of supported attributes for a given audio port. |
| * As input, "port" contains the information (type, role, address etc...) |
| * needed by the HAL to identify the port. |
| * As output, "port" contains possible attributes (sampling rates, formats, |
| * channel masks, gain controllers...) for this port. |
| */ |
| int qahw_get_audio_port(qahw_module_handle_t *hw_module, |
| struct audio_port *port) |
| { |
| int ret = 0; |
| 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->get_audio_port) { |
| ret = qahw_module->audio_device->get_audio_port( |
| qahw_module->audio_device, |
| port); |
| } else { |
| ret = -ENOSYS; |
| ALOGE("%s not supported\n",__func__); |
| } |
| pthread_mutex_unlock(&qahw_module->lock); |
| |
| exit: |
| return ret; |
| } |
| |
| /* Set audio port configuration */ |
| int qahw_set_audio_port_config(qahw_module_handle_t *hw_module, |
| const struct audio_port_config *config) |
| { |
| int ret = 0; |
| 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_audio_port_config) { |
| ret = qahw_module->audio_device->set_audio_port_config( |
| qahw_module->audio_device, |
| config); |
| } else { |
| ret = -ENOSYS; |
| ALOGE("%s not supported\n",__func__); |
| } |
| pthread_mutex_unlock(&qahw_module->lock); |
| |
| exit: |
| return ret; |
| } |
| |
| /* 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); |
| |
| /* clear any existing errors */ |
| const char *error; |
| dlerror(); |
| qahw_stream_out->qahwi_out_get_param_data = (qahwi_out_get_param_data_t) |
| dlsym(qahw_module->module->dso, |
| "qahwi_out_get_param_data"); |
| if ((error = dlerror()) != NULL) { |
| ALOGI("%s: dlsym error %s for qahwi_out_get_param_data", |
| __func__, error); |
| qahw_stream_out->qahwi_out_get_param_data = NULL; |
| } |
| |
| dlerror(); |
| qahw_stream_out->qahwi_out_set_param_data = (qahwi_out_set_param_data_t) |
| dlsym(qahw_module->module->dso, |
| "qahwi_out_set_param_data"); |
| if ((error = dlerror()) != NULL) { |
| ALOGI("%s: dlsym error %s for qahwi_out_set_param_data", |
| __func__, error); |
| qahw_stream_out->qahwi_out_set_param_data = NULL; |
| } |
| } |
| |
| /* dlsym qahwi_out_write_v2 */ |
| if (!rc) { |
| const char *error; |
| |
| /* clear any existing errors */ |
| dlerror(); |
| qahw_stream_out->qahwi_out_write_v2 = (qahwi_out_write_v2_t)dlsym(qahw_module->module->dso, "qahwi_out_write_v2"); |
| if ((error = dlerror()) != NULL) { |
| ALOGI("%s: dlsym error %s for qahwi_out_write_v2", __func__, error); |
| qahw_stream_out->qahwi_out_write_v2 = NULL; |
| } |
| } |
| |
| 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); |
| } |
| |
| /* dlsym qahwi_in_read_v2 if timestamp flag is used */ |
| if (!rc && (flags & QAHW_INPUT_FLAG_TIMESTAMP)) { |
| const char *error; |
| |
| /* clear any existing errors */ |
| dlerror(); |
| qahw_stream_in->qahwi_in_read_v2 = (qahwi_in_read_v2_t) |
| dlsym(qahw_module->module->dso, "qahwi_in_read_v2"); |
| if ((error = dlerror()) != NULL) { |
| ALOGI("%s: dlsym error %s for qahwi_in_read_v2", __func__, error); |
| qahw_stream_in->qahwi_in_read_v2 = NULL; |
| } |
| } |
| |
| 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; |
| } |
| qahw_module->module = module; |
| ALOGD("%s::Loaded HAL %s module %p", __func__, ahal_name, qahw_module); |
| |
| qahw_module->qahwi_get_param_data = (qahwi_get_param_data_t) dlsym (module->dso, |
| "qahwi_get_param_data"); |
| if (!qahw_module->qahwi_get_param_data) |
| ALOGD("%s::qahwi_get_param_data api is not defined\n",__func__); |
| |
| qahw_module->qahwi_set_param_data = (qahwi_set_param_data_t) dlsym (module->dso, |
| "qahwi_set_param_data"); |
| if (!qahw_module->qahwi_set_param_data) |
| ALOGD("%s::qahwi_set_param_data api is not defined\n",__func__); |
| |
| 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); |
| |
| return rc; |
| } |
| |
| __END_DECLS |