audio: qahw_api: Initial version of QTI audio HAL

-Initial version of QTI Audio HAL Wrapper.

Change-Id: Ia11c9d6b736cb5e9fa732601c3a3efd8d75ddd98
diff --git a/Android.mk b/Android.mk
index 273c9cb..42f202b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -16,6 +16,7 @@
 include $(MY_LOCAL_PATH)/visualizer/Android.mk
 include $(MY_LOCAL_PATH)/audiod/Android.mk
 include $(MY_LOCAL_PATH)/post_proc/Android.mk
+include $(MY_LOCAL_PATH)/qahw_api/Android.mk
 endif
 
 endif
diff --git a/qahw_api/Android.mk b/qahw_api/Android.mk
new file mode 100644
index 0000000..e35b67b
--- /dev/null
+++ b/qahw_api/Android.mk
@@ -0,0 +1,31 @@
+ifeq ($(strip $(BOARD_SUPPORTS_QAHW)),true)
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+libqahw-inc := $(LOCAL_PATH)/inc
+
+LOCAL_MODULE := libqahw
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_OWNER := qti
+LOCAL_C_INCLUDES   := $(libqahw-inc)
+
+LOCAL_SRC_FILES := \
+    src/qahw.c
+
+LOCAL_SHARED_LIBRARIES := \
+    liblog \
+    libcutils \
+    libhardware
+
+LOCAL_COPY_HEADERS_TO   := mm-audio/qahw_api/inc
+LOCAL_COPY_HEADERS      := inc/qahw_api.h
+LOCAL_COPY_HEADERS      += inc/qahw_defs.h
+
+LOCAL_PRELINK_MODULE    := false
+LOCAL_PROPRIETARY_MODULE := true
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif
diff --git a/qahw_api/inc/qahw_api.h b/qahw_api/inc/qahw_api.h
new file mode 100644
index 0000000..17f6f5f
--- /dev/null
+++ b/qahw_api/inc/qahw_api.h
@@ -0,0 +1,420 @@
+/*
+ * Copyright (c) 2016, 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_HAL_API_H
+#define QTI_AUDIO_HAL_API_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;
+
+/**************************************/
+/* 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(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(qahw_stream_handle_t *out_handle);
+
+
+/*
+ * Return the sampling rate in Hz - eg. 44100.
+ */
+uint32_t qahw_out_get_sample_rate(const qahw_stream_handle_t *stream);
+
+/*
+ *  use set_parameters with key QAHW_PARAMETER_STREAM_SAMPLING_RATE
+ */
+int qahw_out_set_sample_rate(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(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(const qahw_stream_handle_t *stream);
+
+/*
+ * Return the audio format - e.g. AUDIO_FORMAT_PCM_16_BIT
+ */
+audio_format_t qahw_out_get_format(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(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(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(const qahw_stream_handle_t *stream,
+                               const char *keys);
+
+/*
+ * Return the audio hardware driver estimated latency in milliseconds.
+ */
+uint32_t qahw_out_get_latency(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(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(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(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(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(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(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(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(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(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(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(qahw_stream_handle_t *in_handle);
+
+
+/*
+ * Return the sampling rate in Hz - eg. 44100.
+ */
+uint32_t qahw_in_get_sample_rate(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(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(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(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(const qahw_stream_handle_t *in_handle);
+
+/*
+ * currently unused - use set_parameters with key
+ *     QAHW_PARAMETER_STREAM_FORMAT
+ */
+int qahw_in_set_format(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(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(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(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(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(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(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(const char *hw_module_id);
+
+int qahw_unload_module(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(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(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(qahw_module_handle_t *hw_module, audio_mode_t mode);
+
+/* set/get global audio parameters */
+int qahw_set_parameters(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(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(const qahw_module_handle_t *hw_module,
+                                  const struct audio_config *config);
+
+/*returns current QTI HAL version */
+int qahw_get_version();
+
+__END_DECLS
+
+#endif  // QTI_AUDIO_HAL_API_H
diff --git a/qahw_api/inc/qahw_defs.h b/qahw_api/inc/qahw_defs.h
new file mode 100644
index 0000000..4441435
--- /dev/null
+++ b/qahw_api/inc/qahw_defs.h
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2016, 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"
+
+/* Query fm volume */
+#define QAHW_PARAMETER_KEY_FM_VOLUME "fm_volume"
+
+/* Query if a2dp  is supported */
+#define QAHW_PARAMETER_KEY_HANDLE_A2DP_DEVICE "isA2dpDeviceSupported"
+
+/* 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_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;
+
+__END_DECLS
+
+#endif  // QTI_AUDIO_HAL_DEFS_H
+
diff --git a/qahw_api/src/qahw.c b/qahw_api/src/qahw.c
new file mode 100644
index 0000000..06bcee1
--- /dev/null
+++ b/qahw_api/src/qahw.c
@@ -0,0 +1,1513 @@
+/*
+* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above
+*       copyright notice, this list of conditions and the following
+*       disclaimer in the documentation and/or other materials provided
+*       with the distribution.
+*     * Neither the name of The Linux Foundation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define LOG_TAG "qahw"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <utils/Log.h>
+#include <stdlib.h>
+#include <cutils/list.h>
+
+#include <hardware/audio.h>
+#include "qahw_api.h"
+
+#define NO_ERROR 0
+#define MAX_MODULE_NAME_LENGTH  100
+
+/*
+ * The current HAL API version.
+ */
+#define QAHW_MODULE_API_VERSION_CURRENT QAHW_MODULE_API_VERSION_0_0
+
+typedef struct {
+    audio_hw_device_t *audio_device;
+    char module_name[MAX_MODULE_NAME_LENGTH];
+    struct listnode module_list;
+    struct listnode in_list;
+    struct listnode out_list;
+    pthread_mutex_t lock;
+    uint32_t ref_count;
+} qahw_module_t;
+
+typedef struct {
+    qahw_module_t *module;
+    struct listnode module_list;
+    pthread_mutex_t lock;
+} qahw_module_instances_t;
+
+typedef struct {
+    audio_stream_out_t *stream;
+    qahw_module_t *module;
+    struct listnode list;
+    pthread_mutex_t lock;
+} qahw_stream_out_t;
+
+typedef struct {
+    audio_stream_in_t *stream;
+    qahw_module_t *module;
+    struct listnode list;
+    pthread_mutex_t lock;
+} qahw_stream_in_t;
+
+typedef enum {
+    STREAM_DIR_IN,
+    STREAM_DIR_OUT,
+} qahw_stream_direction_t;
+
+static struct listnode qahw_module_list;
+static int qahw_list_count;
+static pthread_mutex_t qahw_module_init_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/** Start of internal functions */
+/******************************************************************************/
+
+/* call this function without anylock held */
+static bool is_valid_qahw_stream(void *qahw_stream,
+                                 qahw_stream_direction_t dir)
+{
+
+    int is_valid = false;
+    struct listnode *module_node = NULL;
+    struct listnode *stream_node = NULL;
+    struct listnode *list_node = NULL;
+    void  *stream = NULL;
+    qahw_module_t *qahw_module = NULL;
+
+    if (qahw_stream == NULL) {
+        ALOGE("%s:: Invalid stream", __func__);
+        goto exit;
+    }
+
+    if ((dir != STREAM_DIR_OUT) && (dir != STREAM_DIR_IN)) {
+        ALOGE("%s:: Invalid stream direction %d", __func__, dir);
+        goto exit;
+    }
+
+    /* go through all the modules and check for valid stream */
+    pthread_mutex_lock(&qahw_module_init_lock);
+    list_for_each(module_node, &qahw_module_list) {
+        qahw_module = node_to_item(module_node, qahw_module_t, module_list);
+        pthread_mutex_lock(&qahw_module->lock);
+        if(dir == STREAM_DIR_OUT)
+            list_node = &qahw_module->out_list;
+        else
+            list_node = &qahw_module->in_list;
+        list_for_each(stream_node, list_node) {
+            if(dir == STREAM_DIR_OUT)
+                stream = (void *)node_to_item(stream_node,
+                                              qahw_stream_out_t,
+                                              list);
+            else
+                stream = (void *)node_to_item(stream_node,
+                                              qahw_stream_in_t,
+                                              list);
+            if(stream == qahw_stream) {
+                is_valid = true;
+                break;
+            }
+        }
+        pthread_mutex_unlock(&qahw_module->lock);
+        if(is_valid)
+            break;
+    }
+    pthread_mutex_unlock(&qahw_module_init_lock);
+
+exit:
+    return is_valid;
+}
+
+/* call this fucntion with ahw_module_init_lock held*/
+static qahw_module_t* get_qahw_module_by_ptr(qahw_module_t *qahw_module)
+{
+    struct listnode *node = NULL;
+    qahw_module_t *module = NULL, *module_temp = NULL;
+
+    if (qahw_module == NULL)
+        goto exit;
+
+    list_for_each(node, &qahw_module_list) {
+        module_temp = node_to_item(node, qahw_module_t, module_list);
+        if (module_temp == qahw_module) {
+            module = module_temp;
+            break;
+        }
+    }
+exit:
+    return module;
+}
+
+/* call this function with qahw_module_init_lock held*/
+static qahw_module_t* get_qahw_module_by_name(const char *qahw_name)
+{
+    struct listnode *node = NULL;
+    qahw_module_t *module = NULL, *module_temp = NULL;
+
+    if (qahw_name == NULL)
+        goto exit;
+
+    list_for_each(node, &qahw_module_list) {
+        module_temp = node_to_item(node, qahw_module_t, module_list);
+        if(!strncmp(qahw_name, module_temp->module_name, MAX_MODULE_NAME_LENGTH)) {
+            module = module_temp;
+            break;
+        }
+    }
+exit:
+    return module;
+}
+/* End of of internal functions */
+
+/*
+ * Return the sampling rate in Hz - eg. 44100.
+ */
+uint32_t qahw_out_get_sample_rate(const qahw_stream_handle_t *out_handle)
+{
+    uint32_t rate = 0;
+    qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+    audio_stream_out_t *out = NULL;
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+        ALOGV("%s::Invalid out handle %p", __func__, out_handle);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_stream_out->lock);
+    out = qahw_stream_out->stream;
+    if (out->common.get_sample_rate)
+        rate = out->common.get_sample_rate(&out->common);
+    else
+        ALOGW("%s not supported", __func__);
+    pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+     return rate;
+}
+
+/*
+ * currently unused - use set_parameters with key
+ *    AUDIO_PARAMETER_STREAM_SAMPLING_RATE
+ */
+int qahw_out_set_sample_rate(qahw_stream_handle_t *out_handle, uint32_t rate)
+{
+    int32_t rc = -EINVAL;
+    qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+    audio_stream_out_t *out = NULL;
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+        ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+        goto exit;
+    }
+    pthread_mutex_lock(&qahw_stream_out->lock);
+    out = qahw_stream_out->stream;
+    if (out->common.set_sample_rate) {
+        rc = out->common.set_sample_rate(&out->common, rate);
+    } else {
+        rc = -ENOSYS;
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_stream_out->lock);
+exit:
+    return rc;
+}
+
+size_t qahw_out_get_buffer_size(const qahw_stream_handle_t *out_handle)
+{
+    size_t buf_size = 0;
+    qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+    audio_stream_out_t *out = NULL;
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+        ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+        goto exit;
+    }
+    pthread_mutex_lock(&qahw_stream_out->lock);
+    out = qahw_stream_out->stream;
+    if (out->common.get_buffer_size) {
+        buf_size = out->common.get_buffer_size(&out->common);
+    } else {
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+    return buf_size;
+}
+
+audio_channel_mask_t qahw_out_get_channels(const qahw_stream_handle_t *out_handle)
+{
+    audio_channel_mask_t ch_mask = 0;
+    qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+    audio_stream_out_t *out = NULL;
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+        ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+        goto exit;
+    }
+    pthread_mutex_lock(&qahw_stream_out->lock);
+    out = qahw_stream_out->stream;
+    if (out->common.get_channels) {
+        ch_mask = out->common.get_channels(&out->common);
+    } else {
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+    return ch_mask;
+}
+
+audio_format_t qahw_out_get_format(const qahw_stream_handle_t *out_handle)
+{
+    audio_format_t format = AUDIO_FORMAT_INVALID;
+    qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+    audio_stream_out_t *out = NULL;
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+        ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+        goto exit;
+    }
+    pthread_mutex_lock(&qahw_stream_out->lock);
+    out = qahw_stream_out->stream;
+    if (out->common.get_format) {
+        format = out->common.get_format(&out->common);
+    } else {
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+    return format;
+}
+
+int qahw_out_standby(qahw_stream_handle_t *out_handle)
+{
+    int32_t rc = -EINVAL;
+    qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+    audio_stream_out_t *out = NULL;
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+        ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_stream_out->lock);
+    out = qahw_stream_out->stream;
+    if (out->common.standby) {
+        rc = out->common.standby(&out->common);
+    } else {
+        rc = -ENOSYS;
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+    return rc;
+}
+
+int qahw_out_set_parameters(qahw_stream_handle_t *out_handle, const char *kv_pairs)
+{
+    int rc = NO_ERROR;
+    qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+    audio_stream_out_t *out = NULL;
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+        ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+        rc = -EINVAL;
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_stream_out->lock);
+    out = qahw_stream_out->stream;
+    if (out->common.set_parameters) {
+        rc = out->common.set_parameters(&out->common, kv_pairs);
+    } else {
+        rc = -ENOSYS;
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+    return rc;
+}
+
+char *qahw_out_get_parameters(const qahw_stream_handle_t *out_handle,
+                               const char *keys)
+{
+    char *str_param = NULL;
+    qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+    audio_stream_out_t *out = NULL;
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+        ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_stream_out->lock);
+    out = qahw_stream_out->stream;
+    if (out->common.get_parameters) {
+        str_param = out->common.get_parameters(&out->common, keys);
+    } else {
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+    return str_param;
+}
+
+uint32_t qahw_out_get_latency(const qahw_stream_handle_t *out_handle)
+{
+    uint32_t latency = 0;
+    qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+    audio_stream_out_t *out = NULL;
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+        ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_stream_out->lock);
+    out = qahw_stream_out->stream;
+    if (out->get_latency) {
+        latency = out->get_latency(out);
+    } else {
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+    return latency;
+}
+
+int qahw_out_set_volume(qahw_stream_handle_t *out_handle, float left, float right)
+{
+    int rc = -EINVAL;
+    qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+    audio_stream_out_t *out = NULL;
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+        ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_stream_out->lock);
+    out = qahw_stream_out->stream;
+    if (out->set_volume) {
+        rc = out->set_volume(out, left, right);
+    } else {
+        rc = -ENOSYS;
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+   return rc;
+}
+
+ssize_t qahw_out_write(qahw_stream_handle_t *out_handle,
+        qahw_out_buffer_t *out_buf)
+{
+    int rc = -EINVAL;
+    qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+    audio_stream_out_t *out = NULL;
+
+    if ((out_buf == NULL) || (out_buf->buffer == NULL)) {
+        ALOGE("%s::Invalid meta data %p", __func__, out_buf);
+        goto exit;
+    }
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+        ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+        goto exit;
+    }
+
+    /*TBD:: validate other meta data parameters */
+
+    pthread_mutex_lock(&qahw_stream_out->lock);
+    out = qahw_stream_out->stream;
+    if (out->write) {
+        rc = out->write(out, out_buf->buffer, out_buf->bytes);
+    } else {
+        rc = -ENOSYS;
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_stream_out->lock);
+exit:
+    return rc;
+}
+
+int qahw_out_get_render_position(const qahw_stream_handle_t *out_handle,
+                                 uint32_t *dsp_frames)
+{
+    int rc = -EINVAL;
+    qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+    audio_stream_out_t *out = NULL;
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+        ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_stream_out->lock);
+    out = qahw_stream_out->stream;
+    if (out->get_render_position) {
+        rc = out->get_render_position(out, dsp_frames);
+    } else {
+        rc = -ENOSYS;
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_stream_out->lock);
+exit:
+    return rc;
+}
+
+int qahw_out_set_callback(qahw_stream_handle_t *out_handle,
+                          qahw_stream_callback_t callback,
+                          void *cookie)
+{
+    /*TBD:load hal func pointer and call */
+    int rc = -EINVAL;
+    qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+    audio_stream_out_t *out = NULL;
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+        ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_stream_out->lock);
+    out = qahw_stream_out->stream;
+    if (out->set_callback) {
+        rc = out->set_callback(out, (stream_callback_t)callback, cookie);
+    } else {
+        rc = -ENOSYS;
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+    return rc;
+}
+
+int qahw_out_pause(qahw_stream_handle_t *out_handle)
+{
+    /*TBD:load hal func pointer and call */
+    int rc = -EINVAL;
+    qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+    audio_stream_out_t *out = NULL;
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+        ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_stream_out->lock);
+    out = qahw_stream_out->stream;
+    if (out->pause) {
+        rc = out->pause(out);
+    } else {
+        rc = -ENOSYS;
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+    return rc;
+}
+
+int qahw_out_resume(qahw_stream_handle_t *out_handle)
+{
+    /*TBD:load hal func pointer and call */
+    int rc = -EINVAL;
+    qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+    audio_stream_out_t *out = NULL;
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+        ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_stream_out->lock);
+    out = qahw_stream_out->stream;
+    if (out->resume) {
+        rc = out->resume(out);
+    } else {
+        rc = -ENOSYS;
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+    return rc;
+}
+
+int qahw_out_drain(qahw_stream_handle_t *out_handle, qahw_drain_type_t type )
+{
+    /*TBD:load hal func pointer and call */
+    int rc = -EINVAL;
+    qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+    audio_stream_out_t *out = NULL;
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+        ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_stream_out->lock);
+    out = qahw_stream_out->stream;
+    if (out->drain) {
+        rc = out->drain(out,(audio_drain_type_t)type);
+    } else {
+        rc = -ENOSYS;
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+    return rc;
+}
+
+int qahw_out_flush(qahw_stream_handle_t *out_handle)
+{
+    int rc = -EINVAL;
+    qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+    audio_stream_out_t *out = NULL;
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+        ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_stream_out->lock);
+    out = qahw_stream_out->stream;
+    if (out->flush) {
+        rc = out->flush(out);
+    } else {
+        rc = -ENOSYS;
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+    return rc;
+}
+
+int qahw_out_get_presentation_position(const qahw_stream_handle_t *out_handle,
+                           uint64_t *frames, struct timespec *timestamp)
+{
+    int rc = -EINVAL;
+    qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+    audio_stream_out_t *out = NULL;
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+        ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_stream_out->lock);
+    out = qahw_stream_out->stream;
+    if (out->get_presentation_position) {
+        rc = out->get_presentation_position(out, frames, timestamp);
+    } else {
+        rc = -ENOSYS;
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+    return rc;
+}
+
+/* Input stream specific APIs */
+uint32_t qahw_in_get_sample_rate(const qahw_stream_handle_t *in_handle)
+{
+    uint32_t rate = 0;
+    qahw_stream_in_t *qahw_stream_in = (qahw_stream_in_t *)in_handle;
+    audio_stream_in_t *in = NULL;
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_in, STREAM_DIR_IN)) {
+        ALOGV("%s::Invalid in handle %p", __func__, in_handle);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_stream_in->lock);
+    in = qahw_stream_in->stream;
+    if (in->common.get_sample_rate) {
+        rate = in->common.get_sample_rate(&in->common);
+    } else {
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_stream_in->lock);
+
+exit:
+    return rate;
+}
+
+/*
+ * currently unused - use set_parameters with key
+ *    AUDIO_PARAMETER_STREAM_SAMPLING_RATE
+ */
+int qahw_in_set_sample_rate(qahw_stream_handle_t *in_handle, uint32_t rate)
+{
+    int rc = -EINVAL;
+    qahw_stream_in_t *qahw_stream_in = (qahw_stream_in_t *)in_handle;
+    audio_stream_in_t *in = NULL;
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_in, STREAM_DIR_IN)) {
+        ALOGV("%s::Invalid in handle %p", __func__, in_handle);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_stream_in->lock);
+    in = qahw_stream_in->stream;
+    if (in->common.set_sample_rate) {
+        rc = in->common.set_sample_rate(&in->common, rate);
+    } else {
+        rc = -ENOSYS;
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_stream_in->lock);
+
+exit:
+    return rc;
+}
+
+size_t qahw_in_get_buffer_size(const qahw_stream_handle_t *in_handle)
+{
+    size_t buf_size = 0;
+    qahw_stream_in_t *qahw_stream_in = (qahw_stream_in_t *)in_handle;
+    audio_stream_in_t *in = NULL;
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_in, STREAM_DIR_IN)) {
+        ALOGV("%s::Invalid in handle %p", __func__, in_handle);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_stream_in->lock);
+    in = qahw_stream_in->stream;
+    if (in->common.get_sample_rate) {
+        buf_size = in->common.get_buffer_size(&in->common);
+    } else {
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_stream_in->lock);
+
+exit:
+    return buf_size;
+}
+
+
+audio_channel_mask_t qahw_in_get_channels(const qahw_stream_handle_t *in_handle)
+{
+    audio_channel_mask_t ch_mask = 0;;
+    qahw_stream_in_t *qahw_stream_in = (qahw_stream_in_t *)in_handle;
+    audio_stream_in_t *in = NULL;
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_in, STREAM_DIR_IN)) {
+        ALOGV("%s::Invalid in handle %p", __func__, in_handle);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_stream_in->lock);
+    in = qahw_stream_in->stream;
+    if (in->common.get_channels) {
+        ch_mask = in->common.get_channels(&in->common);
+    } else {
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_stream_in->lock);
+
+exit:
+    return ch_mask;
+}
+
+audio_format_t qahw_in_get_format(const qahw_stream_handle_t *in_handle)
+{
+    audio_format_t format = AUDIO_FORMAT_INVALID;
+    qahw_stream_in_t *qahw_stream_in = (qahw_stream_in_t *)in_handle;
+    audio_stream_in_t *in = NULL;
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_in, STREAM_DIR_IN)) {
+        ALOGV("%s::Invalid in handle %p", __func__, in_handle);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_stream_in->lock);
+    in = qahw_stream_in->stream;
+    if (in->common.get_format) {
+        format = in->common.get_format(&in->common);
+    } else {
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_stream_in->lock);
+
+exit:
+    return format;
+}
+
+/*
+ * currently unused - use set_parameters with key
+ *     AUDIO_PARAMETER_STREAM_FORMAT
+ */
+int qahw_in_set_format(qahw_stream_handle_t *in_handle, audio_format_t format)
+{
+    int rc = -EINVAL;
+    qahw_stream_in_t *qahw_stream_in = (qahw_stream_in_t *)in_handle;
+    audio_stream_in_t *in = NULL;
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_in, STREAM_DIR_IN)) {
+        ALOGV("%s::Invalid in handle %p", __func__, in_handle);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_stream_in->lock);
+    in = qahw_stream_in->stream;
+    if (in->common.set_format) {
+        rc = in->common.set_format(&in->common, format);
+    } else {
+        rc = -ENOSYS;
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_stream_in->lock);
+
+exit:
+    return rc;
+}
+
+int qahw_in_standby(qahw_stream_handle_t *in_handle)
+{
+    int rc = -EINVAL;
+    qahw_stream_in_t *qahw_stream_in = (qahw_stream_in_t *)in_handle;
+    audio_stream_in_t *in = NULL;
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_in, STREAM_DIR_IN)) {
+        ALOGV("%s::Invalid in handle %p", __func__, in_handle);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_stream_in->lock);
+    in = qahw_stream_in->stream;
+    if (in->common.standby) {
+        rc = in->common.standby(&in->common);
+    } else {
+        rc = -ENOSYS;
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_stream_in->lock);
+
+exit:
+    return rc;
+}
+
+/*
+ * set/get audio stream parameters. The function accepts a list of
+ * parameter key value pairs in the form: key1=value1;key2=value2;...
+ *
+ * Some keys are reserved for standard parameters (See AudioParameter class)
+ *
+ * If the implementation does not accept a parameter change while
+ * the output is active but the parameter is acceptable otherwise, it must
+ * return -ENOSYS.
+ *
+ * The audio flinger will put the stream in standby and then change the
+ * parameter value.
+ */
+int qahw_in_set_parameters(qahw_stream_handle_t *in_handle, const char *kv_pairs)
+{
+    int rc = -EINVAL;
+    qahw_stream_in_t *qahw_stream_in = (qahw_stream_in_t *)in_handle;
+    audio_stream_in_t *in = NULL;
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_in, STREAM_DIR_IN)) {
+        ALOGV("%s::Invalid in handle %p", __func__, in_handle);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_stream_in->lock);
+    in = qahw_stream_in->stream;
+    if (in->common.set_parameters) {
+        rc = in->common.set_parameters(&in->common, kv_pairs);
+    } else {
+        rc = -ENOSYS;
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_stream_in->lock);
+exit:
+    return rc;
+}
+
+/*
+ * Returns a pointer to a heap allocated string. The caller is responsible
+ * for freeing the memory for it using free().
+ */
+char * qahw_in_get_parameters(const qahw_stream_handle_t *in_handle,
+                              const char *keys)
+{
+    char *str_param = NULL;
+    qahw_stream_in_t *qahw_stream_in = (qahw_stream_in_t *)in_handle;
+    audio_stream_in_t *in = NULL;
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_in, STREAM_DIR_IN)) {
+        ALOGV("%s::Invalid in handle %p", __func__, in_handle);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_stream_in->lock);
+    in = qahw_stream_in->stream;
+    if (in->common.get_parameters) {
+        str_param = in->common.get_parameters(&in->common, keys);
+    } else {
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_stream_in->lock);
+
+exit:
+    return str_param;
+}
+
+/*
+ * Read audio buffer in from audio driver. Returns number of bytes read, or a
+ *  negative status_t. If at least one frame was read prior to the error,
+ *  read should return that byte count and then return an error in the subsequent call.
+ */
+ssize_t qahw_in_read(qahw_stream_handle_t *in_handle,
+                     qahw_in_buffer_t *in_buf)
+{
+    int rc = -EINVAL;
+    qahw_stream_in_t *qahw_stream_in = (qahw_stream_in_t *)in_handle;
+    audio_stream_in_t *in = NULL;
+
+    if ((in_buf == NULL) || (in_buf->buffer == NULL)) {
+        ALOGE("%s::Invalid meta data %p", __func__, in_buf);
+        goto exit;
+    }
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_in, STREAM_DIR_IN)) {
+        ALOGV("%s::Invalid in handle %p", __func__, in_handle);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_stream_in->lock);
+    in = qahw_stream_in->stream;
+    /*TBD:: call HAL timestamp read API*/
+    if (in->read) {
+        rc = in->read(in, in_buf->buffer, in_buf->bytes);
+        in_buf->offset = 0;
+    } else {
+        rc = -ENOSYS;
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_stream_in->lock);
+
+exit:
+    return rc;
+}
+
+/*
+ * Return the amount of input frames lost in the audio driver since the
+ * last call of this function.
+ * Audio driver is expected to reset the value to 0 and restart counting
+ * upon returning the current value by this function call.
+ * Such loss typically occurs when the user space process is blocked
+ * longer than the capacity of audio driver buffers.
+ *
+ * Unit: the number of input audio frames
+ */
+uint32_t qahw_in_get_input_frames_lost(qahw_stream_handle_t *in_handle)
+{
+    uint32_t rc = 0;
+    qahw_stream_in_t *qahw_stream_in = (qahw_stream_in_t *)in_handle;
+    audio_stream_in_t *in = NULL;
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_in, STREAM_DIR_IN)) {
+        ALOGV("%s::Invalid in handle %p", __func__, in_handle);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_stream_in->lock);
+    in = qahw_stream_in->stream;
+    if (in->get_input_frames_lost) {
+        rc = in->get_input_frames_lost(in);
+    } else {
+        rc = -ENOSYS;
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_stream_in->lock);
+
+exit:
+    return rc;
+}
+
+/*
+ * Return a recent count of the number of audio frames received and
+ * the clock time associated with that frame count.
+ *
+ * frames is the total frame count received. This should be as early in
+ *     the capture pipeline as possible. In general,
+ *     frames should be non-negative and should not go "backwards".
+ *
+ * time is the clock MONOTONIC time when frames was measured. In general,
+ *     time should be a positive quantity and should not go "backwards".
+ *
+ * The status returned is 0 on success, -ENOSYS if the device is not
+ * ready/available, or -EINVAL if the arguments are null or otherwise invalid.
+ */
+int qahw_in_get_capture_position(const qahw_stream_handle_t *in_handle __unused,
+                                 int64_t *frames __unused, int64_t *time __unused)
+{
+    /*TBD:: do we need this*/
+    return -ENOSYS;
+}
+
+/*
+ * check to see if the audio hardware interface has been initialized.
+ * returns 0 on success, -ENODEV on failure.
+ */
+int qahw_init_check(const qahw_module_handle_t *hw_module)
+{
+    int rc = -EINVAL;
+    qahw_module_t *qahw_module = (qahw_module_t *)hw_module;
+    qahw_module_t *qahw_module_temp;
+
+    pthread_mutex_lock(&qahw_module_init_lock);
+    qahw_module_temp = get_qahw_module_by_ptr(qahw_module);
+    pthread_mutex_unlock(&qahw_module_init_lock);
+    if (qahw_module_temp == NULL) {
+        ALOGE("%s:: invalid hw module %p", __func__, qahw_module);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_module->lock);
+    if (qahw_module->audio_device->init_check) {
+        rc = qahw_module->audio_device->init_check(qahw_module->audio_device);
+    } else {
+        rc = -ENOSYS;
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_module->lock);
+
+exit:
+    return rc;
+}
+/* set the audio volume of a voice call. Range is between 0.0 and 1.0 */
+int qahw_set_voice_volume(qahw_module_handle_t *hw_module, float volume)
+{
+    int rc = -EINVAL;
+    qahw_module_t *qahw_module = (qahw_module_t *)hw_module;
+    qahw_module_t *qahw_module_temp;
+
+    pthread_mutex_lock(&qahw_module_init_lock);
+    qahw_module_temp = get_qahw_module_by_ptr(qahw_module);
+    pthread_mutex_unlock(&qahw_module_init_lock);
+    if (qahw_module_temp == NULL) {
+        ALOGE("%s:: invalid hw module %p", __func__, qahw_module);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_module->lock);
+    if (qahw_module->audio_device->set_voice_volume) {
+        rc = qahw_module->audio_device->set_voice_volume(qahw_module->audio_device,
+                                                         volume);
+    } else {
+        rc = -ENOSYS;
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_module->lock);
+
+exit:
+    return rc;
+}
+
+/*
+ * set_mode is called when the audio mode changes. AUDIO_MODE_NORMAL mode
+ * is for standard audio playback, AUDIO_MODE_RINGTONE when a ringtone is
+ * playing, and AUDIO_MODE_IN_CALL when a call is in progress.
+ */
+int qahw_set_mode(qahw_module_handle_t *hw_module, audio_mode_t mode)
+{
+    int rc = -EINVAL;
+    qahw_module_t *qahw_module = (qahw_module_t *)hw_module;
+    qahw_module_t *qahw_module_temp;
+
+    pthread_mutex_lock(&qahw_module_init_lock);
+    qahw_module_temp = get_qahw_module_by_ptr(qahw_module);
+    pthread_mutex_unlock(&qahw_module_init_lock);
+    if (qahw_module_temp == NULL) {
+        ALOGE("%s:: invalid hw module %p", __func__, qahw_module);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_module->lock);
+    if (qahw_module->audio_device->set_mode) {
+        rc = qahw_module->audio_device->set_mode(qahw_module->audio_device,
+                                                 mode);
+    } else {
+        rc = -ENOSYS;
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_module->lock);
+
+exit:
+    return rc;
+}
+
+/* set/get global audio parameters */
+int qahw_set_parameters(qahw_module_handle_t *hw_module, const char *kv_pairs)
+{
+    int rc = -EINVAL;
+    qahw_module_t *qahw_module = (qahw_module_t *)hw_module;
+    qahw_module_t *qahw_module_temp;
+    audio_hw_device_t *audio_device;
+
+    pthread_mutex_lock(&qahw_module_init_lock);
+    qahw_module_temp = get_qahw_module_by_ptr(qahw_module);
+    pthread_mutex_unlock(&qahw_module_init_lock);
+    if (qahw_module_temp == NULL) {
+        ALOGE("%s:: invalid hw module %p", __func__, qahw_module);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_module->lock);
+    audio_device = qahw_module->audio_device;
+    if (qahw_module->audio_device->set_parameters) {
+        rc = audio_device->set_parameters(qahw_module->audio_device, kv_pairs);
+    } else {
+        rc = -ENOSYS;
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_module->lock);
+
+exit:
+    return rc;
+}
+
+/*
+ * Returns a pointer to a heap allocated string. The caller is responsible
+ * for freeing the memory for it using free().
+ */
+char * qahw_get_parameters(const qahw_module_handle_t *hw_module,
+                           const char *keys)
+{
+    char *str_param = NULL;
+    qahw_module_t *qahw_module = (qahw_module_t *)hw_module;
+    qahw_module_t *qahw_module_temp;
+    audio_hw_device_t *audio_device;
+
+    pthread_mutex_lock(&qahw_module_init_lock);
+    qahw_module_temp = get_qahw_module_by_ptr(qahw_module);
+    pthread_mutex_unlock(&qahw_module_init_lock);
+    if (qahw_module_temp == NULL) {
+        ALOGE("%s:: invalid hw module %p", __func__, qahw_module);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_module->lock);
+    audio_device = qahw_module->audio_device;
+    if (qahw_module->audio_device->get_parameters) {
+        str_param = audio_device->get_parameters(qahw_module->audio_device, keys);
+    } else {
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_module->lock);
+
+exit:
+    return str_param;
+}
+
+/* Returns audio input buffer size according to parameters passed or
+ * 0 if one of the parameters is not supported.
+ * See also get_buffer_size which is for a particular stream.
+ */
+size_t qahw_get_input_buffer_size(const qahw_module_handle_t *hw_module,
+                                  const struct audio_config *config)
+{
+    size_t rc = 0;
+    qahw_module_t *qahw_module = (qahw_module_t *)hw_module;
+    qahw_module_t *qahw_module_temp;
+    audio_hw_device_t *audio_device;
+
+    pthread_mutex_lock(&qahw_module_init_lock);
+    qahw_module_temp = get_qahw_module_by_ptr(qahw_module);
+    pthread_mutex_unlock(&qahw_module_init_lock);
+    if (qahw_module_temp == NULL) {
+        ALOGE("%s:: invalid hw module %p", __func__, qahw_module);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_module->lock);
+    audio_device = qahw_module->audio_device;
+    if (qahw_module->audio_device->get_input_buffer_size) {
+        rc = audio_device->get_input_buffer_size(qahw_module->audio_device,
+                                                 config);
+    } else {
+        rc = -ENOSYS;
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_module->lock);
+
+exit:
+    return rc;
+}
+
+/*
+ * This method creates and opens the audio hardware output stream.
+ * The "address" parameter qualifies the "devices" audio device type if needed.
+ * The format format depends on the device type:
+ * - Bluetooth devices use the MAC address of the device in the form "00:11:22:AA:BB:CC"
+ * - USB devices use the ALSA card and device numbers in the form  "card=X;device=Y"
+ * - Other devices may use a number or any other string.
+ */
+int qahw_open_output_stream(qahw_module_handle_t *hw_module,
+                            audio_io_handle_t handle,
+                            audio_devices_t devices,
+                            audio_output_flags_t flags,
+                            struct audio_config *config,
+                            qahw_stream_handle_t **out_handle,
+                            const char *address)
+{
+    int rc = -EINVAL;
+    qahw_module_t *qahw_module = (qahw_module_t *)hw_module;
+    qahw_module_t *qahw_module_temp = NULL;
+    audio_hw_device_t *audio_device = NULL;
+    qahw_stream_out_t *qahw_stream_out = NULL;
+
+    pthread_mutex_lock(&qahw_module_init_lock);
+    qahw_module_temp = get_qahw_module_by_ptr(qahw_module);
+    pthread_mutex_unlock(&qahw_module_init_lock);
+    if (qahw_module_temp == NULL) {
+        ALOGE("%s:: invalid hw module %p", __func__, qahw_module);
+        return rc;
+    }
+
+    pthread_mutex_lock(&qahw_module->lock);
+    audio_device = qahw_module->audio_device;
+    qahw_stream_out = (qahw_stream_out_t *)calloc(1, sizeof(qahw_stream_out_t));
+    if (qahw_stream_out == NULL) {
+        ALOGE("%s:: calloc failed for out stream_out_t",__func__);
+        rc = -ENOMEM;
+        goto exit;
+    }
+
+    rc = audio_device->open_output_stream(audio_device,
+                                          handle,
+                                          devices,
+                                          flags,
+                                          config,
+                                          &qahw_stream_out->stream,
+                                          address);
+    if (rc) {
+        ALOGE("%s::open output stream failed %d",__func__, rc);
+        free(qahw_stream_out);
+    } else {
+        qahw_stream_out->module = hw_module;
+        *out_handle = (void *)qahw_stream_out;
+        pthread_mutex_init(&qahw_stream_out->lock, (const pthread_mutexattr_t *)NULL);
+        list_add_tail(&qahw_module->out_list, &qahw_stream_out->list);
+    }
+
+exit:
+    pthread_mutex_unlock(&qahw_module->lock);
+    return rc;
+}
+
+int qahw_close_output_stream(qahw_stream_handle_t *out_handle)
+{
+
+    int rc = 0;
+    qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+    qahw_module_t *qahw_module = NULL;
+    audio_hw_device_t *audio_device = NULL;
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+        ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+        rc = -EINVAL;
+        goto exit;
+    }
+
+    ALOGV("%s::calling device close_output_stream %p", __func__, out_handle);
+    pthread_mutex_lock(&qahw_stream_out->lock);
+    qahw_module = qahw_stream_out->module;
+    audio_device = qahw_module->audio_device;
+    audio_device->close_output_stream(audio_device,
+                                      qahw_stream_out->stream);
+
+    pthread_mutex_lock(&qahw_module->lock);
+    list_remove(&qahw_stream_out->list);
+    pthread_mutex_unlock(&qahw_module->lock);
+
+    pthread_mutex_unlock(&qahw_stream_out->lock);
+
+    pthread_mutex_destroy(&qahw_stream_out->lock);
+    free(qahw_stream_out);
+
+exit:
+    return rc;
+}
+
+/* This method creates and opens the audio hardware input stream */
+int qahw_open_input_stream(qahw_module_handle_t *hw_module,
+                           audio_io_handle_t handle,
+                           audio_devices_t devices,
+                           struct audio_config *config,
+                           qahw_stream_handle_t **in_handle,
+                           audio_input_flags_t flags,
+                           const char *address,
+                           audio_source_t source)
+{
+    int rc = -EINVAL;
+    qahw_module_t *qahw_module = (qahw_module_t *)hw_module;
+    qahw_module_t *qahw_module_temp = NULL;
+    audio_hw_device_t *audio_device = NULL;
+    qahw_stream_in_t *qahw_stream_in = NULL;
+
+    pthread_mutex_lock(&qahw_module_init_lock);
+    qahw_module_temp = get_qahw_module_by_ptr(qahw_module);
+    pthread_mutex_unlock(&qahw_module_init_lock);
+    if (qahw_module_temp == NULL) {
+        ALOGE("%s:: invalid hw module %p", __func__, qahw_module);
+        return rc;
+    }
+
+    pthread_mutex_lock(&qahw_module->lock);
+    audio_device = qahw_module->audio_device;
+    qahw_stream_in = (qahw_stream_in_t *)calloc(1, sizeof(qahw_stream_in_t));
+    if (qahw_stream_in == NULL) {
+        ALOGE("%s:: calloc failed for in stream_in_t",__func__);
+        rc = -ENOMEM;
+        goto exit;
+    }
+
+    rc = audio_device->open_input_stream(audio_device,
+                                          handle,
+                                          devices,
+                                          config,
+                                          &qahw_stream_in->stream,
+                                          flags,
+                                          address,
+                                          source);
+    if (rc) {
+        ALOGE("%s::open input stream failed %d",__func__, rc);
+        free(qahw_stream_in);
+    } else {
+        qahw_stream_in->module = hw_module;
+        *in_handle = (void *)qahw_stream_in;
+        pthread_mutex_init(&qahw_stream_in->lock, (const pthread_mutexattr_t *)NULL);
+        list_add_tail(&qahw_module->in_list, &qahw_stream_in->list);
+    }
+
+exit:
+    pthread_mutex_unlock(&qahw_module->lock);
+    return rc;
+}
+
+int qahw_close_input_stream(qahw_stream_handle_t *in_handle)
+{
+    int rc = 0;
+    qahw_stream_in_t *qahw_stream_in = (qahw_stream_in_t *)in_handle;
+    qahw_module_t *qahw_module = NULL;
+    audio_hw_device_t *audio_device = NULL;
+
+    if (!is_valid_qahw_stream((void *)qahw_stream_in, STREAM_DIR_IN)) {
+        ALOGV("%s::Invalid in handle %p", __func__, in_handle);
+        rc = -EINVAL;
+        goto exit;
+    }
+
+    ALOGV("%s:: calling device close_input_stream %p", __func__, in_handle);
+    pthread_mutex_lock(&qahw_stream_in->lock);
+    qahw_module = qahw_stream_in->module;
+    audio_device = qahw_module->audio_device;
+    audio_device->close_input_stream(audio_device,
+                                     qahw_stream_in->stream);
+
+    pthread_mutex_lock(&qahw_module->lock);
+    list_remove(&qahw_stream_in->list);
+    pthread_mutex_unlock(&qahw_module->lock);
+
+    pthread_mutex_unlock(&qahw_stream_in->lock);
+
+    pthread_mutex_destroy(&qahw_stream_in->lock);
+    free(qahw_stream_in);
+
+exit:
+    return rc;
+}
+
+/*returns current QTI HAL verison */
+int qahw_get_version() {
+    return QAHW_MODULE_API_VERSION_CURRENT;
+}
+
+/* convenience API for opening and closing an audio HAL module */
+
+qahw_module_handle_t *qahw_load_module(const char *hw_module_id)
+{
+    int rc = -EINVAL;
+    qahw_module_handle_t *qahw_mod_handle = NULL;
+    qahw_module_t *qahw_module = NULL;
+    char *ahal_name = NULL;
+    const hw_module_t* module = NULL;
+    audio_hw_device_t* audio_device = NULL;
+
+    if (hw_module_id == NULL) {
+        ALOGE("%s::module id is NULL",__func__);
+        goto exit;
+    }
+
+    if (!strcmp(hw_module_id, QAHW_MODULE_ID_PRIMARY)) {
+        ahal_name = "primary";
+    } else if (!strcmp(hw_module_id, QAHW_MODULE_ID_A2DP)) {
+        ahal_name = "a2dp";
+    } else if (!strcmp(hw_module_id, QAHW_MODULE_ID_USB)) {
+        ahal_name = "usb";
+    } else {
+        ALOGE("%s::Invalid Module id %s", __func__, hw_module_id);
+        goto exit;
+    }
+
+    /* return exiting module ptr if already loaded */
+    pthread_mutex_lock(&qahw_module_init_lock);
+    if (qahw_list_count > 0) {
+        qahw_module = get_qahw_module_by_name(hw_module_id);
+        if(qahw_module != NULL) {
+            qahw_mod_handle = (void *)qahw_module;
+            pthread_mutex_lock(&qahw_module->lock);
+            qahw_module->ref_count++;
+            pthread_mutex_unlock(&qahw_module->lock);
+            goto error_exit;
+        }
+    }
+
+    rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, ahal_name, &module);
+    if(rc) {
+        ALOGE("%s::HAL Loading failed %d", __func__, rc);
+        goto error_exit;
+    }
+
+    rc = audio_hw_device_open(module, &audio_device);
+    if(rc) {
+        ALOGE("%s::HAL Device open failed %d", __func__, rc);
+        goto error_exit;
+    }
+
+    qahw_module = (qahw_module_t *)calloc(1, sizeof(qahw_module_t));
+    if(qahw_module == NULL) {
+        ALOGE("%s::calloc failed", __func__);
+        audio_hw_device_close(audio_device);
+        goto error_exit;
+    }
+    ALOGD("%s::Loaded HAL %s module %p", __func__, ahal_name, qahw_module);
+
+    if (!qahw_list_count)
+        list_init(&qahw_module_list);
+    qahw_list_count++;
+
+    pthread_mutex_init(&qahw_module->lock, (const pthread_mutexattr_t *) NULL);
+    pthread_mutex_lock(&qahw_module->lock);
+    qahw_module->ref_count++;
+    pthread_mutex_unlock(&qahw_module->lock);
+
+    list_init(&qahw_module->out_list);
+    list_init(&qahw_module->in_list);
+
+    /* update qahw_module */
+    qahw_module->audio_device = audio_device;
+    strlcpy(&qahw_module->module_name[0], hw_module_id, MAX_MODULE_NAME_LENGTH);
+
+    qahw_mod_handle = (void *)qahw_module;
+
+    /* Add module list to global module list */
+    list_add_tail(&qahw_module_list, &qahw_module->module_list);
+
+
+error_exit:
+    pthread_mutex_unlock(&qahw_module_init_lock);
+
+exit:
+    return qahw_mod_handle;
+}
+
+int qahw_unload_module(qahw_module_handle_t *hw_module)
+{
+    int rc = -EINVAL;
+    bool is_empty = false;
+    qahw_module_t *qahw_module = (qahw_module_t *)hw_module;
+    qahw_module_t *qahw_module_temp = NULL;
+
+    /* close HW device if its valid and all the streams on
+     * it is closed
+    */
+    pthread_mutex_lock(&qahw_module_init_lock);
+    qahw_module_temp = get_qahw_module_by_ptr(qahw_module);
+    if (qahw_module_temp == NULL) {
+        ALOGE("%s:: invalid hw module %p", __func__, qahw_module);
+        goto error_exit;
+    }
+
+    pthread_mutex_lock(&qahw_module->lock);
+    qahw_module->ref_count--;
+    if (qahw_module->ref_count > 0) {
+        rc = 0;
+        ALOGE("%s:: skipping module unload of %p count %d", __func__,
+              qahw_module,
+              qahw_module->ref_count);
+        pthread_mutex_unlock(&qahw_module->lock);
+        goto error_exit;
+    }
+
+    is_empty = (list_empty(&qahw_module->out_list) &&
+             list_empty(&qahw_module->in_list));
+    if (is_empty) {
+        rc = audio_hw_device_close(qahw_module->audio_device);
+        if(rc) {
+            ALOGE("%s::HAL Device close failed Error %d Module %p",__func__,
+                    rc, qahw_module);
+            rc = 0;
+        }
+        qahw_list_count--;
+        list_remove(&qahw_module->module_list);
+        pthread_mutex_unlock(&qahw_module->lock);
+        pthread_mutex_destroy(&qahw_module->lock);
+        free(qahw_module);
+    } else {
+        pthread_mutex_unlock(&qahw_module->lock);
+        ALOGE("%s::failed as all the streams on this module"
+               "is not closed", __func__);
+        rc = -EINVAL;
+    }
+
+error_exit:
+    pthread_mutex_unlock(&qahw_module_init_lock);
+
+exit:
+    return rc;
+}
+
+__END_DECLS