audio: get rid of legacy audio HAL.

Change-Id: Iab96f1cdae507976fff6073ac2c1905d8381e62f
diff --git a/audio/Android.mk b/audio/Android.mk
index 899b1fc..1b62508 100644
--- a/audio/Android.mk
+++ b/audio/Android.mk
@@ -21,20 +21,10 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    libutils \
-    libhardware_legacy
+LOCAL_SHARED_LIBRARIES := libcutils
+
+LOCAL_SRC_FILES := audio_hw.c
 
 LOCAL_SHARED_LIBRARIES += libdl
 
-LOCAL_SRC_FILES += \
-    AudioHardwareGeneric.cpp
-
-LOCAL_STATIC_LIBRARIES := \
-    libmedia_helper
-
-LOCAL_WHOLE_STATIC_LIBRARIES := \
-    libaudiohw_legacy
-
 include $(BUILD_SHARED_LIBRARY)
diff --git a/audio/AudioHardwareGeneric.cpp b/audio/AudioHardwareGeneric.cpp
deleted file mode 100644
index 61d9999..0000000
--- a/audio/AudioHardwareGeneric.cpp
+++ /dev/null
@@ -1,414 +0,0 @@
-/*
-**
-** Copyright 2007, 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 <stdint.h>
-#include <sys/types.h>
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sched.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-
-#define LOG_TAG "AudioHardware"
-#include <utils/Log.h>
-#include <utils/String8.h>
-
-#include "AudioHardwareGeneric.h"
-
-namespace android_audio_legacy {
-
-// ----------------------------------------------------------------------------
-
-static char const * const kAudioDeviceName = "/dev/eac";
-
-// ----------------------------------------------------------------------------
-
-AudioHardwareGeneric::AudioHardwareGeneric()
-    : mOutput(0), mInput(0),  mFd(-1), mMicMute(false)
-{
-    mFd = ::open(kAudioDeviceName, O_RDWR);
-}
-
-AudioHardwareGeneric::~AudioHardwareGeneric()
-{
-    if (mFd >= 0) ::close(mFd);
-    closeOutputStream((AudioStreamOut *)mOutput);
-    closeInputStream((AudioStreamIn *)mInput);
-}
-
-status_t AudioHardwareGeneric::initCheck()
-{
-    if (mFd >= 0) {
-        if (::access(kAudioDeviceName, O_RDWR) == NO_ERROR)
-            return NO_ERROR;
-    }
-    return NO_INIT;
-}
-
-AudioStreamOut* AudioHardwareGeneric::openOutputStream(
-        uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
-{
-    AutoMutex lock(mLock);
-
-    // only one output stream allowed
-    if (mOutput) {
-        if (status) {
-            *status = INVALID_OPERATION;
-        }
-        return 0;
-    }
-
-    // create new output stream
-    AudioStreamOutGeneric* out = new AudioStreamOutGeneric();
-    status_t lStatus = out->set(this, mFd, devices, format, channels, sampleRate);
-    if (status) {
-        *status = lStatus;
-    }
-    if (lStatus == NO_ERROR) {
-        mOutput = out;
-    } else {
-        delete out;
-    }
-    return mOutput;
-}
-
-void AudioHardwareGeneric::closeOutputStream(AudioStreamOut* out) {
-    if (mOutput && out == mOutput) {
-        delete mOutput;
-        mOutput = 0;
-    }
-}
-
-AudioStreamIn* AudioHardwareGeneric::openInputStream(
-        uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate,
-        status_t *status, AudioSystem::audio_in_acoustics acoustics)
-{
-    // check for valid input source
-    if (!AudioSystem::isInputDevice((AudioSystem::audio_devices)devices)) {
-        return 0;
-    }
-
-    AutoMutex lock(mLock);
-
-    // only one input stream allowed
-    if (mInput) {
-        if (status) {
-            *status = INVALID_OPERATION;
-        }
-        return 0;
-    }
-
-    // create new output stream
-    AudioStreamInGeneric* in = new AudioStreamInGeneric();
-    status_t lStatus = in->set(this, mFd, devices, format, channels, sampleRate, acoustics);
-    if (status) {
-        *status = lStatus;
-    }
-    if (lStatus == NO_ERROR) {
-        mInput = in;
-    } else {
-        delete in;
-    }
-    return mInput;
-}
-
-void AudioHardwareGeneric::closeInputStream(AudioStreamIn* in) {
-    if (mInput && in == mInput) {
-        delete mInput;
-        mInput = 0;
-    }
-}
-
-status_t AudioHardwareGeneric::setVoiceVolume(float v)
-{
-    // Implement: set voice volume
-    return NO_ERROR;
-}
-
-status_t AudioHardwareGeneric::setMasterVolume(float v)
-{
-    // Implement: set master volume
-    // return error - software mixer will handle it
-    return INVALID_OPERATION;
-}
-
-status_t AudioHardwareGeneric::setMicMute(bool state)
-{
-    mMicMute = state;
-    return NO_ERROR;
-}
-
-status_t AudioHardwareGeneric::getMicMute(bool* state)
-{
-    *state = mMicMute;
-    return NO_ERROR;
-}
-
-status_t AudioHardwareGeneric::dumpInternals(int fd, const Vector<String16>& args)
-{
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-    result.append("AudioHardwareGeneric::dumpInternals\n");
-    snprintf(buffer, SIZE, "\tmFd: %d mMicMute: %s\n",  mFd, mMicMute? "true": "false");
-    result.append(buffer);
-    ::write(fd, result.string(), result.size());
-    return NO_ERROR;
-}
-
-status_t AudioHardwareGeneric::dump(int fd, const Vector<String16>& args)
-{
-    dumpInternals(fd, args);
-    if (mInput) {
-        mInput->dump(fd, args);
-    }
-    if (mOutput) {
-        mOutput->dump(fd, args);
-    }
-    return NO_ERROR;
-}
-
-// ----------------------------------------------------------------------------
-
-status_t AudioStreamOutGeneric::set(
-        AudioHardwareGeneric *hw,
-        int fd,
-        uint32_t devices,
-        int *pFormat,
-        uint32_t *pChannels,
-        uint32_t *pRate)
-{
-    int lFormat = pFormat ? *pFormat : 0;
-    uint32_t lChannels = pChannels ? *pChannels : 0;
-    uint32_t lRate = pRate ? *pRate : 0;
-
-    // fix up defaults
-    if (lFormat == 0) lFormat = format();
-    if (lChannels == 0) lChannels = channels();
-    if (lRate == 0) lRate = sampleRate();
-
-    // check values
-    if ((lFormat != format()) ||
-            (lChannels != channels()) ||
-            (lRate != sampleRate())) {
-        if (pFormat) *pFormat = format();
-        if (pChannels) *pChannels = channels();
-        if (pRate) *pRate = sampleRate();
-        return BAD_VALUE;
-    }
-
-    if (pFormat) *pFormat = lFormat;
-    if (pChannels) *pChannels = lChannels;
-    if (pRate) *pRate = lRate;
-
-    mAudioHardware = hw;
-    mFd = fd;
-    mDevice = devices;
-    return NO_ERROR;
-}
-
-AudioStreamOutGeneric::~AudioStreamOutGeneric()
-{
-}
-
-ssize_t AudioStreamOutGeneric::write(const void* buffer, size_t bytes)
-{
-    Mutex::Autolock _l(mLock);
-    return ssize_t(::write(mFd, buffer, bytes));
-}
-
-status_t AudioStreamOutGeneric::standby()
-{
-    // Implement: audio hardware to standby mode
-    return NO_ERROR;
-}
-
-status_t AudioStreamOutGeneric::dump(int fd, const Vector<String16>& args)
-{
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-    snprintf(buffer, SIZE, "AudioStreamOutGeneric::dump\n");
-    result.append(buffer);
-    snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
-    result.append(buffer);
-    snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
-    result.append(buffer);
-    snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
-    result.append(buffer);
-    snprintf(buffer, SIZE, "\tformat: %d\n", format());
-    result.append(buffer);
-    snprintf(buffer, SIZE, "\tdevice: %d\n", mDevice);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "\tmAudioHardware: %p\n", mAudioHardware);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "\tmFd: %d\n", mFd);
-    result.append(buffer);
-    ::write(fd, result.string(), result.size());
-    return NO_ERROR;
-}
-
-status_t AudioStreamOutGeneric::setParameters(const String8& keyValuePairs)
-{
-    AudioParameter param = AudioParameter(keyValuePairs);
-    String8 key = String8(AudioParameter::keyRouting);
-    status_t status = NO_ERROR;
-    int device;
-    ALOGV("setParameters() %s", keyValuePairs.string());
-
-    if (param.getInt(key, device) == NO_ERROR) {
-        mDevice = device;
-        param.remove(key);
-    }
-
-    if (param.size()) {
-        status = BAD_VALUE;
-    }
-    return status;
-}
-
-String8 AudioStreamOutGeneric::getParameters(const String8& keys)
-{
-    AudioParameter param = AudioParameter(keys);
-    String8 value;
-    String8 key = String8(AudioParameter::keyRouting);
-
-    if (param.get(key, value) == NO_ERROR) {
-        param.addInt(key, (int)mDevice);
-    }
-
-    ALOGV("getParameters() %s", param.toString().string());
-    return param.toString();
-}
-
-status_t AudioStreamOutGeneric::getRenderPosition(uint32_t *dspFrames)
-{
-    return INVALID_OPERATION;
-}
-
-// ----------------------------------------------------------------------------
-
-// record functions
-status_t AudioStreamInGeneric::set(
-        AudioHardwareGeneric *hw,
-        int fd,
-        uint32_t devices,
-        int *pFormat,
-        uint32_t *pChannels,
-        uint32_t *pRate,
-        AudioSystem::audio_in_acoustics acoustics)
-{
-    if (pFormat == 0 || pChannels == 0 || pRate == 0) return BAD_VALUE;
-    ALOGV("AudioStreamInGeneric::set(%p, %d, %d, %d, %u)", hw, fd, *pFormat, *pChannels, *pRate);
-    // check values
-    if ((*pFormat != format()) ||
-        (*pChannels != channels()) ||
-        (*pRate != sampleRate())) {
-        ALOGE("Error opening input channel");
-        *pFormat = format();
-        *pChannels = channels();
-        *pRate = sampleRate();
-        return BAD_VALUE;
-    }
-
-    mAudioHardware = hw;
-    mFd = fd;
-    mDevice = devices;
-    return NO_ERROR;
-}
-
-AudioStreamInGeneric::~AudioStreamInGeneric()
-{
-}
-
-ssize_t AudioStreamInGeneric::read(void* buffer, ssize_t bytes)
-{
-    AutoMutex lock(mLock);
-    if (mFd < 0) {
-        ALOGE("Attempt to read from unopened device");
-        return NO_INIT;
-    }
-    return ::read(mFd, buffer, bytes);
-}
-
-status_t AudioStreamInGeneric::dump(int fd, const Vector<String16>& args)
-{
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-    snprintf(buffer, SIZE, "AudioStreamInGeneric::dump\n");
-    result.append(buffer);
-    snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
-    result.append(buffer);
-    snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
-    result.append(buffer);
-    snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
-    result.append(buffer);
-    snprintf(buffer, SIZE, "\tformat: %d\n", format());
-    result.append(buffer);
-    snprintf(buffer, SIZE, "\tdevice: %d\n", mDevice);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "\tmAudioHardware: %p\n", mAudioHardware);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "\tmFd: %d\n", mFd);
-    result.append(buffer);
-    ::write(fd, result.string(), result.size());
-    return NO_ERROR;
-}
-
-status_t AudioStreamInGeneric::setParameters(const String8& keyValuePairs)
-{
-    AudioParameter param = AudioParameter(keyValuePairs);
-    String8 key = String8(AudioParameter::keyRouting);
-    status_t status = NO_ERROR;
-    int device;
-    ALOGV("setParameters() %s", keyValuePairs.string());
-
-    if (param.getInt(key, device) == NO_ERROR) {
-        mDevice = device;
-        param.remove(key);
-    }
-
-    if (param.size()) {
-        status = BAD_VALUE;
-    }
-    return status;
-}
-
-String8 AudioStreamInGeneric::getParameters(const String8& keys)
-{
-    AudioParameter param = AudioParameter(keys);
-    String8 value;
-    String8 key = String8(AudioParameter::keyRouting);
-
-    if (param.get(key, value) == NO_ERROR) {
-        param.addInt(key, (int)mDevice);
-    }
-
-    ALOGV("getParameters() %s", param.toString().string());
-    return param.toString();
-}
-
-// ----------------------------------------------------------------------------
-
-extern "C" AudioHardwareInterface* createAudioHardware(void) {
-    return new AudioHardwareGeneric();
-}
-
-}; // namespace android
diff --git a/audio/AudioHardwareGeneric.h b/audio/AudioHardwareGeneric.h
deleted file mode 100644
index 6b48aa6..0000000
--- a/audio/AudioHardwareGeneric.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
-**
-** Copyright 2007, 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_HARDWARE_GENERIC_H
-#define ANDROID_AUDIO_HARDWARE_GENERIC_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/threads.h>
-
-#include <hardware_legacy/AudioHardwareBase.h>
-
-namespace android_audio_legacy {
-    using android::Mutex;
-    using android::AutoMutex;
-
-// ----------------------------------------------------------------------------
-
-class AudioHardwareGeneric;
-
-class AudioStreamOutGeneric : public AudioStreamOut {
-public:
-                        AudioStreamOutGeneric() : mAudioHardware(0), mFd(-1) {}
-    virtual             ~AudioStreamOutGeneric();
-
-    virtual status_t    set(
-            AudioHardwareGeneric *hw,
-            int mFd,
-            uint32_t devices,
-            int *pFormat,
-            uint32_t *pChannels,
-            uint32_t *pRate);
-
-    virtual uint32_t    sampleRate() const { return 44100; }
-    virtual size_t      bufferSize() const { return 4096; }
-    virtual uint32_t    channels() const { return AudioSystem::CHANNEL_OUT_STEREO; }
-    virtual int         format() const { return AudioSystem::PCM_16_BIT; }
-    virtual uint32_t    latency() const { return 20; }
-    virtual status_t    setVolume(float left, float right) { return INVALID_OPERATION; }
-    virtual ssize_t     write(const void* buffer, size_t bytes);
-    virtual status_t    standby();
-    virtual status_t    dump(int fd, const Vector<String16>& args);
-    virtual status_t    setParameters(const String8& keyValuePairs);
-    virtual String8     getParameters(const String8& keys);
-    virtual status_t    getRenderPosition(uint32_t *dspFrames);
-
-private:
-    AudioHardwareGeneric *mAudioHardware;
-    Mutex   mLock;
-    int     mFd;
-    uint32_t mDevice;
-};
-
-class AudioStreamInGeneric : public AudioStreamIn {
-public:
-                        AudioStreamInGeneric() : mAudioHardware(0), mFd(-1) {}
-    virtual             ~AudioStreamInGeneric();
-
-    virtual status_t    set(
-            AudioHardwareGeneric *hw,
-            int mFd,
-            uint32_t devices,
-            int *pFormat,
-            uint32_t *pChannels,
-            uint32_t *pRate,
-            AudioSystem::audio_in_acoustics acoustics);
-
-    virtual uint32_t    sampleRate() const { return 8000; }
-    virtual size_t      bufferSize() const { return 320; }
-    virtual uint32_t    channels() const { return AudioSystem::CHANNEL_IN_MONO; }
-    virtual int         format() const { return AudioSystem::PCM_16_BIT; }
-    virtual status_t    setGain(float gain) { return INVALID_OPERATION; }
-    virtual ssize_t     read(void* buffer, ssize_t bytes);
-    virtual status_t    dump(int fd, const Vector<String16>& args);
-    virtual status_t    standby() { return NO_ERROR; }
-    virtual status_t    setParameters(const String8& keyValuePairs);
-    virtual String8     getParameters(const String8& keys);
-    virtual unsigned int  getInputFramesLost() const { return 0; }
-    virtual status_t    addAudioEffect(effect_handle_t effect) { return NO_ERROR; }
-    virtual status_t    removeAudioEffect(effect_handle_t effect) { return NO_ERROR; }
-
-private:
-    AudioHardwareGeneric *mAudioHardware;
-    Mutex   mLock;
-    int     mFd;
-    uint32_t mDevice;
-};
-
-
-class AudioHardwareGeneric : public AudioHardwareBase
-{
-public:
-                        AudioHardwareGeneric();
-    virtual             ~AudioHardwareGeneric();
-    virtual status_t    initCheck();
-    virtual status_t    setVoiceVolume(float volume);
-    virtual status_t    setMasterVolume(float volume);
-
-    // mic mute
-    virtual status_t    setMicMute(bool state);
-    virtual status_t    getMicMute(bool* state);
-
-    // create I/O streams
-    virtual AudioStreamOut* openOutputStream(
-            uint32_t devices,
-            int *format=0,
-            uint32_t *channels=0,
-            uint32_t *sampleRate=0,
-            status_t *status=0);
-    virtual    void        closeOutputStream(AudioStreamOut* out);
-
-    virtual AudioStreamIn* openInputStream(
-            uint32_t devices,
-            int *format,
-            uint32_t *channels,
-            uint32_t *sampleRate,
-            status_t *status,
-            AudioSystem::audio_in_acoustics acoustics);
-    virtual    void        closeInputStream(AudioStreamIn* in);
-
-            void            closeOutputStream(AudioStreamOutGeneric* out);
-            void            closeInputStream(AudioStreamInGeneric* in);
-protected:
-    virtual status_t        dump(int fd, const Vector<String16>& args);
-
-private:
-    status_t                dumpInternals(int fd, const Vector<String16>& args);
-
-    Mutex                   mLock;
-    AudioStreamOutGeneric   *mOutput;
-    AudioStreamInGeneric    *mInput;
-    int                     mFd;
-    bool                    mMicMute;
-};
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_AUDIO_HARDWARE_GENERIC_H
diff --git a/audio/audio_hw.c b/audio/audio_hw.c
new file mode 100644
index 0000000..b7ea353
--- /dev/null
+++ b/audio/audio_hw.c
@@ -0,0 +1,690 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#define LOG_TAG "audio_hw_generic"
+/*#define LOG_NDEBUG 0*/
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <fcntl.h>
+
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+
+#include <hardware/hardware.h>
+#include <system/audio.h>
+#include <hardware/audio.h>
+
+
+#define AUDIO_DEVICE_NAME "/dev/eac"
+#define OUT_SAMPLING_RATE 44100
+#define OUT_BUFFER_SIZE 4096
+#define OUT_LATENCY_MS 20
+#define IN_SAMPLING_RATE 8000
+#define IN_BUFFER_SIZE 320
+
+
+struct generic_audio_device {
+    struct audio_hw_device device;
+    pthread_mutex_t lock;
+    struct audio_stream_out *output;
+    struct audio_stream_in *input;
+    int fd;
+    bool mic_mute;
+};
+
+
+struct generic_stream_out {
+    struct audio_stream_out stream;
+    struct generic_audio_device *dev;
+    audio_devices_t device;
+};
+
+struct generic_stream_in {
+    struct audio_stream_in stream;
+    struct generic_audio_device *dev;
+    audio_devices_t device;
+};
+
+
+static uint32_t out_get_sample_rate(const struct audio_stream *stream)
+{
+    return OUT_SAMPLING_RATE;
+}
+
+static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+{
+    return -ENOSYS;
+}
+
+static size_t out_get_buffer_size(const struct audio_stream *stream)
+{
+    return OUT_BUFFER_SIZE;
+}
+
+static audio_channel_mask_t out_get_channels(const struct audio_stream *stream)
+{
+    return AUDIO_CHANNEL_OUT_STEREO;
+}
+
+static audio_format_t out_get_format(const struct audio_stream *stream)
+{
+    return AUDIO_FORMAT_PCM_16_BIT;
+}
+
+static int out_set_format(struct audio_stream *stream, audio_format_t format)
+{
+    return -ENOSYS;
+}
+
+static int out_standby(struct audio_stream *stream)
+{
+    // out_standby is a no op
+    return 0;
+}
+
+static int out_dump(const struct audio_stream *stream, int fd)
+{
+    struct generic_stream_out *out = (struct generic_stream_out *)stream;
+
+    fdprintf(fd, "\tout_dump:\n"
+                 "\t\tsample rate: %u\n"
+                 "\t\tbuffer size: %u\n"
+                 "\t\tchannel mask: %08x\n"
+                 "\t\tformat: %d\n"
+                 "\t\tdevice: %08x\n"
+                 "\t\taudio dev: %p\n\n",
+                 out_get_sample_rate(stream),
+                 out_get_buffer_size(stream),
+                 out_get_channels(stream),
+                 out_get_format(stream),
+                 out->device,
+                 out->dev);
+
+    return 0;
+}
+
+static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+    struct generic_stream_out *out = (struct generic_stream_out *)stream;
+    struct str_parms *parms;
+    char value[32];
+    int ret;
+    long val;
+    char *end;
+
+    parms = str_parms_create_str(kvpairs);
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING,
+                            value, sizeof(value));
+    if (ret >= 0) {
+        errno = 0;
+        val = strtol(value, &end, 10);
+        if (errno == 0 && (end != NULL) && (*end == '\0') && ((int)val == val)) {
+            out->device = (int)val;
+        } else {
+            ret = -EINVAL;
+        }
+    }
+
+    str_parms_destroy(parms);
+    return ret;
+}
+
+static char * out_get_parameters(const struct audio_stream *stream, const char *keys)
+{
+    struct generic_stream_out *out = (struct generic_stream_out *)stream;
+    struct str_parms *query = str_parms_create_str(keys);
+    char *str;
+    char value[256];
+    struct str_parms *reply = str_parms_create();
+    int ret;
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
+    if (ret >= 0) {
+        str_parms_add_int(reply, AUDIO_PARAMETER_STREAM_ROUTING, out->device);
+        str = strdup(str_parms_to_str(reply));
+    } else {
+        str = strdup(keys);
+    }
+
+    str_parms_destroy(query);
+    str_parms_destroy(reply);
+    return str;
+}
+
+static uint32_t out_get_latency(const struct audio_stream_out *stream)
+{
+    return OUT_LATENCY_MS;
+}
+
+static int out_set_volume(struct audio_stream_out *stream, float left,
+                          float right)
+{
+    return -ENOSYS;
+}
+
+static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
+                         size_t bytes)
+{
+    struct generic_stream_out *out = (struct generic_stream_out *)stream;
+    struct generic_audio_device *adev = out->dev;
+
+    pthread_mutex_lock(&adev->lock);
+    if (adev->fd >= 0)
+        bytes = write(adev->fd, buffer, bytes);
+    pthread_mutex_unlock(&adev->lock);
+
+    return bytes;
+}
+
+static int out_get_render_position(const struct audio_stream_out *stream,
+                                   uint32_t *dsp_frames)
+{
+    return -ENOSYS;
+}
+
+static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+    // out_add_audio_effect is a no op
+    return 0;
+}
+
+static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+    // out_remove_audio_effect is a no op
+    return 0;
+}
+
+static int out_get_next_write_timestamp(const struct audio_stream_out *stream,
+                                        int64_t *timestamp)
+{
+    return -ENOSYS;
+}
+
+/** audio_stream_in implementation **/
+static uint32_t in_get_sample_rate(const struct audio_stream *stream)
+{
+    return IN_SAMPLING_RATE;
+}
+
+static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+{
+    return -ENOSYS;
+}
+
+static size_t in_get_buffer_size(const struct audio_stream *stream)
+{
+    return IN_BUFFER_SIZE;
+}
+
+static audio_channel_mask_t in_get_channels(const struct audio_stream *stream)
+{
+    return AUDIO_CHANNEL_IN_MONO;
+}
+
+static audio_format_t in_get_format(const struct audio_stream *stream)
+{
+    return AUDIO_FORMAT_PCM_16_BIT;
+}
+
+static int in_set_format(struct audio_stream *stream, audio_format_t format)
+{
+    return -ENOSYS;
+}
+
+static int in_standby(struct audio_stream *stream)
+{
+    // in_standby is a no op
+    return 0;
+}
+
+static int in_dump(const struct audio_stream *stream, int fd)
+{
+    struct generic_stream_in *in = (struct generic_stream_in *)stream;
+
+    fdprintf(fd, "\tin_dump:\n"
+                 "\t\tsample rate: %u\n"
+                 "\t\tbuffer size: %u\n"
+                 "\t\tchannel mask: %08x\n"
+                 "\t\tformat: %d\n"
+                 "\t\tdevice: %08x\n"
+                 "\t\taudio dev: %p\n\n",
+                 in_get_sample_rate(stream),
+                 in_get_buffer_size(stream),
+                 in_get_channels(stream),
+                 in_get_format(stream),
+                 in->device,
+                 in->dev);
+
+    return 0;
+}
+
+static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+    struct generic_stream_in *in = (struct generic_stream_in *)stream;
+    struct str_parms *parms;
+    char value[32];
+    int ret;
+    long val;
+    char *end;
+
+    parms = str_parms_create_str(kvpairs);
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING,
+                            value, sizeof(value));
+    if (ret >= 0) {
+        errno = 0;
+        val = strtol(value, &end, 10);
+        if ((errno == 0) && (end != NULL) && (*end == '\0') && ((int)val == val)) {
+            in->device = (int)val;
+        } else {
+            ret = -EINVAL;
+        }
+    }
+
+    str_parms_destroy(parms);
+    return ret;
+}
+
+static char * in_get_parameters(const struct audio_stream *stream,
+                                const char *keys)
+{
+    struct generic_stream_in *in = (struct generic_stream_in *)stream;
+    struct str_parms *query = str_parms_create_str(keys);
+    char *str;
+    char value[256];
+    struct str_parms *reply = str_parms_create();
+    int ret;
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
+    if (ret >= 0) {
+        str_parms_add_int(reply, AUDIO_PARAMETER_STREAM_ROUTING, in->device);
+        str = strdup(str_parms_to_str(reply));
+    } else {
+        str = strdup(keys);
+    }
+
+    str_parms_destroy(query);
+    str_parms_destroy(reply);
+    return str;
+}
+
+static int in_set_gain(struct audio_stream_in *stream, float gain)
+{
+    // in_set_gain is a no op
+    return 0;
+}
+
+static ssize_t in_read(struct audio_stream_in *stream, void* buffer,
+                       size_t bytes)
+{
+    struct generic_stream_in *in = (struct generic_stream_in *)stream;
+    struct generic_audio_device *adev = in->dev;
+
+    pthread_mutex_lock(&adev->lock);
+    if (adev->fd >= 0)
+        bytes = read(adev->fd, buffer, bytes);
+    if (adev->mic_mute && (bytes > 0)) {
+        memset(buffer, 0, bytes);
+    }
+    pthread_mutex_unlock(&adev->lock);
+
+    return bytes;
+}
+
+static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream)
+{
+    return 0;
+}
+
+static int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+    // in_add_audio_effect is a no op
+    return 0;
+}
+
+static int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+    // in_add_audio_effect is a no op
+    return 0;
+}
+
+static int adev_open_output_stream(struct audio_hw_device *dev,
+                                   audio_io_handle_t handle,
+                                   audio_devices_t devices,
+                                   audio_output_flags_t flags,
+                                   struct audio_config *config,
+                                   struct audio_stream_out **stream_out)
+{
+    struct generic_audio_device *adev = (struct generic_audio_device *)dev;
+    struct generic_stream_out *out;
+    int ret = 0;
+
+    pthread_mutex_lock(&adev->lock);
+    if (adev->output != NULL) {
+        ret = -ENOSYS;
+        goto error;
+    }
+
+    if ((config->format != AUDIO_FORMAT_PCM_16_BIT) ||
+        (config->channel_mask != AUDIO_CHANNEL_OUT_STEREO) ||
+        (config->sample_rate != OUT_SAMPLING_RATE)) {
+        ALOGE("Error opening output stream format %d, channel_mask %04x, sample_rate %u",
+              config->format, config->channel_mask, config->sample_rate);
+        config->format = AUDIO_FORMAT_PCM_16_BIT;
+        config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+        config->sample_rate = OUT_SAMPLING_RATE;
+        ret = -EINVAL;
+        goto error;
+    }
+
+    out = (struct generic_stream_out *)calloc(1, sizeof(struct generic_stream_out));
+
+    out->stream.common.get_sample_rate = out_get_sample_rate;
+    out->stream.common.set_sample_rate = out_set_sample_rate;
+    out->stream.common.get_buffer_size = out_get_buffer_size;
+    out->stream.common.get_channels = out_get_channels;
+    out->stream.common.get_format = out_get_format;
+    out->stream.common.set_format = out_set_format;
+    out->stream.common.standby = out_standby;
+    out->stream.common.dump = out_dump;
+    out->stream.common.set_parameters = out_set_parameters;
+    out->stream.common.get_parameters = out_get_parameters;
+    out->stream.common.add_audio_effect = out_add_audio_effect;
+    out->stream.common.remove_audio_effect = out_remove_audio_effect;
+    out->stream.get_latency = out_get_latency;
+    out->stream.set_volume = out_set_volume;
+    out->stream.write = out_write;
+    out->stream.get_render_position = out_get_render_position;
+    out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
+
+    out->dev = adev;
+    out->device = devices;
+    adev->output = (struct audio_stream_out *)out;
+    *stream_out = &out->stream;
+
+error:
+    pthread_mutex_unlock(&adev->lock);
+
+    return ret;
+}
+
+static void adev_close_output_stream(struct audio_hw_device *dev,
+                                     struct audio_stream_out *stream)
+{
+    struct generic_audio_device *adev = (struct generic_audio_device *)dev;
+
+    pthread_mutex_lock(&adev->lock);
+    if (stream == adev->output) {
+        free(stream);
+        adev->output = NULL;
+    }
+    pthread_mutex_unlock(&adev->lock);
+}
+
+static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
+{
+    return 0;
+}
+
+static char * adev_get_parameters(const struct audio_hw_device *dev,
+                                  const char *keys)
+{
+    return strdup("");
+}
+
+static int adev_init_check(const struct audio_hw_device *dev)
+{
+    struct generic_audio_device *adev = (struct generic_audio_device *)dev;
+
+    if (adev->fd >= 0)
+        return 0;
+
+    return -ENODEV;
+}
+
+static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
+{
+    // adev_set_voice_volume is a no op (simulates phones)
+    return 0;
+}
+
+static int adev_set_master_volume(struct audio_hw_device *dev, float volume)
+{
+    return -ENOSYS;
+}
+
+static int adev_get_master_volume(struct audio_hw_device *dev, float *volume)
+{
+    return -ENOSYS;
+}
+
+static int adev_set_master_mute(struct audio_hw_device *dev, bool muted)
+{
+    return -ENOSYS;
+}
+
+static int adev_get_master_mute(struct audio_hw_device *dev, bool *muted)
+{
+    return -ENOSYS;
+}
+
+static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
+{
+    // adev_set_mode is a no op (simulates phones)
+    return 0;
+}
+
+static int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
+{
+    struct generic_audio_device *adev = (struct generic_audio_device *)dev;
+
+    pthread_mutex_lock(&adev->lock);
+    adev->mic_mute = state;
+    pthread_mutex_unlock(&adev->lock);
+    return 0;
+}
+
+static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
+{
+    struct generic_audio_device *adev = (struct generic_audio_device *)dev;
+
+    pthread_mutex_lock(&adev->lock);
+    *state = adev->mic_mute;
+    pthread_mutex_unlock(&adev->lock);
+
+    return 0;
+}
+
+static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
+                                         const struct audio_config *config)
+{
+    return IN_BUFFER_SIZE;
+}
+
+static int adev_open_input_stream(struct audio_hw_device *dev,
+                                  audio_io_handle_t handle,
+                                  audio_devices_t devices,
+                                  struct audio_config *config,
+                                  struct audio_stream_in **stream_in)
+{
+    struct generic_audio_device *adev = (struct generic_audio_device *)dev;
+    struct generic_stream_in *in;
+    int ret = 0;
+
+    pthread_mutex_lock(&adev->lock);
+    if (adev->input != NULL) {
+        ret = -ENOSYS;
+        goto error;
+    }
+
+    if ((config->format != AUDIO_FORMAT_PCM_16_BIT) ||
+        (config->channel_mask != AUDIO_CHANNEL_IN_MONO) ||
+        (config->sample_rate != IN_SAMPLING_RATE)) {
+        ALOGE("Error opening input stream format %d, channel_mask %04x, sample_rate %u",
+              config->format, config->channel_mask, config->sample_rate);
+        config->format = AUDIO_FORMAT_PCM_16_BIT;
+        config->channel_mask = AUDIO_CHANNEL_IN_MONO;
+        config->sample_rate = IN_SAMPLING_RATE;
+        ret = -EINVAL;
+        goto error;
+    }
+
+    in = (struct generic_stream_in *)calloc(1, sizeof(struct generic_stream_in));
+
+    in->stream.common.get_sample_rate = in_get_sample_rate;
+    in->stream.common.set_sample_rate = in_set_sample_rate;
+    in->stream.common.get_buffer_size = in_get_buffer_size;
+    in->stream.common.get_channels = in_get_channels;
+    in->stream.common.get_format = in_get_format;
+    in->stream.common.set_format = in_set_format;
+    in->stream.common.standby = in_standby;
+    in->stream.common.dump = in_dump;
+    in->stream.common.set_parameters = in_set_parameters;
+    in->stream.common.get_parameters = in_get_parameters;
+    in->stream.common.add_audio_effect = in_add_audio_effect;
+    in->stream.common.remove_audio_effect = in_remove_audio_effect;
+    in->stream.set_gain = in_set_gain;
+    in->stream.read = in_read;
+    in->stream.get_input_frames_lost = in_get_input_frames_lost;
+
+    in->dev = adev;
+    in->device = devices;
+    adev->input = (struct audio_stream_in *)in;
+    *stream_in = &in->stream;
+
+error:
+    pthread_mutex_unlock(&adev->lock);
+
+    return ret;
+}
+
+static void adev_close_input_stream(struct audio_hw_device *dev,
+                                   struct audio_stream_in *stream)
+{
+    struct generic_audio_device *adev = (struct generic_audio_device *)dev;
+
+    pthread_mutex_lock(&adev->lock);
+    if (stream == adev->input) {
+        free(stream);
+        adev->input = NULL;
+    }
+    pthread_mutex_unlock(&adev->lock);
+}
+
+static int adev_dump(const audio_hw_device_t *dev, int fd)
+{
+    struct generic_audio_device *adev = (struct generic_audio_device *)dev;
+
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+
+    fdprintf(fd, "\nadev_dump:\n"
+                 "\tfd: %d\n"
+                 "\tmic_mute: %s\n"
+                 "\toutput: %p\n"
+                 "\tinput: %p\n\n",
+                 adev->fd,
+                 adev->mic_mute ? "true": "false",
+                 adev->output,
+                 adev->input);
+
+    if (adev->output != NULL)
+        out_dump((const struct audio_stream *)adev->output, fd);
+    if (adev->input != NULL)
+        in_dump((const struct audio_stream *)adev->input, fd);
+
+    return 0;
+}
+
+static int adev_close(hw_device_t *dev)
+{
+    struct generic_audio_device *adev = (struct generic_audio_device *)dev;
+
+    adev_close_output_stream((struct audio_hw_device *)dev, adev->output);
+    adev_close_input_stream((struct audio_hw_device *)dev, adev->input);
+
+    if (adev->fd >= 0)
+        close(adev->fd);
+
+    free(dev);
+    return 0;
+}
+
+static int adev_open(const hw_module_t* module, const char* name,
+                     hw_device_t** device)
+{
+    struct generic_audio_device *adev;
+    int fd;
+
+    if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
+        return -EINVAL;
+
+    fd = open(AUDIO_DEVICE_NAME, O_RDWR);
+    if (fd < 0)
+        return -ENOSYS;
+
+    adev = calloc(1, sizeof(struct generic_audio_device));
+
+    adev->fd = fd;
+
+    adev->device.common.tag = HARDWARE_DEVICE_TAG;
+    adev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
+    adev->device.common.module = (struct hw_module_t *) module;
+    adev->device.common.close = adev_close;
+
+    adev->device.init_check = adev_init_check;
+    adev->device.set_voice_volume = adev_set_voice_volume;
+    adev->device.set_master_volume = adev_set_master_volume;
+    adev->device.get_master_volume = adev_get_master_volume;
+    adev->device.set_master_mute = adev_set_master_mute;
+    adev->device.get_master_mute = adev_get_master_mute;
+    adev->device.set_mode = adev_set_mode;
+    adev->device.set_mic_mute = adev_set_mic_mute;
+    adev->device.get_mic_mute = adev_get_mic_mute;
+    adev->device.set_parameters = adev_set_parameters;
+    adev->device.get_parameters = adev_get_parameters;
+    adev->device.get_input_buffer_size = adev_get_input_buffer_size;
+    adev->device.open_output_stream = adev_open_output_stream;
+    adev->device.close_output_stream = adev_close_output_stream;
+    adev->device.open_input_stream = adev_open_input_stream;
+    adev->device.close_input_stream = adev_close_input_stream;
+    adev->device.dump = adev_dump;
+
+    *device = &adev->device.common;
+
+    return 0;
+}
+
+static struct hw_module_methods_t hal_module_methods = {
+    .open = adev_open,
+};
+
+struct audio_module HAL_MODULE_INFO_SYM = {
+    .common = {
+        .tag = HARDWARE_MODULE_TAG,
+        .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
+        .hal_api_version = HARDWARE_HAL_API_VERSION,
+        .id = AUDIO_HARDWARE_MODULE_ID,
+        .name = "Generic audio HW HAL",
+        .author = "The Android Open Source Project",
+        .methods = &hal_module_methods,
+    },
+};