diff options
author | Sidipotu Ashok <sashok@codeaurora.org> | 2017-10-10 22:27:51 +0530 |
---|---|---|
committer | Dhanalakshmi Siddani <dsiddani@codeaurora.org> | 2017-11-16 11:08:30 +0530 |
commit | 404f26d1f68e5cf7cfd120ef3ae191356d5eb535 (patch) | |
tree | d918d3054f364800304adb727002fee037904fe7 /qahw | |
parent | 386d1871308e018cc5180e0d62863b2fac63e412 (diff) |
qahw: Add binder support for Audio HAL
- Bring in a new cpp source file which HAL clients talk to
- This code in turn makes the binder proxy/clients side calls
- The binder server calls into the existing qahw.c
Change-Id: I45625bcb2d8a2eb858c68d24f0cad3202d754244
Diffstat (limited to 'qahw')
-rw-r--r-- | qahw/Android.mk | 38 | ||||
-rw-r--r-- | qahw/Makefile.am | 20 | ||||
-rw-r--r-- | qahw/configure.ac | 36 | ||||
-rw-r--r-- | qahw/inc/qahw.h | 482 | ||||
-rw-r--r-- | qahw/inc/qahw_defs.h | 393 | ||||
-rw-r--r-- | qahw/inc/qahw_effect_api.h | 845 | ||||
-rw-r--r-- | qahw/src/qahw.c | 1934 | ||||
-rw-r--r-- | qahw/src/qahw_effect.c | 321 |
8 files changed, 4069 insertions, 0 deletions
diff --git a/qahw/Android.mk b/qahw/Android.mk new file mode 100644 index 00000000..c7df9e3e --- /dev/null +++ b/qahw/Android.mk @@ -0,0 +1,38 @@ +ifeq ($(strip $(BOARD_SUPPORTS_QAHW)),true) + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +libqahw-inc := $(LOCAL_PATH)/inc + +LOCAL_MODULE := libqahwwrapper +LOCAL_MODULE_TAGS := optional +LOCAL_C_INCLUDES := $(libqahw-inc) + +LOCAL_SRC_FILES := \ + src/qahw.c \ + src/qahw_effect.c + +LOCAL_SHARED_LIBRARIES := \ + liblog \ + libcutils \ + libhardware \ + libdl + +LOCAL_CFLAGS += -Wall -Werror + +LOCAL_COPY_HEADERS_TO := mm-audio/qahw/inc +LOCAL_COPY_HEADERS := inc/qahw.h +LOCAL_COPY_HEADERS += inc/qahw_effect_api.h + +LOCAL_PRELINK_MODULE := false + +include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_COPY_HEADERS_TO := mm-audio/qahw_api/inc +LOCAL_COPY_HEADERS := inc/qahw_defs.h + +include $(BUILD_COPY_HEADERS) +endif diff --git a/qahw/Makefile.am b/qahw/Makefile.am new file mode 100644 index 00000000..b6ebd8b5 --- /dev/null +++ b/qahw/Makefile.am @@ -0,0 +1,20 @@ +AM_CFLAGS = -I $(top_srcdir)/inc + +h_sources = inc/qahw.h \ + inc/qahw_effect_api.h + +qahw_include_HEADERS = $(h_sources) +qahw_includedir = $(includedir)/mm-audio/qahw/inc + +qahw_api_include_HEADERS = inc/qahw_defs.h +qahw_api_includedir = $(includedir)/mm-audio/qahw_api/inc + +lib_LTLIBRARIES = libqahwwrapper.la +libqahwwrapper_la_SOURCES = src/qahw.c \ + src/qahw_effect.c + +libqahwwrapper_la_CFLAGS = $(AM_CFLAGS) +libqahwwrapper_la_CFLAGS += -include stddef.h +libqahwwrapper_la_CFLAGS += -D__unused=__attribute__\(\(__unused__\)\) +libqahwwrapper_la_CFLAGS += -Werror +libqahwwrapper_la_LDFLAGS = -shared -avoid-version -llog -lcutils -lhardware diff --git a/qahw/configure.ac b/qahw/configure.ac new file mode 100644 index 00000000..c87447ea --- /dev/null +++ b/qahw/configure.ac @@ -0,0 +1,36 @@ +# -*- Autoconf -*- +# configure.ac -- Autoconf script for halinterface +# + +# Process this file with autoconf to produce a configure script. + +# Requires autoconf tool later than 2.61 +AC_PREREQ([2.69]) +# Initialize the audiohalwrapper-interface package version 1.0.0 +AC_INIT(audiohalwrapperinterface,1.0.0) +# Does not strictly follow GNU Coding standards +AM_INIT_AUTOMAKE([foreign]) +# Disables auto rebuilding of configure, Makefile.ins +#AM_MAINTAINER_MODE +# defines some macros variable to be included by source +AC_CONFIG_HEADERS([config.h]) +# defines some macros variable to be included by source +AC_CONFIG_MACRO_DIR([m4]) + +# Checks for programs. +AC_PROG_CC +AM_PROG_CC_C_O +AC_PROG_CXX +AC_PROG_LIBTOOL +AC_PROG_AWK +AC_PROG_CPP +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_MAKE_SET +PKG_PROG_PKG_CONFIG + +AC_CONFIG_FILES([ \ + Makefile + ]) + +AC_OUTPUT diff --git a/qahw/inc/qahw.h b/qahw/inc/qahw.h new file mode 100644 index 00000000..b7088ed5 --- /dev/null +++ b/qahw/inc/qahw.h @@ -0,0 +1,482 @@ +/* + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2011 The Android Open Source Project * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef QTI_AUDIO_QAHW_H +#define QTI_AUDIO_QAHW_H + +#include <stdint.h> +#include <strings.h> +#include <sys/cdefs.h> +#include <sys/types.h> +#include <sys/time.h> +#include <cutils/bitops.h> +#include <system/audio.h> +#include "qahw_defs.h" + +__BEGIN_DECLS +/* + * Helper macros for module implementors. + * + * The derived modules should provide convenience macros for supported + * versions so that implementations can explicitly specify module + * versions at definition time. + */ + +#define QAHW_MAKE_API_VERSION(maj,min) \ + ((((maj) & 0xff) << 8) | ((min) & 0xff)) + +/* First generation of audio devices had version hardcoded to 0. all devices with + * versions < 1.0 will be considered of first generation API. + */ +#define QAHW_MODULE_API_VERSION_0_0 QAHW_MAKE_API_VERSION(0, 0) + +/* Minimal QTI audio HAL version supported by the audio framework */ +#define QAHW_MODULE_API_VERSION_MIN QAHW_MODULE_API_VERSION_0_0 + +/** + * List of known audio HAL modules. This is the base name of the audio HAL + * library composed of the "audio." prefix, one of the base names below and + * a suffix specific to the device. + * e.g: audio.primary.goldfish.so or audio.a2dp.default.so + */ + +#define QAHW_MODULE_ID_PRIMARY "audio.primary" +#define QAHW_MODULE_ID_A2DP "audio.a2dp" +#define QAHW_MODULE_ID_USB "audio.usb" + +typedef void qahw_module_handle_t; +typedef void qahw_stream_handle_t; + +#ifdef __cplusplus +extern "C" +{ +#endif +/**************************************/ +/* Output stream specific APIs **/ + +/* + * 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_l(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 qahw_close_output_stream_l(qahw_stream_handle_t *out_handle); + +/* + * Return the sampling rate in Hz - eg. 44100. + */ +uint32_t qahw_out_get_sample_rate_l(const qahw_stream_handle_t *stream); + +/* + * use set_parameters with key QAHW_PARAMETER_STREAM_SAMPLING_RATE + */ +int qahw_out_set_sample_rate_l(qahw_stream_handle_t *stream, uint32_t rate); + +/* + * Return size of input/output buffer in bytes for this stream - eg. 4800. + * It should be a multiple of the frame size. See also get_input_buffer_size. + */ +size_t qahw_out_get_buffer_size_l(const qahw_stream_handle_t *stream); + +/* + * Return the channel mask - + * e.g. AUDIO_CHANNEL_OUT_STEREO or AUDIO_CHANNEL_IN_STEREO + */ +audio_channel_mask_t qahw_out_get_channels_l(const qahw_stream_handle_t *stream); + +/* + * Return the audio format - e.g. AUDIO_FORMAT_PCM_16_BIT + */ +audio_format_t qahw_out_get_format_l(const qahw_stream_handle_t *stream); + +/* + * Put the audio hardware input/output into standby mode. + * Driver should exit from standby mode at the next I/O operation. + * Returns 0 on success and <0 on failure. + */ +int qahw_out_standby_l(qahw_stream_handle_t *stream); + +/* + * 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_out_set_parameters_l(qahw_stream_handle_t *stream, const char*kv_pairs); + +/* + * Returns a pointer to a heap allocated string. The caller is responsible + * for freeing the memory for it using free(). + */ +char* qahw_out_get_parameters_l(const qahw_stream_handle_t *stream, + const char *keys); + +/* API to set playback stream specific config parameters */ +int qahw_out_set_param_data_l(qahw_stream_handle_t *out_handle, + qahw_param_id param_id, + qahw_param_payload *payload); + +/* API to get playback stream specific config parameters */ +int qahw_out_get_param_data_l(qahw_stream_handle_t *out_handle, + qahw_param_id param_id, + qahw_param_payload *payload); + +/* + * Return the audio hardware driver estimated latency in milliseconds. + */ +uint32_t qahw_out_get_latency_l(const qahw_stream_handle_t *stream); + +/* + * Use this method in situations where audio mixing is done in the + * hardware. This method serves as a direct interface with hardware, + * allowing you to directly set the volume as apposed to via the framework. + * This method might produce multiple PCM outputs or hardware accelerated + * codecs, such as MP3 or AAC. + */ +int qahw_out_set_volume_l(qahw_stream_handle_t *stream, float left, float right); + +/* + * Write audio buffer present in meta_data starting from offset + * along with timestamp to driver. Returns number of bytes + * written or a negative status_t. If at least one frame was written successfully + * prior to the error, it is suggested that the driver return that successful + * (short) byte count and then return an error in the subsequent call. + * timestamp is only sent driver is session has been opened with timestamp flag + * otherwise its ignored. + * + * If set_callback() has previously been called to enable non-blocking mode + * the write() is not allowed to block. It must write only the number of + * bytes that currently fit in the driver/hardware buffer and then return + * this byte count. If this is less than the requested write size the + * callback function must be called when more space is available in the + * driver/hardware buffer. + */ +ssize_t qahw_out_write_l(qahw_stream_handle_t *stream, + qahw_out_buffer_t *out_buf); + +/* + * return the number of audio frames written by the audio dsp to DAC since + * the output has exited standby + */ +int qahw_out_get_render_position_l(const qahw_stream_handle_t *stream, + uint32_t *dsp_frames); + +/* + * set the callback function for notifying completion of non-blocking + * write and drain. + * Calling this function implies that all future rite() and drain() + * must be non-blocking and use the callback to signal completion. + */ +int qahw_out_set_callback_l(qahw_stream_handle_t *stream, + qahw_stream_callback_t callback, + void *cookie); + +/* + * Notifies to the audio driver to stop playback however the queued buffers are + * retained by the hardware. Useful for implementing pause/resume. Empty implementation + * if not supported however should be implemented for hardware with non-trivial + * latency. In the pause state audio hardware could still be using power. User may + * consider calling suspend after a timeout. + * + * Implementation of this function is mandatory for offloaded playback. + */ +int qahw_out_pause_l(qahw_stream_handle_t *out_handle); + +/* + * Notifies to the audio driver to resume playback following a pause. + * Returns error if called without matching pause. + * + * Implementation of this function is mandatory for offloaded playback. + */ +int qahw_out_resume_l(qahw_stream_handle_t *out_handle); + +/* + * Requests notification when data buffered by the driver/hardware has + * been played. If set_callback() has previously been called to enable + * non-blocking mode, the drain() must not block, instead it should return + * quickly and completion of the drain is notified through the callback. + * If set_callback() has not been called, the drain() must block until + * completion. + * If type==AUDIO_DRAIN_ALL, the drain completes when all previously written + * data has been played. + * If type==AUDIO_DRAIN_EARLY_NOTIFY, the drain completes shortly before all + * data for the current track has played to allow time for the framework + * to perform a gapless track switch. + * + * Drain must return immediately on stop() and flush() call + * + * Implementation of this function is mandatory for offloaded playback. + */ +int qahw_out_drain_l(qahw_stream_handle_t *out_handle, qahw_drain_type_t type); + +/* + * Notifies to the audio driver to flush the queued data. Stream must already + * be paused before calling flush(). + * + * Implementation of this function is mandatory for offloaded playback. + */ +int qahw_out_flush_l(qahw_stream_handle_t *out_handle); + +/* + * Return a recent count of the number of audio frames presented to an external observer. + * This excludes frames which have been written but are still in the pipeline. + * The count is not reset to zero when output enters standby. + * Also returns the value of CLOCK_MONOTONIC as of this presentation count. + * The returned count is expected to be 'recent', + * but does not need to be the most recent possible value. + * However, the associated time should correspond to whatever count is returned. + * Example: assume that N+M frames have been presented, where M is a 'small' number. + * Then it is permissible to return N instead of N+M, + * and the timestamp should correspond to N rather than N+M. + * The terms 'recent' and 'small' are not defined. + * They reflect the quality of the implementation. + * + * 3.0 and higher only. + */ +int qahw_out_get_presentation_position_l(const qahw_stream_handle_t *out_handle, + uint64_t *frames, struct timespec *timestamp); + +/* Input stream specific APIs */ + +/* This method creates and opens the audio hardware input stream */ +int qahw_open_input_stream_l(qahw_module_handle_t *hw_module, + audio_io_handle_t handle, + audio_devices_t devices, + struct audio_config *config, + qahw_stream_handle_t **stream_in, + audio_input_flags_t flags, + const char *address, + audio_source_t source); + +int qahw_close_input_stream_l(qahw_stream_handle_t *in_handle); + +/* + * Return the sampling rate in Hz - eg. 44100. + */ +uint32_t qahw_in_get_sample_rate_l(const qahw_stream_handle_t *in_handle); + +/* + * currently unused - use set_parameters with key + * QAHW_PARAMETER_STREAM_SAMPLING_RATE + */ +int qahw_in_set_sample_rate_l(qahw_stream_handle_t *in_handle, uint32_t rate); + +/* + * Return size of input/output buffer in bytes for this stream - eg. 4800. + * It should be a multiple of the frame size. See also get_input_buffer_size. + */ +size_t qahw_in_get_buffer_size_l(const qahw_stream_handle_t *in_handle); + +/* + * Return the channel mask - + * e.g. AUDIO_CHANNEL_OUT_STEREO or AUDIO_CHANNEL_IN_STEREO + */ +audio_channel_mask_t qahw_in_get_channels_l(const qahw_stream_handle_t *in_handle); + +/* + * Return the audio format - e.g. AUDIO_FORMAT_PCM_16_BIT + */ +audio_format_t qahw_in_get_format_l(const qahw_stream_handle_t *in_handle); + +/* + * currently unused - use set_parameters with key + * QAHW_PARAMETER_STREAM_FORMAT + */ +int qahw_in_set_format_l(qahw_stream_handle_t *in_handle, audio_format_t format); + +/* + * Put the audio hardware input/output into standby mode. + * Driver should exit from standby mode at the next I/O operation. + * Returns 0 on success and <0 on failure. + */ +int qahw_in_standby_l(qahw_stream_handle_t *in_handle); + +/* + * 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_l(qahw_stream_handle_t *in_handle, const char *kv_pairs); + +/* + * 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_l(const qahw_stream_handle_t *in_handle, + const char *keys); +/* + * Read audio buffer in from audio driver. Returns number of bytes read, or a + * negative status_t. meta_data structure is filled buffer pointer, start + * offset and valid catpure timestamp (if session is opened with timetamp flag) + * and buffer. 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_l(qahw_stream_handle_t *in_handle, + qahw_in_buffer_t *in_buf); +/* + * 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_l(qahw_stream_handle_t *in_handle); + +/* + * 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_l(const qahw_stream_handle_t *in_handle, + int64_t *frames, int64_t *time); + +/* Module specific APIs */ + +/* convenience API for opening and closing an audio HAL module */ +qahw_module_handle_t *qahw_load_module_l(const char *hw_module_id); + +int qahw_unload_module_l(qahw_module_handle_t *hw_module); + +/* + * check to see if the audio hardware interface has been initialized. + * returns 0 on success, -ENODEV on failure. + */ +int qahw_init_check_l(const qahw_module_handle_t *hw_module); + +/* set the audio volume of a voice call. Range is between 0.0 and 1.0 */ +int qahw_set_voice_volume_l(qahw_module_handle_t *hw_module, float volume); + +/* + * 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_l(qahw_module_handle_t *hw_module, audio_mode_t mode); + +/* Mute/unmute mic during voice/voip/HFP call */ +int qahw_set_mic_mute_l(qahw_module_handle_t *hw_module, bool state); + +/* Get mute/unmute status of mic during voice call */ +int qahw_get_mic_mute_l(qahw_module_handle_t *hw_module, bool *state); + +/* set/get global audio parameters */ +int qahw_set_parameters_l(qahw_module_handle_t *hw_module, const char *kv_pairs); + +/* + * Returns a pointer to a heap allocated string. The caller is responsible + * for freeing the memory for it using free(). + */ +char* qahw_get_parameters_l(const qahw_module_handle_t *hw_module, + const char *keys); + +/* 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_l(const qahw_module_handle_t *hw_module, + const struct audio_config *config); + +/*returns current QTI HAL version */ +int qahw_get_version_l(); + +/* Api to implement get parameters based on keyword param_id + * and store data in payload. + */ +int qahw_get_param_data_l(const qahw_module_handle_t *hw_module, + qahw_param_id param_id, + qahw_param_payload *payload); + +/* Api to implement set parameters based on keyword param_id + * and data present in payload. + */ +int qahw_set_param_data_l(const qahw_module_handle_t *hw_module, + qahw_param_id param_id, + qahw_param_payload *payload); + +/* 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_l(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); + +/* Release an audio patch */ +int qahw_release_audio_patch_l(qahw_module_handle_t *hw_module, + audio_patch_handle_t handle); +/* 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_l(qahw_module_handle_t *hw_module, + struct audio_port *port); + +/* Set audio port configuration */ +int qahw_set_audio_port_config_l(qahw_module_handle_t *hw_module, + const struct audio_port_config *config); +#ifdef __cplusplus +} +#endif + +__END_DECLS + +#endif // QTI_AUDIO_QAHW_H diff --git a/qahw/inc/qahw_defs.h b/qahw/inc/qahw_defs.h new file mode 100644 index 00000000..c13a1a44 --- /dev/null +++ b/qahw/inc/qahw_defs.h @@ -0,0 +1,393 @@ +/* + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2011 The Android Open Source Project * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <sys/cdefs.h> +#include <stdint.h> + +#ifndef QTI_AUDIO_HAL_DEFS_H +#define QTI_AUDIO_HAL_DEFS_H + +__BEGIN_DECLS + +/**************************************/ + +/** + * standard audio parameters that the HAL may need to handle + */ + +/** + * audio device parameters + */ + +/* BT SCO Noise Reduction + Echo Cancellation parameters */ +#define QAHW_PARAMETER_KEY_BT_NREC "bt_headset_nrec" +#define QAHW_PARAMETER_VALUE_ON "on" +#define QAHW_PARAMETER_VALUE_OFF "off" + +/* TTY mode selection */ +#define QAHW_PARAMETER_KEY_TTY_MODE "tty_mode" +#define QAHW_PARAMETER_VALUE_TTY_OFF "tty_off" +#define QAHW_PARAMETER_VALUE_TTY_VCO "tty_vco" +#define QAHW_PARAMETER_VALUE_TTY_HCO "tty_hco" +#define QAHW_PARAMETER_VALUE_TTY_FULL "tty_full" + +/* Hearing Aid Compatibility - Telecoil (HAC-T) mode on/off + Strings must be in sync with CallFeaturesSetting.java */ +#define QAHW_PARAMETER_KEY_HAC "HACSetting" +#define QAHW_PARAMETER_VALUE_HAC_ON "ON" +#define QAHW_PARAMETER_VALUE_HAC_OFF "OFF" + +/* A2DP sink address set by framework */ +#define QAHW_PARAMETER_A2DP_SINK_ADDRESS "a2dp_sink_address" + +/* A2DP source address set by framework */ +#define QAHW_PARAMETER_A2DP_SOURCE_ADDRESS "a2dp_source_address" + +/* Screen state */ +#define QAHW_PARAMETER_KEY_SCREEN_STATE "screen_state" + +/* Bluetooth SCO wideband */ +#define QAHW_PARAMETER_KEY_BT_SCO_WB "bt_wbs" + +/* Get a new HW synchronization source identifier. + * Return a valid source (positive integer) or AUDIO_HW_SYNC_INVALID if an error occurs + * or no HW sync is available. */ +#define QAHW_PARAMETER_HW_AV_SYNC "hw_av_sync" + +/** + * audio stream parameters + */ + +#define QAHW_PARAMETER_STREAM_ROUTING "routing" /* audio_devices_t */ +#define QAHW_PARAMETER_STREAM_FORMAT "format" /* audio_format_t */ +#define QAHW_PARAMETER_STREAM_CHANNELS "channels" /* audio_channel_mask_t */ +#define QAHW_PARAMETER_STREAM_FRAME_COUNT "frame_count" /* size_t */ +#define QAHW_PARAMETER_STREAM_INPUT_SOURCE "input_source" /* audio_source_t */ +#define QAHW_PARAMETER_STREAM_SAMPLING_RATE "sampling_rate" /* uint32_t */ + +#define QAHW_PARAMETER_DEVICE_CONNECT "connect" /* audio_devices_t */ +#define QAHW_PARAMETER_DEVICE_DISCONNECT "disconnect" /* audio_devices_t */ + +/* Query supported formats. The response is a '|' separated list of strings from + * audio_format_t enum e.g: "sup_formats=AUDIO_FORMAT_PCM_16_BIT" */ +#define QAHW_PARAMETER_STREAM_SUP_FORMATS "sup_formats" + +/* Query supported channel masks. The response is a '|' separated list of + * strings from audio_channel_mask_t enum + * e.g: "sup_channels=AUDIO_CHANNEL_OUT_STEREO|AUDIO_CHANNEL_OUT_MONO" */ +#define QAHW_PARAMETER_STREAM_SUP_CHANNELS "sup_channels" + +/* Query supported sampling rates. The response is a '|' separated list of + * integer values e.g: "sup_sampling_rates=44100|48000" */ +#define QAHW_PARAMETER_STREAM_SUP_SAMPLING_RATES "sup_sampling_rates" + +/* Set the HW synchronization source for an output stream. */ +#define QAHW_PARAMETER_STREAM_HW_AV_SYNC "hw_av_sync" + +/* Enable mono audio playback if 1, else should be 0. */ +#define QAHW_PARAMETER_MONO_OUTPUT "mono_output" + +/** + * audio codec parameters + */ + +#define QAHW_OFFLOAD_CODEC_PARAMS "music_offload_codec_param" +#define QAHW_OFFLOAD_CODEC_BIT_PER_SAMPLE "music_offload_bit_per_sample" +#define QAHW_OFFLOAD_CODEC_BIT_RATE "music_offload_bit_rate" +#define QAHW_OFFLOAD_CODEC_AVG_BIT_RATE "music_offload_avg_bit_rate" +#define QAHW_OFFLOAD_CODEC_ID "music_offload_codec_id" +#define QAHW_OFFLOAD_CODEC_BLOCK_ALIGN "music_offload_block_align" +#define QAHW_OFFLOAD_CODEC_SAMPLE_RATE "music_offload_sample_rate" +#define QAHW_OFFLOAD_CODEC_ENCODE_OPTION "music_offload_encode_option" +#define QAHW_OFFLOAD_CODEC_NUM_CHANNEL "music_offload_num_channels" +#define QAHW_OFFLOAD_CODEC_DOWN_SAMPLING "music_offload_down_sampling" +#define QAHW_OFFLOAD_CODEC_DELAY_SAMPLES "delay_samples" +#define QAHW_OFFLOAD_CODEC_PADDING_SAMPLES "padding_samples" + +/** + * extended audio codec parameters + */ + +#define QAHW_OFFLOAD_CODEC_WMA_FORMAT_TAG "music_offload_wma_format_tag" +#define QAHW_OFFLOAD_CODEC_WMA_BLOCK_ALIGN "music_offload_wma_block_align" +#define QAHW_OFFLOAD_CODEC_WMA_BIT_PER_SAMPLE "music_offload_wma_bit_per_sample" +#define QAHW_OFFLOAD_CODEC_WMA_CHANNEL_MASK "music_offload_wma_channel_mask" +#define QAHW_OFFLOAD_CODEC_WMA_ENCODE_OPTION "music_offload_wma_encode_option" +#define QAHW_OFFLOAD_CODEC_WMA_ENCODE_OPTION1 "music_offload_wma_encode_option1" +#define QAHW_OFFLOAD_CODEC_WMA_ENCODE_OPTION2 "music_offload_wma_encode_option2" + +#define QAHW_OFFLOAD_CODEC_FLAC_MIN_BLK_SIZE "music_offload_flac_min_blk_size" +#define QAHW_OFFLOAD_CODEC_FLAC_MAX_BLK_SIZE "music_offload_flac_max_blk_size" +#define QAHW_OFFLOAD_CODEC_FLAC_MIN_FRAME_SIZE "music_offload_flac_min_frame_size" +#define QAHW_OFFLOAD_CODEC_FLAC_MAX_FRAME_SIZE "music_offload_flac_max_frame_size" + +#define QAHW_OFFLOAD_CODEC_ALAC_FRAME_LENGTH "music_offload_alac_frame_length" +#define QAHW_OFFLOAD_CODEC_ALAC_COMPATIBLE_VERSION "music_offload_alac_compatible_version" +#define QAHW_OFFLOAD_CODEC_ALAC_BIT_DEPTH "music_offload_alac_bit_depth" +#define QAHW_OFFLOAD_CODEC_ALAC_PB "music_offload_alac_pb" +#define QAHW_OFFLOAD_CODEC_ALAC_MB "music_offload_alac_mb" +#define QAHW_OFFLOAD_CODEC_ALAC_KB "music_offload_alac_kb" +#define QAHW_OFFLOAD_CODEC_ALAC_NUM_CHANNELS "music_offload_alac_num_channels" +#define QAHW_OFFLOAD_CODEC_ALAC_MAX_RUN "music_offload_alac_max_run" +#define QAHW_OFFLOAD_CODEC_ALAC_MAX_FRAME_BYTES "music_offload_alac_max_frame_bytes" +#define QAHW_OFFLOAD_CODEC_ALAC_AVG_BIT_RATE "music_offload_alac_avg_bit_rate" +#define QAHW_OFFLOAD_CODEC_ALAC_SAMPLING_RATE "music_offload_alac_sampling_rate" +#define QAHW_OFFLOAD_CODEC_ALAC_CHANNEL_LAYOUT_TAG "music_offload_alac_channel_layout_tag" + +#define QAHW_OFFLOAD_CODEC_APE_COMPATIBLE_VERSION "music_offload_ape_compatible_version" +#define QAHW_OFFLOAD_CODEC_APE_COMPRESSION_LEVEL "music_offload_ape_compression_level" +#define QAHW_OFFLOAD_CODEC_APE_FORMAT_FLAGS "music_offload_ape_format_flags" +#define QAHW_OFFLOAD_CODEC_APE_BLOCKS_PER_FRAME "music_offload_ape_blocks_per_frame" +#define QAHW_OFFLOAD_CODEC_APE_FINAL_FRAME_BLOCKS "music_offload_ape_final_frame_blocks" +#define QAHW_OFFLOAD_CODEC_APE_TOTAL_FRAMES "music_offload_ape_total_frames" +#define QAHW_OFFLOAD_CODEC_APE_BITS_PER_SAMPLE "music_offload_ape_bits_per_sample" +#define QAHW_OFFLOAD_CODEC_APE_NUM_CHANNELS "music_offload_ape_num_channels" +#define QAHW_OFFLOAD_CODEC_APE_SAMPLE_RATE "music_offload_ape_sample_rate" +#define QAHW_OFFLOAD_CODEC_APE_SEEK_TABLE_PRESENT "music_offload_seek_table_present" + +#define QAHW_OFFLOAD_CODEC_VORBIS_BITSTREAM_FMT "music_offload_vorbis_bitstream_fmt" + +/* Set or Query stream profile type */ +#define QAHW_PARAMETER_STREAM_PROFILE "audio_stream_profile" + +/* audio input flags for compress and timestamp mode. + * check other input flags defined in audio.h for conflicts + */ +#define QAHW_INPUT_FLAG_TIMESTAMP 0x80000000 +#define QAHW_INPUT_FLAG_COMPRESS 0x40000000 + +/* Query fm volume */ +#define QAHW_PARAMETER_KEY_FM_VOLUME "fm_volume" + +/* Query if a2dp is supported */ +#define QAHW_PARAMETER_KEY_HANDLE_A2DP_DEVICE "isA2dpDeviceSupported" + +#define MAX_OUT_CHANNELS 8 +#define MAX_INP_CHANNELS 8 + +#define QAHW_PCM_CHANNEL_FL 1 /* Front left channel. */ +#define QAHW_PCM_CHANNEL_FR 2 /* Front right channel. */ +#define QAHW_PCM_CHANNEL_FC 3 /* Front center channel. */ +#define QAHW_PCM_CHANNEL_LS 4 /* Left surround channel. */ +#define QAHW_PCM_CHANNEL_RS 5 /* Right surround channel. */ +#define QAHW_PCM_CHANNEL_LFE 6 /* Low frequency effect channel. */ +#define QAHW_PCM_CHANNEL_CS 7 /* Center surround channel; Rear center channel. */ +#define QAHW_PCM_CHANNEL_LB 8 /* Left back channel; Rear left channel. */ +#define QAHW_PCM_CHANNEL_RB 9 /* Right back channel; Rear right channel. */ +#define QAHW_PCM_CHANNEL_TS 10 /* Top surround channel. */ +#define QAHW_PCM_CHANNEL_CVH 11 /* Center vertical height channel. */ +#define QAHW_PCM_CHANNEL_MS 12 /* Mono surround channel. */ +#define QAHW_PCM_CHANNEL_FLC 13 /* Front left of center. */ +#define QAHW_PCM_CHANNEL_FRC 14 /* Front right of center. */ +#define QAHW_PCM_CHANNEL_RLC 15 /* Rear left of center. */ +#define QAHW_PCM_CHANNEL_RRC 16 /* Rear right of center. */ + +/* type of asynchronous write callback events. Mutually exclusive */ +typedef enum { + QAHW_STREAM_CBK_EVENT_WRITE_READY, /* non blocking write completed */ + QAHW_STREAM_CBK_EVENT_DRAIN_READY, /* drain completed */ + QAHW_STREAM_CBK_EVENT_ERROR, /* stream hit some error */ + + QAHW_STREAM_CBK_EVENT_ADSP = 0x100 /* callback event from ADSP PP, + * corresponding payload will be + * sent as is to the client + */ +} qahw_stream_callback_event_t; + +typedef int qahw_stream_callback_t(qahw_stream_callback_event_t event, + void *param, + void *cookie); + +/* type of drain requested to audio_stream_out->drain(). Mutually exclusive */ +typedef enum { + QAHW_DRAIN_ALL, /* drain() returns when all data has been played */ + QAHW_DRAIN_EARLY_NOTIFY /* drain() returns a short time before all data + from the current track has been played to + give time for gapless track switch */ +} qahw_drain_type_t; + +/* meta data flags */ +/*TBD: Extend this based on stb requirement*/ +typedef enum { + QAHW_META_DATA_FLAGS_NONE = 0, +} qahw_meta_data_flags_t; + +typedef struct { + const void *buffer; /* write buffer pointer */ + size_t bytes; /* size of buffer */ + size_t offset; /* offset in buffer from where valid byte starts */ + int64_t *timestamp; /* timestmap */ + qahw_meta_data_flags_t flags; /* meta data flags */ + uint32_t reserved[64]; /*reserved for future */ +} qahw_out_buffer_t; + +typedef struct { + void *buffer; /* read buffer pointer */ + size_t bytes; /* size of buffer */ + size_t offset; /* offset in buffer from where valid byte starts */ + int64_t *timestamp; /* timestmap */ + uint32_t reserved[64]; /*reserved for future */ +} qahw_in_buffer_t; + +#define MAX_SECTORS 8 + +struct qahw_source_tracking_param { + uint8_t vad[MAX_SECTORS]; + uint16_t doa_speech; + uint16_t doa_noise[3]; + uint8_t polar_activity[360]; +}; + +struct qahw_sound_focus_param { + uint16_t start_angle[MAX_SECTORS]; + uint8_t enable[MAX_SECTORS]; + uint16_t gain_step; +}; + +struct aptx_dec_bt_addr { + uint32_t nap; + uint32_t uap; + uint32_t lap; +}; + +struct qahw_aptx_dec_param { + struct aptx_dec_bt_addr bt_addr; +}; + +struct qahw_avt_device_drift_param { + /* Flag to indicate if resync is required on the client side for + * drift correction. Flag is set to TRUE for the first get_param response + * after device interface starts. This flag value can be used by client + * to identify if device interface restart has happened and if any + * re-sync is required at their end for drift correction. + */ + uint32_t resync_flag; + /* Accumulated drift value in microseconds. + * Positive drift value indicates AV timer is running faster than device. + * Negative drift value indicates AV timer is running slower than device. + */ + int32_t avt_device_drift_value; + /* 64-bit absolute timestamp of reference */ + uint64_t ref_timer_abs_ts; +}; + +/*use these for setting infine window.i.e free run mode */ +#define QAHW_MAX_RENDER_START_WINDOW 0x8000000000000000 +#define QAHW_MAX_RENDER_END_WINDOW 0x7FFFFFFFFFFFFFFF + +struct qahw_out_render_window_param { + uint64_t render_ws; /* render window start value microseconds*/ + uint64_t render_we; /* render window end value microseconds*/ +}; + +struct qahw_out_start_delay_param { + uint64_t start_delay; /* session start delay in microseconds*/ +}; + +struct qahw_out_enable_drift_correction { + bool enable; /* enable drift correction*/ +}; + +struct qahw_out_correct_drift { + /* + * adjust time in microseconds, a positive value + * to advance the clock or a negative value to + * delay the clock. + */ + int64_t adjust_time; +}; + +#define QAHW_MAX_ADSP_STREAM_CMD_PAYLOAD_LEN 512 + +typedef enum { + QAHW_STREAM_PP_EVENT = 0, + QAHW_STREAM_ENCDEC_EVENT = 1, +} qahw_event_id; + +/* payload format for HAL parameter + * QAHW_PARAM_ADSP_STREAM_CMD + */ +struct qahw_adsp_event { + qahw_event_id event_type; /* type of the event */ + uint32_t payload_length; /* length in bytes of the payload */ + void *payload; /* the actual payload */ +}; + +struct qahw_out_channel_map_param { + uint8_t channels; /* Input Channels */ + uint8_t channel_map[AUDIO_CHANNEL_COUNT_MAX]; /* Input Channel Map */ +}; + +struct qahw_device_cfg_param { + uint32_t sample_rate; + uint32_t channels; + uint32_t bit_width; + audio_format_t format; + audio_devices_t device; + uint8_t channel_map[AUDIO_CHANNEL_COUNT_MAX]; + uint16_t channel_allocation; +}; + +typedef struct qahw_mix_matrix_params { + uint16_t num_output_channels; + uint16_t num_input_channels; + uint8_t has_output_channel_map; + uint32_t output_channel_map[AUDIO_CHANNEL_COUNT_MAX]; + uint8_t has_input_channel_map; + uint32_t input_channel_map[AUDIO_CHANNEL_COUNT_MAX]; + uint8_t has_mixer_coeffs; + float mixer_coeffs[AUDIO_CHANNEL_COUNT_MAX][AUDIO_CHANNEL_COUNT_MAX]; +} qahw_mix_matrix_params_t; + +typedef union { + struct qahw_source_tracking_param st_params; + struct qahw_sound_focus_param sf_params; + struct qahw_aptx_dec_param aptx_params; + struct qahw_avt_device_drift_param drift_params; + struct qahw_out_render_window_param render_window_params; + struct qahw_out_start_delay_param start_delay; + struct qahw_out_enable_drift_correction drift_enable_param; + struct qahw_out_correct_drift drift_correction_param; + struct qahw_adsp_event adsp_event_params; + struct qahw_out_channel_map_param channel_map_params; + struct qahw_device_cfg_param device_cfg_params; + struct qahw_mix_matrix_params mix_matrix_params; +} qahw_param_payload; + +typedef enum { + QAHW_PARAM_SOURCE_TRACK, + QAHW_PARAM_SOUND_FOCUS, + QAHW_PARAM_APTX_DEC, + QAHW_PARAM_AVT_DEVICE_DRIFT, /* PARAM to query AV timer vs device drift */ + QAHW_PARAM_OUT_RENDER_WINDOW, /* PARAM to set render window */ + QAHW_PARAM_OUT_START_DELAY, /* PARAM to set session start delay*/ + /* enable adsp drift correction this must be called before out_write */ + QAHW_PARAM_OUT_ENABLE_DRIFT_CORRECTION, + /* param to set drift value to be adjusted by dsp */ + QAHW_PARAM_OUT_CORRECT_DRIFT, + QAHW_PARAM_ADSP_STREAM_CMD, + QAHW_PARAM_OUT_CHANNEL_MAP, /* PARAM to set i/p channel map */ + QAHW_PARAM_DEVICE_CONFIG, /* PARAM to set device config */ + QAHW_PARAM_OUT_MIX_MATRIX_PARAMS, + QAHW_PARAM_CH_MIX_MATRIX_PARAMS, +} qahw_param_id; + +__END_DECLS + +#endif // QTI_AUDIO_HAL_DEFS_H + diff --git a/qahw/inc/qahw_effect_api.h b/qahw/inc/qahw_effect_api.h new file mode 100644 index 00000000..de53cd3c --- /dev/null +++ b/qahw/inc/qahw_effect_api.h @@ -0,0 +1,845 @@ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef ANDROID_AUDIO_QAHW_EFFECT_H +#define ANDROID_AUDIO_QAHW_EFFECT_H + +#include <errno.h> +#include <stdint.h> +#include <strings.h> +#include <sys/cdefs.h> +#include <sys/types.h> + +#include <cutils/bitops.h> + +#include <system/audio.h> + +#include "qahw.h" + +__BEGIN_DECLS + +#define QAHW_EFFECT_API_VERSION_0_0 QAHW_MAKE_API_VERSION(0, 0) +#define QAHW_EFFECT_API_VERSION_MIN QAHW_EFFECT_API_VERSION_0_0 + +///////////////////////////////////////////////// +// Common Definitions +///////////////////////////////////////////////// + +// +//--- Effect descriptor structure qahw_effect_descriptor_t +// + +// Unique effect ID (can be generated from the following site: +// http://www.itu.int/ITU-T/asn1/uuid.html) +// This format is used for both "type" and "uuid" fields of the effect descriptor structure. +// - When used for effect type and the engine is implementing and effect corresponding to a standard +// OpenSL ES interface, this ID must be the one defined in OpenSLES_IID.h for that interface. +// - When used as uuid, it should be a unique UUID for this particular implementation. +typedef struct qahw_effect_uuid_s { + uint32_t timeLow; + uint16_t timeMid; + uint16_t timeHiAndVersion; + uint16_t clockSeq; + uint8_t node[6]; +} qahw_effect_uuid_t; + +// Maximum length of character strings in structures defines by this API. +#define QAHW_EFFECT_STRING_LEN_MAX 64 + +// NULL UUID definition (matches SL_IID_NULL_) +#define QAHW_EFFECT_UUID_INITIALIZER { 0xec7178ec, 0xe5e1, 0x4432, 0xa3f4, \ + { 0x46, 0x57, 0xe6, 0x79, 0x52, 0x10 } } +static const qahw_effect_uuid_t QAHW_EFFECT_UUID_NULL_ = QAHW_EFFECT_UUID_INITIALIZER; +static const qahw_effect_uuid_t * const QAHW_EFFECT_UUID_NULL = &QAHW_EFFECT_UUID_NULL_; +static const char * const QAHW_EFFECT_UUID_NULL_STR = "ec7178ec-e5e1-4432-a3f4-4657e6795210"; + + +// The effect descriptor contains necessary information to facilitate the enumeration of the effect +// engines present in a library. +typedef struct qahw_effect_descriptor_s { + qahw_effect_uuid_t type; // UUID of to the OpenSL ES interface implemented by this effect + qahw_effect_uuid_t uuid; // UUID for this particular implementation + uint32_t apiVersion; // Version of the effect control API implemented + uint32_t flags; // effect engine capabilities/requirements flags (see below) + uint16_t cpuLoad; // CPU load indication (see below) + uint16_t memoryUsage; // Data Memory usage (see below) + char name[QAHW_EFFECT_STRING_LEN_MAX]; // human readable effect name + char implementor[QAHW_EFFECT_STRING_LEN_MAX]; // human readable effect implementor name +} qahw_effect_descriptor_t; + +#define QAHW_EFFECT_MAKE_API_VERSION(M, m) (((M)<<16) | ((m) & 0xFFFF)) +#define QAHW_EFFECT_API_VERSION_MAJOR(v) ((v)>>16) +#define QAHW_EFFECT_API_VERSION_MINOR(v) ((m) & 0xFFFF) + + +///////////////////////////////////////////////// +// Effect control interface +///////////////////////////////////////////////// + +// Effect control interface version 2.0 +#define QAHW_EFFECT_CONTROL_API_VERSION QAHW_EFFECT_MAKE_API_VERSION(2,0) + +typedef void* qahw_effect_handle_t; + + +// Forward definition of type qahw_audio_buffer_t +typedef struct qahw_audio_buffer_s qahw_audio_buffer_t; + + +// +//--- Standardized command codes for command() function +// +enum qahw_effect_command_e { + QAHW_EFFECT_CMD_INIT, // initialize effect engine + QAHW_EFFECT_CMD_SET_CONFIG, // configure effect engine (see effect_config_t) + QAHW_EFFECT_CMD_RESET, // reset effect engine + QAHW_EFFECT_CMD_ENABLE, // enable effect process + QAHW_EFFECT_CMD_DISABLE, // disable effect process + QAHW_EFFECT_CMD_SET_PARAM, // set parameter immediately (see effect_param_t) + QAHW_EFFECT_CMD_SET_PARAM_DEFERRED, // set parameter deferred + QAHW_EFFECT_CMD_SET_PARAM_COMMIT, // commit previous set parameter deferred + QAHW_EFFECT_CMD_GET_PARAM, // get parameter + QAHW_EFFECT_CMD_SET_DEVICE, // set audio device (see audio.h, audio_devices_t) + QAHW_EFFECT_CMD_SET_VOLUME, // set volume + QAHW_EFFECT_CMD_SET_AUDIO_MODE, // set the audio mode (normal, ring, ...) + QAHW_EFFECT_CMD_SET_CONFIG_REVERSE, // configure effect engine reverse stream + // (see effect_config_t) + QAHW_EFFECT_CMD_SET_INPUT_DEVICE, // set capture device (see audio.h, audio_devices_t) + QAHW_EFFECT_CMD_GET_CONFIG, // read effect engine configuration + QAHW_EFFECT_CMD_GET_CONFIG_REVERSE, // read configure effect engine reverse stream + // configuration + QAHW_EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS, // get all supported configurations for + // a feature. + QAHW_EFFECT_CMD_GET_FEATURE_CONFIG, // get current feature configuration + QAHW_EFFECT_CMD_SET_FEATURE_CONFIG, // set current feature configuration + QAHW_EFFECT_CMD_SET_AUDIO_SOURCE, // set the audio source (see audio.h, audio_source_t) + QAHW_EFFECT_CMD_OFFLOAD, // set if effect thread is an offload one, + // send the ioHandle of the effect thread + QAHW_EFFECT_CMD_FIRST_PROPRIETARY = 0x10000 // first proprietary command code +}; + +//================================================================================================== +// command: QAHW_EFFECT_CMD_INIT +//-------------------------------------------------------------------------------------------------- +// description: +// Initialize effect engine: All configurations return to default +//-------------------------------------------------------------------------------------------------- +// command format: +// size: 0 +// data: N/A +//-------------------------------------------------------------------------------------------------- +// reply format: +// size: sizeof(int) +// data: status +//================================================================================================== +// command: QAHW_EFFECT_CMD_SET_CONFIG +//-------------------------------------------------------------------------------------------------- +// description: +// Apply new audio parameters configurations for input and output buffers +//-------------------------------------------------------------------------------------------------- +// command format: +// size: sizeof(effect_config_t) +// data: effect_config_t +//-------------------------------------------------------------------------------------------------- +// reply format: +// size: sizeof(int) +// data: status +//================================================================================================== +// command: QAHW_EFFECT_CMD_RESET +//-------------------------------------------------------------------------------------------------- +// description: +// Reset the effect engine. Keep configuration but resets state and buffer content +//-------------------------------------------------------------------------------------------------- +// command format: +// size: 0 +// data: N/A +//-------------------------------------------------------------------------------------------------- +// reply format: +// size: 0 +// data: N/A +//================================================================================================== +// command: QAHW_EFFECT_CMD_ENABLE +//-------------------------------------------------------------------------------------------------- +// description: +// Enable the process. Called by the framework before the first call to process() +//-------------------------------------------------------------------------------------------------- +// command format: +// size: 0 +// data: N/A +//-------------------------------------------------------------------------------------------------- +// reply format: +// size: sizeof(int) +// data: status +//================================================================================================== +// command: QAHW_EFFECT_CMD_DISABLE +//-------------------------------------------------------------------------------------------------- +// description: +// Disable the process. Called by the framework after the last call to process() +//-------------------------------------------------------------------------------------------------- +// command format: +// size: 0 +// data: N/A +//-------------------------------------------------------------------------------------------------- +// reply format: +// size: sizeof(int) +// data: status +//================================================================================================== +// command: QAHW_EFFECT_CMD_SET_PARAM +//-------------------------------------------------------------------------------------------------- +// description: +// Set a parameter and apply it immediately +//-------------------------------------------------------------------------------------------------- +// command format: +// size: sizeof(effect_param_t) + size of param and value +// data: effect_param_t + param + value. See effect_param_t definition below for value offset +//-------------------------------------------------------------------------------------------------- +// reply format: +// size: sizeof(int) +// data: status +//================================================================================================== +// command: QAHW_EFFECT_CMD_SET_PARAM_DEFERRED +//-------------------------------------------------------------------------------------------------- +// description: +// Set a parameter but apply it only when receiving QAHW_EFFECT_CMD_SET_PARAM_COMMIT command +//-------------------------------------------------------------------------------------------------- +// command format: +// size: sizeof(effect_param_t) + size of param and value +// data: effect_param_t + param + value. See effect_param_t definition below for value offset +//-------------------------------------------------------------------------------------------------- +// reply format: +// size: 0 +// data: N/A +//================================================================================================== +// command: QAHW_EFFECT_CMD_SET_PARAM_COMMIT +//-------------------------------------------------------------------------------------------------- +// description: +// Apply all previously received QAHW_EFFECT_CMD_SET_PARAM_DEFERRED commands +//-------------------------------------------------------------------------------------------------- +// command format: +// size: 0 +// data: N/A +//-------------------------------------------------------------------------------------------------- +// reply format: +// size: sizeof(int) +// data: status +//================================================================================================== +// command: QAHW_EFFECT_CMD_GET_PARAM +//-------------------------------------------------------------------------------------------------- +// description: +// Get a parameter value +//-------------------------------------------------------------------------------------------------- +// command format: +// size: sizeof(effect_param_t) + size of param +// data: effect_param_t + param +//-------------------------------------------------------------------------------------------------- +// reply format: +// size: sizeof(effect_param_t) + size of param and value +// data: effect_param_t + param + value. See effect_param_t definition below for value offset +//================================================================================================== +// command: QAHW_EFFECT_CMD_SET_DEVICE +//-------------------------------------------------------------------------------------------------- +// description: +// Set the rendering device the audio output path is connected to. See audio.h, audio_devices_t +// for device values. +// The effect implementation must set QAHW_EFFECT_FLAG_DEVICE_IND flag in its descriptor to +// receive this command when the device changes +//-------------------------------------------------------------------------------------------------- +// command format: +// size: sizeof(uint32_t) +// data: uint32_t +//-------------------------------------------------------------------------------------------------- +// reply format: +// size: 0 +// data: N/A +//================================================================================================== +// command: QAHW_EFFECT_CMD_SET_VOLUME +//-------------------------------------------------------------------------------------------------- +// description: +// Set and get volume. Used by audio framework to delegate volume control to effect engine. +// The effect implementation must set QAHW_EFFECT_FLAG_VOLUME_IND or QAHW_EFFECT_FLAG_VOLUME_CTRL +// flag in its descriptor to receive this command before every call to process() function +// If QAHW_EFFECT_FLAG_VOLUME_CTRL flag is set in the effect descriptor, the effect engine must +// return the volume that should be applied before the effect is processed. The overall volume +// (the volume actually applied by the effect engine multiplied by the returned value) should +// match the value indicated in the command. +//-------------------------------------------------------------------------------------------------- +// command format: +// size: n * sizeof(uint32_t) +// data: volume for each channel defined in effect_config_t for output buffer expressed in +// 8.24 fixed point format +//-------------------------------------------------------------------------------------------------- +// reply format: +// size: n * sizeof(uint32_t) / 0 +// data: - if QAHW_EFFECT_FLAG_VOLUME_CTRL is set in effect descriptor: +// volume for each channel defined in effect_config_t for output buffer expressed in +// 8.24 fixed point format +// - if QAHW_EFFECT_FLAG_VOLUME_CTRL is not set in effect descriptor: +// N/A +// It is legal to receive a null pointer as pReplyData in which case the effect framework has +// delegated volume control to another effect +//================================================================================================== +// command: QAHW_EFFECT_CMD_SET_AUDIO_MODE +//-------------------------------------------------------------------------------------------------- +// description: +// Set the audio mode. The effect implementation must set QAHW_EFFECT_FLAG_AUDIO_MODE_IND flag +// in its descriptor to receive this command when the audio mode changes. +//-------------------------------------------------------------------------------------------------- +// command format: +// size: sizeof(uint32_t) +// data: audio_mode_t +//-------------------------------------------------------------------------------------------------- +// reply format: +// size: 0 +// data: N/A +//================================================================================================== +// command: QAHW_EFFECT_CMD_SET_CONFIG_REVERSE +//-------------------------------------------------------------------------------------------------- +// description: +// Apply new audio parameters configurations for input and output buffers of reverse stream. +// An example of reverse stream is the echo reference supplied to an Acoustic Echo Canceler. +//-------------------------------------------------------------------------------------------------- +// command format: +// size: sizeof(effect_config_t) +// data: effect_config_t +//-------------------------------------------------------------------------------------------------- +// reply format: +// size: sizeof(int) +// data: status +//================================================================================================== +// command: QAHW_EFFECT_CMD_SET_INPUT_DEVICE +//-------------------------------------------------------------------------------------------------- +// description: +// Set the capture device the audio input path is connected to. See audio.h, audio_devices_t +// for device values. +// The effect implementation must set QAHW_EFFECT_FLAG_DEVICE_IND flag in its descriptor to +// receive this command when the device changes +//-------------------------------------------------------------------------------------------------- +// command format: +// size: sizeof(uint32_t) +// data: uint32_t +//-------------------------------------------------------------------------------------------------- +// reply format: +// size: 0 +// data: N/A +//================================================================================================== +// command: QAHW_EFFECT_CMD_GET_CONFIG +//-------------------------------------------------------------------------------------------------- +// description: +// Read audio parameters configurations for input and output buffers +//-------------------------------------------------------------------------------------------------- +// command format: +// size: 0 +// data: N/A +//-------------------------------------------------------------------------------------------------- +// reply format: +// size: sizeof(effect_config_t) +// data: effect_config_t +//================================================================================================== +// command: QAHW_EFFECT_CMD_GET_CONFIG_REVERSE +//-------------------------------------------------------------------------------------------------- +// description: +// Read audio parameters configurations for input and output buffers of reverse stream +//-------------------------------------------------------------------------------------------------- +// command format: +// size: 0 +// data: N/A +//-------------------------------------------------------------------------------------------------- +// reply format: +// size: sizeof(effect_config_t) +// data: effect_config_t +//================================================================================================== +// command: QAHW_EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS +//-------------------------------------------------------------------------------------------------- +// description: +// Queries for supported configurations for a particular feature (e.g. get the supported +// combinations of main and auxiliary channels for a noise suppressor). +// The command parameter is the feature identifier (See effect_feature_e for a list of defined +// features) followed by the maximum number of configuration descriptor to return. +// The reply is composed of: +// - status (uint32_t): +// - 0 if feature is supported +// - -ENOSYS if the feature is not supported, +// - -ENOMEM if the feature is supported but the total number of supported configurations +// exceeds the maximum number indicated by the caller. +// - total number of supported configurations (uint32_t) +// - an array of configuration descriptors. +// The actual number of descriptors returned must not exceed the maximum number indicated by +// the caller. +//-------------------------------------------------------------------------------------------------- +// command format: +// size: 2 x sizeof(uint32_t) +// data: effect_feature_e + maximum number of configurations to return +//-------------------------------------------------------------------------------------------------- +// reply format: +// size: 2 x sizeof(uint32_t) + n x sizeof (<config descriptor>) +// data: status + total number of configurations supported + array of n config descriptors +//================================================================================================== +// command: QAHW_EFFECT_CMD_GET_FEATURE_CONFIG +//-------------------------------------------------------------------------------------------------- +// description: +// Retrieves current configuration for a given feature. +// The reply status is: +// - 0 if feature is supported +// - -ENOSYS if the feature is not supported, +//-------------------------------------------------------------------------------------------------- +// command format: +// size: sizeof(uint32_t) +// data: effect_feature_e +//-------------------------------------------------------------------------------------------------- +// reply format: +// size: sizeof(uint32_t) + sizeof (<config descriptor>) +// data: status + config descriptor +//================================================================================================== +// command: QAHW_EFFECT_CMD_SET_FEATURE_CONFIG +//-------------------------------------------------------------------------------------------------- +// description: +// Sets current configuration for a given feature. +// The reply status is: +// - 0 if feature is supported +// - -ENOSYS if the feature is not supported, +// - -EINVAL if the configuration is invalid +//-------------------------------------------------------------------------------------------------- +// command format: +// size: sizeof(uint32_t) + sizeof (<config descriptor>) +// data: effect_feature_e + config descriptor +//-------------------------------------------------------------------------------------------------- +// reply format: +// size: sizeof(uint32_t) +// data: status +//================================================================================================== +// command: QAHW_EFFECT_CMD_SET_AUDIO_SOURCE +//-------------------------------------------------------------------------------------------------- +// description: +// Set the audio source the capture path is configured for (Camcorder, voice recognition...). +// See audio.h, audio_source_t for values. +//-------------------------------------------------------------------------------------------------- +// command format: +// size: sizeof(uint32_t) +// data: uint32_t +//-------------------------------------------------------------------------------------------------- +// reply format: +// size: 0 +// data: N/A +//================================================================================================== +// command: QAHW_EFFECT_CMD_OFFLOAD +//-------------------------------------------------------------------------------------------------- +// description: +// 1.indicate if the playback thread the effect is attached to is offloaded or not +// 2.update the io handle of the playback thread the effect is attached to +//-------------------------------------------------------------------------------------------------- +// command format: +// size: sizeof(effect_offload_param_t) +// data: effect_offload_param_t +//-------------------------------------------------------------------------------------------------- +// reply format: +// size: sizeof(uint32_t) +// data: uint32_t +//-------------------------------------------------------------------------------------------------- +// command: QAHW_EFFECT_CMD_FIRST_PROPRIETARY +//-------------------------------------------------------------------------------------------------- +// description: +// All proprietary effect commands must use command codes above this value. The size and format of +// command and response fields is free in this case +//================================================================================================== + + +// Audio buffer descriptor used by process(), bufferProvider() functions and buffer_config_t +// structure. Multi-channel audio is always interleaved. The channel order is from LSB to MSB with +// regard to the channel mask definition in audio.h, audio_channel_mask_t e.g : +// Stereo: left, right +// 5 point 1: front left, front right, front center, low frequency, back left, back right +// The buffer size is expressed in frame count, a frame being composed of samples for all +// channels at a given time. Frame size for unspecified format (AUDIO_FORMAT_OTHER) is 8 bit by +// definition +struct qahw_audio_buffer_s { + size_t frameCount; // number of frames in buffer + union { + void* raw; // raw pointer to start of buffer + int32_t* s32; // pointer to signed 32 bit data at start of buffer + int16_t* s16; // pointer to signed 16 bit data at start of buffer + uint8_t* u8; // pointer to unsigned 8 bit data at start of buffer + }; +}; + +// The buffer_provider_s structure contains functions that can be used +// by the effect engine process() function to query and release input +// or output audio buffer. +// The getBuffer() function is called to retrieve a buffer where data +// should read from or written to by process() function. +// The releaseBuffer() function MUST be called when the buffer retrieved +// with getBuffer() is not needed anymore. +// The process function should use the buffer provider mechanism to retrieve +// input or output buffer if the in_buffer or out_buffer passed as argument is NULL +// and the buffer configuration (buffer_config_t) given by the QAHW_EFFECT_CMD_SET_CONFIG +// command did not specify an audio buffer. + +typedef int32_t (* qahw_buffer_function_t)(void *cookie, qahw_audio_buffer_t *buffer); + +typedef struct qahw_buffer_provider_s { + qahw_buffer_function_t getBuffer; // retrieve next buffer + qahw_buffer_function_t releaseBuffer; // release used buffer + void *cookie; // for use by client of buffer provider functions +} qahw_buffer_provider_t; + + +// The qahw_buffer_config_s structure specifies the input or output audio format +// to be used by the effect engine. It is part of the effect_config_t +// structure that defines both input and output buffer configurations and is +// passed by the QAHW_EFFECT_CMD_SET_CONFIG or QAHW_EFFECT_CMD_SET_CONFIG_REVERSE command. +typedef struct qahw_buffer_config_s { + qahw_audio_buffer_t buffer; // buffer for use by process() function if not passed explicitly + uint32_t samplingRate; // sampling rate + uint32_t channels; // channel mask (see audio_channel_mask_t in audio.h) + qahw_buffer_provider_t bufferProvider; // buffer provider + uint8_t format; // Audio format (see audio_format_t in audio.h) + uint8_t accessMode; // read/write or accumulate in buffer (qahw_effect_buffer_access_e) + uint16_t mask; // indicates which of the above fields is valid +} qahw_buffer_config_t; + +// Values for "accessMode" field of buffer_config_t: +// overwrite, read only, accumulate (read/modify/write) +enum qahw_effect_buffer_access_e { + QAHW_EFFECT_BUFFER_ACCESS_WRITE, + QAHW_EFFECT_BUFFER_ACCESS_READ, + QAHW_EFFECT_BUFFER_ACCESS_ACCUMULATE + +}; + +// feature identifiers for QAHW_EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS command +enum qahw_effect_feature_e { + QAHW_EFFECT_FEATURE_AUX_CHANNELS, // supports auxiliary channels + // (e.g. dual mic noise suppressor) + QAHW_EFFECT_FEATURE_CNT +}; + +// QAHW_EFFECT_FEATURE_AUX_CHANNELS feature configuration descriptor. Describe a combination +// of main and auxiliary channels supported +typedef struct qahw_channel_config_s { + audio_channel_mask_t main_channels; // channel mask for main channels + audio_channel_mask_t aux_channels; // channel mask for auxiliary channels +} qahw_channel_config_t; + + +// Values for bit field "mask" in buffer_config_t. If a bit is set, the corresponding field +// in buffer_config_t must be taken into account when executing the QAHW_EFFECT_CMD_SET_CONFIG +// command +#define QAHW_EFFECT_CONFIG_BUFFER 0x0001 // buffer field must be taken into account +#define QAHW_EFFECT_CONFIG_SMP_RATE 0x0002 // samplingRate field must be taken into account +#define QAHW_EFFECT_CONFIG_CHANNELS 0x0004 // channels field must be taken into account +#define QAHW_EFFECT_CONFIG_FORMAT 0x0008 // format field must be taken into account +#define QAHW_EFFECT_CONFIG_ACC_MODE 0x0010 // accessMode field must be taken into account +#define QAHW_EFFECT_CONFIG_PROVIDER 0x0020 // bufferProvider field must be taken into account +#define QAHW_EFFECT_CONFIG_ALL (QAHW_EFFECT_CONFIG_BUFFER | QAHW_EFFECT_CONFIG_SMP_RATE | \ + QAHW_EFFECT_CONFIG_CHANNELS | QAHW_EFFECT_CONFIG_FORMAT | \ + QAHW_EFFECT_CONFIG_ACC_MODE | QAHW_EFFECT_CONFIG_PROVIDER) + + +// effect_config_s structure describes the format of the pCmdData argument of +// QAHW_EFFECT_CMD_SET_CONFIG command to configure audio parameters and buffers for effect +// engine input and output. +typedef struct qahw_effect_config_s { + qahw_buffer_config_t input_cfg; + qahw_buffer_config_t output_cfg; +} qahw_effect_config_t; + + +// effect_param_s structure describes the format of the pCmdData argument of +// QAHW_EFFECT_CMD_SET_PARAM command and pCmdData and pReplyData of QAHW_EFFECT_CMD_GET_PARAM +// command. psize and vsize represent the actual size of parameter and value. +// +// NOTE: the start of value field inside the data field is always on a 32 bit boundary: +// +// +-----------+ +// | status | sizeof(int) +// +-----------+ +// | psize | sizeof(int) +// +-----------+ +// | vsize | sizeof(int) +// +-----------+ +// | | | | +// ~ parameter ~ > psize | +// | | | > ((psize - 1)/sizeof(int) + 1) * sizeof(int) +// +-----------+ | +// | padding | | +// +-----------+ +// | | | +// ~ value ~ > vsize +// | | | +// +-----------+ + +typedef struct qahw_effect_param_s { + int32_t status; // Transaction status (unused for command, used for reply) + uint32_t psize; // Parameter size + uint32_t vsize; // Value size + char data[]; // Start of Parameter + Value data +} qahw_effect_param_t; + +// structure used by QAHW_EFFECT_CMD_OFFLOAD command +typedef struct qahw_effect_offload_param_s { + bool isOffload; // true if the playback thread the effect is attached to is offloaded + int ioHandle; // io handle of the playback thread the effect is attached to +} qahw_effect_offload_param_t; + + +///////////////////////////////////////////////// +// Effect library interface +///////////////////////////////////////////////// + +// Effect library interface version 3.0 +// Note that EffectsFactory.c only checks the major version component, so changes to the minor +// number can only be used for fully backwards compatible changes +#define QAHW_EFFECT_LIBRARY_API_VERSION QAHW_EFFECT_MAKE_API_VERSION(3, 0) + +typedef void* qahw_effect_lib_handle_t; + +//////////////////////////////////////////////////////////////////////////////// +// +// Function: qahw_effect_load_library +// +// Description: Loads an effect library +// +// Input: +// lib_name: Effect library name. +// +// Output: +// returned value: NULL if fails to load library. +// valid effect library handle +// +//////////////////////////////////////////////////////////////////////////////// +qahw_effect_lib_handle_t qahw_effect_load_library(const char *lib_name); + +//////////////////////////////////////////////////////////////////////////////// +// +// Function: qahw_effect_unload_library +// +// Description: Unload the audio effect library +// +// Input: +// handle: Effect library handle. +// +// Output: +// returned value: 0 successful operation. +// -EINVAL invalid effect library handle +// +//////////////////////////////////////////////////////////////////////////////// +int32_t qahw_effect_unload_library(qahw_effect_lib_handle_t handle); + +//////////////////////////////////////////////////////////////////////////////// +// +// Function: qahw_effect_create +// +// Description: Creates an effect engine of the specified implementation uuid and +// returns an effect control interface on this engine. The function will allocate the +// resources for an instance of the requested effect engine and return +// a handle on the effect control interface. +// +// Input: +// handle: handle on the effect library. +// uuid: pointer to the effect uuid. +// sessionId: audio session to which this effect instance will be attached. +// All effects created with the same session ID are connected in series +// and process the same signal stream. Knowing that two effects are part +// of the same effect chain can help the library implement some kind of +// optimizations. +// io_handle: identifies the output or input stream this effect is directed to in +// audio HAL. +// For future use especially with tunneled HW accelerated effects +// +// Input/Output: +// effect_handle: address where to return the effect interface handle. +// +// Output: +// returned value: 0 successful operation. +// -ENODEV library failed to initialize +// -EINVAL invalid pEffectUuid or effect_handle +// -ENOENT no effect with this uuid found +// *effect_handle: updated with the effect interface handle. +// +//////////////////////////////////////////////////////////////////////////////// +int32_t qahw_effect_create(qahw_effect_lib_handle_t handle, + const qahw_effect_uuid_t *uuid, + int32_t io_handle, + qahw_effect_handle_t *effect_handle); + +//////////////////////////////////////////////////////////////////////////////// +// +// Function: qahw_effect_release +// +// Description: Releases the effect engine whose handle is given as argument. +// All resources allocated to this particular instance of the effect are +// released. +// +// Input: +// handle: handle on the effect library. +// effect_handle: handle on the effect interface to be released. +// +// Output: +// returned value: 0 successful operation. +// -EINVAL invalid interface handle +// +//////////////////////////////////////////////////////////////////////////////// +int32_t qahw_effect_release(qahw_effect_lib_handle_t handle, + qahw_effect_handle_t effect_handle); + +//////////////////////////////////////////////////////////////////////////////// +// +// Function: qahw_effect_get_descriptor +// +// Description: Returns the descriptor of the effect engine which implementation UUID is +// given as argument. +// +// Input/Output: +// handle: handle on the effect library. +// uuid: pointer to the effect uuid. +// effect_desc: address where to return the effect descriptor. +// +// Output: +// returned value: 0 successful operation. +// -ENODEV library failed to initialize +// -EINVAL invalid effect_desc or uuid +// *effect_desc: updated with the effect descriptor. +// +//////////////////////////////////////////////////////////////////////////////// +int32_t qahw_effect_get_descriptor(qahw_effect_lib_handle_t handle, + const qahw_effect_uuid_t *uuid, + qahw_effect_descriptor_t *effect_desc); + +//////////////////////////////////////////////////////////////////////////////// +// +// Function: qahw_effect_get_version +// +// Description: Get version of IOT effect APIs. +// +// Output: +// returned value: version number +// +//////////////////////////////////////////////////////////////////////////////// +int32_t qahw_effect_get_version(); + +//////////////////////////////////////////////////////////////////////////////// +// +// Function: qahw_effect_process +// +// Description: Effect process function. Takes input samples as specified +// (count and location) in input buffer descriptor and output processed +// samples as specified in output buffer descriptor. If the buffer descriptor +// is not specified the function must use either the buffer or the +// buffer provider function installed by the QAHW_EFFECT_CMD_SET_CONFIG command. +// The effect framework will call the process() function after the QAHW_EFFECT_CMD_ENABLE +// command is received and until the QAHW_EFFECT_CMD_DISABLE is received. When the engine +// receives the QAHW_EFFECT_CMD_DISABLE command it should turn off the effect gracefully +// and when done indicate that it is OK to stop calling the process() function by +// returning the -ENODATA status. +// +// NOTE: the process() function implementation should be "real-time safe" that is +// it should not perform blocking calls: malloc/free, sleep, read/write/open/close, +// pthread_cond_wait/pthread_mutex_lock... +// +// Input: +// self: handle to the effect interface this function is called on. +// in_buffer: buffer descriptor indicating where to read samples to process. +// If NULL, use the configuration passed by QAHW_EFFECT_CMD_SET_CONFIG command. +// out_buffer: buffer descriptor indicating where to write processed samples. +// If NULL, use the configuration passed by QAHW_EFFECT_CMD_SET_CONFIG command. +// +// Output: +// returned value: 0 successful operation +// -ENODATA the engine has finished the disable phase and the framework +// can stop calling process() +// -EINVAL invalid interface handle or +// invalid input/output buffer description +//////////////////////////////////////////////////////////////////////////////// +int32_t qahw_effect_process(qahw_effect_handle_t self, + qahw_audio_buffer_t *in_buffer, + qahw_audio_buffer_t *out_buffer); +//////////////////////////////////////////////////////////////////////////////// +// +// Function: qahw_effect_command +// +// Description: Send a command and receive a response to/from effect engine. +// +// Input: +// self: handle to the effect interface this function is called on. +// cmd_code: command code: the command can be a standardized command defined in +// qahw_effect_command_e (see below) or a proprietary command. +// cmd_size: size of command in bytes +// cmd_data: pointer to command data +// reply_data: pointer to reply data +// +// Input/Output: +// reply_size: maximum size of reply data as input +// actual size of reply data as output +// +// Output: +// returned value: 0 successful operation +// -EINVAL invalid interface handle or +// invalid command/reply size or format according to +// command code +// The return code should be restricted to indicate problems related to this API +// specification. Status related to the execution of a particular command should be +// indicated as part of the reply field. +// +// *reply_data updated with command response +// +//////////////////////////////////////////////////////////////////////////////// +int32_t qahw_effect_command(qahw_effect_handle_t self, + uint32_t cmd_code, + uint32_t cmd_size, + void *cmd_data, + uint32_t *reply_size, + void *reply_data); + +//////////////////////////////////////////////////////////////////////////////// +// +// Function: qahw_effect_process_reverse +// +// Description: Process reverse stream function. This function is used to pass +// a reference stream to the effect engine. If the engine does not need a reference +// stream, this function pointer can be set to NULL. +// This function would typically implemented by an Echo Canceler. +// +// Input: +// self: handle to the effect interface this function is called on. +// in_buffer: buffer descriptor indicating where to read samples to process. +// If NULL, use the configuration passed by +// QAHW_EFFECT_CMD_SET_CONFIG_REVERSE command. +// +// out_buffer: buffer descriptor indicating where to write processed samples. +// If NULL, use the configuration passed by +// QAHW_EFFECT_CMD_SET_CONFIG_REVERSE command. +// If the buffer and buffer provider in the configuration received by +// QAHW_EFFECT_CMD_SET_CONFIG_REVERSE are also NULL, do not return modified reverse +// stream data +// +// Output: +// returned value: 0 successful operation +// -ENODATA the engine has finished the disable phase and the framework +// can stop calling process_reverse() +// -EINVAL invalid interface handle or +// invalid input/output buffer description +//////////////////////////////////////////////////////////////////////////////// +int32_t qahw_effect_process_reverse(qahw_effect_handle_t self, + qahw_audio_buffer_t *in_buffer, + qahw_audio_buffer_t *out_buffer); + + +__END_DECLS + +#endif // ANDROID_AUDIO_QAHW_EFFECT_H diff --git a/qahw/src/qahw.c b/qahw/src/qahw.c new file mode 100644 index 00000000..91fc5bfc --- /dev/null +++ b/qahw/src/qahw.c @@ -0,0 +1,1934 @@ +/* +* 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.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_l(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_l(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_l(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_l(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_l((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_l(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_l((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_l(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_l((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_l(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_l((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_l(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_l((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_l(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_l((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_l(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_l((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_l(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_l((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_l(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_l((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_l(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_l((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_l(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_l((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_l(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_l((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_l(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_l((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_l(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_l((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_l(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_l((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_l(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_l((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_l(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_l((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_l(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_l((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_l(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_l((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_l(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_l((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_l(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_l((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_l(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_l((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_l(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_l((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_l(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_l((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_l(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_l((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_l(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_l((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_l(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_l((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_l(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_l((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_l(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_l((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_l(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_l((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_l(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_l((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_l(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_l(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_l(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_l(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_l(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_l(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_l(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_l(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_l(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_l(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_l(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_l(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_l(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_l(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_l(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_l(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_l(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_l(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_l(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_l(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_l(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_l(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_l(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_l(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_l(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_l(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_l(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_l(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_l(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_l(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_l(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_l(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_l((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_l(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_l(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_l(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_l((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_l() { + return QAHW_MODULE_API_VERSION_CURRENT; +} + +/* convenience API for opening and closing an audio HAL module */ + +qahw_module_handle_t *qahw_load_module_l(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_l(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_l(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_l(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 diff --git a/qahw/src/qahw_effect.c b/qahw/src/qahw_effect.c new file mode 100644 index 00000000..cf7b3fd3 --- /dev/null +++ b/qahw/src/qahw_effect.c @@ -0,0 +1,321 @@ +/* +* Copyright (c) 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define LOG_TAG "qahw_effect" +//#define LOG_NDEBUG 0 +#define LOG_NDDEBUG 0 + +#include <cutils/list.h> +#include <dlfcn.h> +#include <utils/Log.h> +#include <hardware/audio.h> +#include <hardware/audio_effect.h> +#include <stdlib.h> + +#include "qahw_effect_api.h" + +// The current effect API version. +#define QAHW_EFFECT_API_VERSION_CURRENT QAHW_EFFECT_API_VERSION_0_0 +#define PATH_MAX 4096 + +typedef struct { + char lib_path[PATH_MAX]; + pthread_mutex_t lock; + uint32_t ref_count; + audio_effect_library_t *desc; + void *handle; + struct listnode lib_list; +} qahw_effect_lib_t; + +// list of loaded effect libraries +static struct listnode effect_libraries_list; +static int effect_libraries_count = 0; +static pthread_mutex_t effect_libraries_lock = PTHREAD_MUTEX_INITIALIZER; + +qahw_effect_lib_t *get_qahw_effect_lib_by_name(const char *lib_path) { + struct listnode *node = NULL; + qahw_effect_lib_t *effect_lib = NULL, *effect_lib_temp = NULL; + + if (lib_path == NULL) + goto exit; + + list_for_each(node, &effect_libraries_list) { + effect_lib_temp = node_to_item(node, qahw_effect_lib_t, lib_list); + if(!strncmp(lib_path, effect_lib_temp->lib_path, PATH_MAX)) { + effect_lib = effect_lib_temp; + break; + } + } +exit: + return effect_lib; +} + + +qahw_effect_lib_t *get_qahw_effect_lib_by_desc(qahw_effect_lib_handle_t handle) { + struct listnode *node = NULL; + qahw_effect_lib_t *effect_lib = NULL, *effect_lib_temp = NULL; + + if (handle == NULL) + goto exit; + + list_for_each(node, &effect_libraries_list) { + effect_lib_temp = node_to_item(node, qahw_effect_lib_t, lib_list); + if (effect_lib_temp->desc == (audio_effect_library_t *)handle) { + effect_lib = effect_lib_temp; + break; + } + } +exit: + return effect_lib; +} + + +qahw_effect_lib_handle_t qahw_effect_load_library(const char *lib_path) { + audio_effect_library_t *desc; + qahw_effect_lib_t *qahw_effect_lib; + void *handle; + + if (strlen(lib_path) >= PATH_MAX -1) { + ALOGE("%s: effect libraries path too long", __func__); + return NULL; + } + + /* return existing lib handler if already loaded */ + pthread_mutex_lock(&effect_libraries_lock); + if (effect_libraries_count > 0) { + qahw_effect_lib = get_qahw_effect_lib_by_name(lib_path); + if (qahw_effect_lib != NULL) { + desc = qahw_effect_lib->desc; + pthread_mutex_lock(&qahw_effect_lib->lock); + qahw_effect_lib->ref_count++; + pthread_mutex_unlock(&qahw_effect_lib->lock); + goto done; + } + } + + handle = dlopen(lib_path, RTLD_NOW); + if (handle == NULL) { + ALOGE("%s: failed to dlopen lib %s", __func__, lib_path); + goto error; + } + + desc = (audio_effect_library_t *)dlsym(handle, AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR); + if (desc == NULL) { + ALOGE("%s: could not find symbol %s", __func__, AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR); + goto error; + } + + if (AUDIO_EFFECT_LIBRARY_TAG != desc->tag) { + ALOGE("%s: bad tag %08x in lib info struct", __func__, desc->tag); + goto error; + } + + if (EFFECT_API_VERSION_MAJOR(desc->version) != + EFFECT_API_VERSION_MAJOR(EFFECT_LIBRARY_API_VERSION)) { + ALOGE("%s: bad lib version %08x", __func__, desc->version); + goto error; + } + + qahw_effect_lib = (qahw_effect_lib_t *)calloc(1, sizeof(qahw_effect_lib_t)); + if (qahw_effect_lib == NULL) { + ALOGE("%s: calloc failed", __func__); + goto error; + } + + if (!effect_libraries_count) + list_init(&effect_libraries_list); + effect_libraries_count++; + + /* init and load effect lib into global list */ + strlcpy(qahw_effect_lib->lib_path, lib_path, PATH_MAX); + pthread_mutex_init(&qahw_effect_lib->lock, (const pthread_mutexattr_t *) NULL); + qahw_effect_lib->ref_count = 1; + qahw_effect_lib->desc = desc; + qahw_effect_lib->handle = handle; + + list_add_tail(&effect_libraries_list, &qahw_effect_lib->lib_list); + +done: + pthread_mutex_unlock(&effect_libraries_lock); + return (qahw_effect_lib_handle_t)desc; + +error: + if (handle != NULL) + dlclose(handle); + + pthread_mutex_unlock(&effect_libraries_lock); + return NULL; +} + + +int32_t qahw_effect_unload_library(qahw_effect_lib_handle_t handle) { + qahw_effect_lib_t *qahw_effect_lib; + + pthread_mutex_lock(&effect_libraries_lock); + if (effect_libraries_count <= 0) { + ALOGW("%s: no valid libraries loaded", __func__); + pthread_mutex_unlock(&effect_libraries_lock); + return -EINVAL; + } + + qahw_effect_lib = get_qahw_effect_lib_by_desc(handle); + if (qahw_effect_lib == NULL) { + ALOGW("%s: effect lib handle(%p) not in loaded queue", __func__, (void *)handle); + pthread_mutex_unlock(&effect_libraries_lock); + return -EINVAL; + } + + pthread_mutex_lock(&qahw_effect_lib->lock); + qahw_effect_lib->ref_count--; + if (qahw_effect_lib->ref_count > 0) { + ALOGW("%s: skip unloading effect lib, ref count %d", __func__, qahw_effect_lib->ref_count); + pthread_mutex_unlock(&qahw_effect_lib->lock); + goto done; + } + + if (qahw_effect_lib->handle) + dlclose(qahw_effect_lib->handle); + effect_libraries_count--; + list_remove(&qahw_effect_lib->lib_list); + pthread_mutex_unlock(&qahw_effect_lib->lock); + pthread_mutex_destroy(&qahw_effect_lib->lock); + free(qahw_effect_lib); + +done: + pthread_mutex_unlock(&effect_libraries_lock); + return 0; +} + + +int32_t qahw_effect_create(qahw_effect_lib_handle_t handle, + const qahw_effect_uuid_t *uuid, + int32_t io_handle, + qahw_effect_handle_t *effect_handle) { + int32_t rc = -EINVAL; + audio_effect_library_t *desc = (audio_effect_library_t *)handle; + + if (desc != NULL) { + rc = desc->create_effect((const effect_uuid_t *)uuid, 0, io_handle, + (effect_handle_t *)effect_handle); + } + + return rc; +} + + +int32_t qahw_effect_release(qahw_effect_lib_handle_t handle, + qahw_effect_handle_t effect_handle) { + int32_t rc = -EINVAL; + audio_effect_library_t *desc = (audio_effect_library_t *)handle; + + if (desc != NULL) { + rc = desc->release_effect((effect_handle_t)effect_handle); + } + + return rc; +} + + +int32_t qahw_effect_get_descriptor(qahw_effect_lib_handle_t handle, + const qahw_effect_uuid_t *uuid, + qahw_effect_descriptor_t *effect_desc) { + int32_t rc = -EINVAL; + audio_effect_library_t *desc = (audio_effect_library_t *)handle; + + if (desc != NULL) { + rc = desc->get_descriptor((const effect_uuid_t *)uuid, (effect_descriptor_t *)effect_desc); + } + + return rc; +} + + +int32_t qahw_effect_get_version() { + return QAHW_EFFECT_API_VERSION_CURRENT; +} + + +int32_t qahw_effect_process(qahw_effect_handle_t self, + qahw_audio_buffer_t *in_buffer, + qahw_audio_buffer_t *out_buffer) { + int32_t rc = -EINVAL; + struct effect_interface_s *itfe; + + if (self) { + itfe = *((struct effect_interface_s **)self); + if (itfe) { + rc = itfe->process((effect_handle_t)self, + (audio_buffer_t *)in_buffer, + (audio_buffer_t *)out_buffer); + } + } + + return rc; +} + + +int32_t qahw_effect_command(qahw_effect_handle_t self, + uint32_t cmd_code, + uint32_t cmd_size, + void *cmd_data, + uint32_t *reply_size, + void *reply_data) { + int32_t rc = -EINVAL; + struct effect_interface_s *itfe; + + if (self) { + itfe = *((struct effect_interface_s **)self); + if (itfe) { + rc = itfe->command((effect_handle_t)self, cmd_code, cmd_size, + cmd_data, reply_size, reply_data); + } + } + + return rc; +} + + +int32_t qahw_effect_process_reverse(qahw_effect_handle_t self, + qahw_audio_buffer_t *in_buffer, + qahw_audio_buffer_t *out_buffer) { + int32_t rc = -EINVAL; + struct effect_interface_s *itfe; + + if (self) { + itfe = *((struct effect_interface_s **)self); + if (itfe) { + rc = itfe->process_reverse((effect_handle_t)self, + (audio_buffer_t *)in_buffer, + (audio_buffer_t *)out_buffer); + } + } + + return rc; +} + |