audioflinger: enumerate all the possible audio interfaces

Keep track of the primary interface that handles the master volume,
etc.

Change-Id: Ib0701fccff8d8783a99035a241ab7c8ec75c00ac
Signed-off-by: Dima Zavin <dima@android.com>
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 301f467..e494d05 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -136,49 +136,98 @@
     service->addBatteryData(params);
 }
 
+static int load_audio_interface(const char *if_name, const hw_module_t **mod,
+                                audio_hw_device_t **dev)
+{
+    int rc;
+
+    rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, mod);
+    if (rc)
+        goto out;
+
+    rc = audio_hw_device_open(*mod, dev);
+    LOGE_IF(rc, "couldn't open audio hw device in %s.%s (%s)",
+            AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc));
+    if (rc)
+        goto out;
+
+    return 0;
+
+out:
+    *mod = NULL;
+    *dev = NULL;
+    return rc;
+}
+
+static const char *audio_interfaces[] = {
+    "primary",
+    "a2dp",
+    "usb",
+};
+#define ARRAY_SIZE(x) (sizeof((x))/sizeof(((x)[0])))
+
 // ----------------------------------------------------------------------------
 
 AudioFlinger::AudioFlinger()
     : BnAudioFlinger(),
-        mAudioHardwareDev(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1)
+        mPrimaryHardwareDev(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1)
 {
-    const hw_module_t *module;
-    int rc;
-    char mod_name[PATH_MAX];
+    int rc = 0;
 
     Mutex::Autolock _l(mLock);
 
+    /* TODO: move all this work into an Init() function */
     mHardwareStatus = AUDIO_HW_IDLE;
 
-    /* get the audio hw module and create an audio_hw device */
-    snprintf(mod_name, PATH_MAX, "%s.%s", AUDIO_HARDWARE_MODULE_ID, "primary");
-    rc = hw_get_module(mod_name, &module);
-    if (rc)
-        return;
+    for (size_t i = 0; i < ARRAY_SIZE(audio_interfaces); i++) {
+        const hw_module_t *mod;
+        audio_hw_device_t *dev;
 
-    rc = audio_hw_device_open(module, &mAudioHardwareDev);
-    LOGE_IF(rc, "couldn't open audio hw device (%s)", strerror(-rc));
-    if (rc)
-        return;
+        rc = load_audio_interface(audio_interfaces[i], &mod, &dev);
+        if (rc)
+            continue;
+
+        LOGI("Loaded %s audio interface from %s (%s)", audio_interfaces[i],
+             mod->name, mod->id);
+        mAudioHwDevs.push(dev);
+
+        if (!mPrimaryHardwareDev) {
+            mPrimaryHardwareDev = dev;
+            LOGI("Using '%s' (%s.%s) as the primary audio interface",
+                 AUDIO_HARDWARE_INTERFACE, mod->name, mod->id,
+                 audio_interfaces[i]);
+        }
+    }
 
     mHardwareStatus = AUDIO_HW_INIT;
 
-    rc = mAudioHardwareDev->init_check(mAudioHardwareDev);
-    if (rc == 0) {
-        AutoMutex lock(mHardwareLock);
-        mMode = AUDIO_MODE_NORMAL;
-        mHardwareStatus = AUDIO_HW_SET_MODE;
-        mAudioHardwareDev->set_mode(mAudioHardwareDev, mMode);
-        mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
-        mAudioHardwareDev->set_master_volume(mAudioHardwareDev, 1.0f);
-        mHardwareStatus = AUDIO_HW_IDLE;
-    } else {
-        LOGE("Couldn't even initialize the stubbed audio hardware!");
+    if (!mPrimaryHardwareDev || mAudioHwDevs.size() == 0) {
+        LOGE("Primary audio interface not found");
+        return;
+    }
+
+    for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+        audio_hw_device_t *dev = mAudioHwDevs[i];
+
+        mHardwareStatus = AUDIO_HW_INIT;
+        rc = dev->init_check(dev);
+        if (rc == 0) {
+            AutoMutex lock(mHardwareLock);
+
+            mMode = AUDIO_MODE_NORMAL;
+            mHardwareStatus = AUDIO_HW_SET_MODE;
+            dev->set_mode(dev, mMode);
+            mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+            dev->set_master_volume(dev, 1.0f);
+            mHardwareStatus = AUDIO_HW_IDLE;
+        }
     }
 }
 
 AudioFlinger::~AudioFlinger()
 {
+    int num_devs = mAudioHwDevs.size();
+
     while (!mRecordThreads.isEmpty()) {
         // closeInput() will remove first entry from mRecordThreads
         closeInput(mRecordThreads.keyAt(0));
@@ -187,12 +236,24 @@
         // closeOutput() will remove first entry from mPlaybackThreads
         closeOutput(mPlaybackThreads.keyAt(0));
     }
-    if (mAudioHardwareDev) {
-        audio_hw_device_close(mAudioHardwareDev);
+
+    for (int i = 0; i < num_devs; i++) {
+        audio_hw_device_t *dev = mAudioHwDevs[i];
+        audio_hw_device_close(dev);
     }
+    mAudioHwDevs.clear();
 }
 
-
+audio_hw_device_t* AudioFlinger::findSuitableHwDev_l(uint32_t devices)
+{
+    /* first matching HW device is returned */
+    for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+        audio_hw_device_t *dev = mAudioHwDevs[i];
+        if ((dev->get_supported_devices(dev) & devices) == devices)
+            return dev;
+    }
+    return NULL;
+}
 
 status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
 {
@@ -291,8 +352,10 @@
             mRecordThreads.valueAt(i)->dump(fd, args);
         }
 
-        if (mAudioHardwareDev) {
-            mAudioHardwareDev->dump(mAudioHardwareDev, fd);
+        // dump all hardware devs
+        for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+            audio_hw_device_t *dev = mAudioHwDevs[i];
+            dev->dump(dev, fd);
         }
         if (locked) mLock.unlock();
     }
@@ -468,7 +531,7 @@
     { // scope for the lock
         AutoMutex lock(mHardwareLock);
         mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
-        if (mAudioHardwareDev->set_master_volume(mAudioHardwareDev, value) == NO_ERROR) {
+        if (mPrimaryHardwareDev->set_master_volume(mPrimaryHardwareDev, value) == NO_ERROR) {
             value = 1.0f;
         }
         mHardwareStatus = AUDIO_HW_IDLE;
@@ -498,7 +561,7 @@
     { // scope for the lock
         AutoMutex lock(mHardwareLock);
         mHardwareStatus = AUDIO_HW_SET_MODE;
-        ret = mAudioHardwareDev->set_mode(mAudioHardwareDev, mode);
+        ret = mPrimaryHardwareDev->set_mode(mPrimaryHardwareDev, mode);
         mHardwareStatus = AUDIO_HW_IDLE;
     }
 
@@ -521,7 +584,7 @@
 
     AutoMutex lock(mHardwareLock);
     mHardwareStatus = AUDIO_HW_SET_MIC_MUTE;
-    status_t ret = mAudioHardwareDev->set_mic_mute(mAudioHardwareDev, state);
+    status_t ret = mPrimaryHardwareDev->set_mic_mute(mPrimaryHardwareDev, state);
     mHardwareStatus = AUDIO_HW_IDLE;
     return ret;
 }
@@ -530,7 +593,7 @@
 {
     bool state = AUDIO_MODE_INVALID;
     mHardwareStatus = AUDIO_HW_GET_MIC_MUTE;
-    mAudioHardwareDev->get_mic_mute(mAudioHardwareDev, &state);
+    mPrimaryHardwareDev->get_mic_mute(mPrimaryHardwareDev, &state);
     mHardwareStatus = AUDIO_HW_IDLE;
     return state;
 }
@@ -658,9 +721,14 @@
     if (ioHandle == 0) {
         AutoMutex lock(mHardwareLock);
         mHardwareStatus = AUDIO_SET_PARAMETER;
-        result = mAudioHardwareDev->set_parameters(mAudioHardwareDev, keyValuePairs.string());
+        status_t final_result = NO_ERROR;
+        for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+            audio_hw_device_t *dev = mAudioHwDevs[i];
+            result = dev->set_parameters(dev, keyValuePairs.string());
+            final_result = result ?: final_result;
+        }
         mHardwareStatus = AUDIO_HW_IDLE;
-        return result;
+        return final_result;
     }
 
     // hold a strong ref on thread in case closeOutput() or closeInput() is called
@@ -686,12 +754,14 @@
 //            ioHandle, keys.string(), gettid(), IPCThreadState::self()->getCallingPid());
 
     if (ioHandle == 0) {
-        char *s;
         String8 out_s8;
 
-        s = mAudioHardwareDev->get_parameters(mAudioHardwareDev, keys.string());
-        out_s8 = String8(s);
-        free(s);
+        for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+            audio_hw_device_t *dev = mAudioHwDevs[i];
+            char *s = dev->get_parameters(dev, keys.string());
+            out_s8 += String8(s);
+            free(s);
+        }
         return out_s8;
     }
 
@@ -710,7 +780,7 @@
 
 size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
 {
-    return mAudioHardwareDev->get_input_buffer_size(mAudioHardwareDev, sampleRate, format, channelCount);
+    return mPrimaryHardwareDev->get_input_buffer_size(mPrimaryHardwareDev, sampleRate, format, channelCount);
 }
 
 unsigned int AudioFlinger::getInputFramesLost(int ioHandle)
@@ -737,7 +807,7 @@
 
     AutoMutex lock(mHardwareLock);
     mHardwareStatus = AUDIO_SET_VOICE_VOLUME;
-    status_t ret = mAudioHardwareDev->set_voice_volume(mAudioHardwareDev, value);
+    status_t ret = mPrimaryHardwareDev->set_voice_volume(mPrimaryHardwareDev, value);
     mHardwareStatus = AUDIO_HW_IDLE;
 
     return ret;
@@ -977,7 +1047,7 @@
 
 // ----------------------------------------------------------------------------
 
-AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger, struct audio_stream_out* output, int id, uint32_t device)
+AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device)
     :   ThreadBase(audioFlinger, id),
         mMixBuffer(0), mSuspended(0), mBytesWritten(0), mOutput(output),
         mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false),
@@ -1190,7 +1260,7 @@
 uint32_t AudioFlinger::PlaybackThread::latency() const
 {
     if (mOutput) {
-        return mOutput->get_latency(mOutput);
+        return mOutput->stream->get_latency(mOutput->stream);
     }
     else {
         return 0;
@@ -1287,7 +1357,7 @@
     String8 out_s8;
     char *s;
 
-    s = mOutput->common.get_parameters(&mOutput->common, keys.string());
+    s = mOutput->stream->common.get_parameters(&mOutput->stream->common, keys.string());
     out_s8 = String8(s);
     free(s);
     return out_s8;
@@ -1322,12 +1392,12 @@
 
 void AudioFlinger::PlaybackThread::readOutputParameters()
 {
-    mSampleRate = mOutput->common.get_sample_rate(&mOutput->common);
-    mChannels = mOutput->common.get_channels(&mOutput->common);
+    mSampleRate = mOutput->stream->common.get_sample_rate(&mOutput->stream->common);
+    mChannels = mOutput->stream->common.get_channels(&mOutput->stream->common);
     mChannelCount = (uint16_t)popcount(mChannels);
-    mFormat = mOutput->common.get_format(&mOutput->common);
-    mFrameSize = (uint16_t)audio_stream_frame_size(&mOutput->common);
-    mFrameCount = mOutput->common.get_buffer_size(&mOutput->common) / mFrameSize;
+    mFormat = mOutput->stream->common.get_format(&mOutput->stream->common);
+    mFrameSize = (uint16_t)audio_stream_frame_size(&mOutput->stream->common);
+    mFrameCount = mOutput->stream->common.get_buffer_size(&mOutput->stream->common) / mFrameSize;
 
     // FIXME - Current mixer implementation only supports stereo output: Always
     // Allocate a stereo buffer even if HW output is mono.
@@ -1355,9 +1425,9 @@
     if (mOutput == 0) {
         return INVALID_OPERATION;
     }
-    *halFrames = mBytesWritten / audio_stream_frame_size(&mOutput->common);
+    *halFrames = mBytesWritten / audio_stream_frame_size(&mOutput->stream->common);
 
-    return mOutput->get_render_position(mOutput, dspFrames);
+    return mOutput->stream->get_render_position(mOutput->stream, dspFrames);
 }
 
 uint32_t AudioFlinger::PlaybackThread::hasAudioSession(int sessionId)
@@ -1428,7 +1498,7 @@
 
 // ----------------------------------------------------------------------------
 
-AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, struct audio_stream_out* output, int id, uint32_t device)
+AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device)
     :   PlaybackThread(audioFlinger, output, id, device),
         mAudioMixer(0)
 {
@@ -1487,7 +1557,7 @@
                         mSuspended) {
                 if (!mStandby) {
                     LOGV("Audio hardware entering standby, mixer %p, mSuspended %d\n", this, mSuspended);
-                    mOutput->common.standby(&mOutput->common);
+                    mOutput->stream->common.standby(&mOutput->stream->common);
                     mStandby = true;
                     mBytesWritten = 0;
                 }
@@ -1564,7 +1634,7 @@
             mInWrite = true;
             mBytesWritten += mixBufferSize;
 
-            int bytesWritten = (int)mOutput->write(mOutput, mMixBuffer, mixBufferSize);
+            int bytesWritten = (int)mOutput->stream->write(mOutput->stream, mMixBuffer, mixBufferSize);
             if (bytesWritten < 0) mBytesWritten -= mixBufferSize;
             mNumWrites++;
             mInWrite = false;
@@ -1599,7 +1669,7 @@
     }
 
     if (!mStandby) {
-        mOutput->common.standby(&mOutput->common);
+        mOutput->stream->common.standby(&mOutput->stream->common);
     }
 
     LOGV("MixerThread %p exiting", this);
@@ -1903,13 +1973,13 @@
         }
 
         if (status == NO_ERROR) {
-            status = mOutput->common.set_parameters(&mOutput->common,
+            status = mOutput->stream->common.set_parameters(&mOutput->stream->common,
                                                     keyValuePair.string());
             if (!mStandby && status == INVALID_OPERATION) {
-               mOutput->common.standby(&mOutput->common);
+               mOutput->stream->common.standby(&mOutput->stream->common);
                mStandby = true;
                mBytesWritten = 0;
-               status = mOutput->common.set_parameters(&mOutput->common,
+               status = mOutput->stream->common.set_parameters(&mOutput->stream->common,
                                                        keyValuePair.string());
             }
             if (status == NO_ERROR && reconfig) {
@@ -1954,7 +2024,7 @@
 
 uint32_t AudioFlinger::MixerThread::activeSleepTimeUs()
 {
-    return (uint32_t)(mOutput->get_latency(mOutput) * 1000) / 2;
+    return (uint32_t)(mOutput->stream->get_latency(mOutput->stream) * 1000) / 2;
 }
 
 uint32_t AudioFlinger::MixerThread::idleSleepTimeUs()
@@ -1968,7 +2038,7 @@
 }
 
 // ----------------------------------------------------------------------------
-AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger, struct audio_stream_out* output, int id, uint32_t device)
+AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device)
     :   PlaybackThread(audioFlinger, output, id, device)
 {
     mType = PlaybackThread::DIRECT;
@@ -2118,7 +2188,7 @@
                 // wait until we have something to do...
                 if (!mStandby) {
                     LOGV("Audio hardware entering standby, mixer %p\n", this);
-                    mOutput->common.standby(&mOutput->common);
+                    mOutput->stream->common.standby(&mOutput->stream->common);
                     mStandby = true;
                     mBytesWritten = 0;
                 }
@@ -2203,7 +2273,7 @@
 
                         // If audio HAL implements volume control,
                         // force software volume to nominal value
-                        if (mOutput->set_volume(mOutput, left, right) == NO_ERROR) {
+                        if (mOutput->stream->set_volume(mOutput->stream, left, right) == NO_ERROR) {
                             left = 1.0f;
                             right = 1.0f;
                         }
@@ -2326,7 +2396,7 @@
             mLastWriteTime = systemTime();
             mInWrite = true;
             mBytesWritten += mixBufferSize;
-            int bytesWritten = (int)mOutput->write(mOutput, mMixBuffer, mixBufferSize);
+            int bytesWritten = (int)mOutput->stream->write(mOutput->stream, mMixBuffer, mixBufferSize);
             if (bytesWritten < 0) mBytesWritten -= mixBufferSize;
             mNumWrites++;
             mInWrite = false;
@@ -2348,7 +2418,7 @@
     }
 
     if (!mStandby) {
-        mOutput->common.standby(&mOutput->common);
+        mOutput->stream->common.standby(&mOutput->stream->common);
     }
 
     LOGV("DirectOutputThread %p exiting", this);
@@ -2388,13 +2458,13 @@
             }
         }
         if (status == NO_ERROR) {
-            status = mOutput->common.set_parameters(&mOutput->common,
+            status = mOutput->stream->common.set_parameters(&mOutput->stream->common,
                                                     keyValuePair.string());
             if (!mStandby && status == INVALID_OPERATION) {
-               mOutput->common.standby(&mOutput->common);
+               mOutput->stream->common.standby(&mOutput->stream->common);
                mStandby = true;
                mBytesWritten = 0;
-               status = mOutput->common.set_parameters(&mOutput->common,
+               status = mOutput->stream->common.set_parameters(&mOutput->stream->common,
                                                        keyValuePair.string());
             }
             if (status == NO_ERROR && reconfig) {
@@ -2416,7 +2486,7 @@
 {
     uint32_t time;
     if (audio_is_linear_pcm(mFormat)) {
-        time = (uint32_t)(mOutput->get_latency(mOutput) * 1000) / 2;
+        time = (uint32_t)(mOutput->stream->get_latency(mOutput->stream) * 1000) / 2;
     } else {
         time = 10000;
     }
@@ -3705,7 +3775,7 @@
 
 // ----------------------------------------------------------------------------
 
-AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, struct audio_stream_in *input, uint32_t sampleRate, uint32_t channels, int id) :
+AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, AudioStreamIn *input, uint32_t sampleRate, uint32_t channels, int id) :
     ThreadBase(audioFlinger, id),
     mInput(input), mResampler(0), mRsmpOutBuffer(0), mRsmpInBuffer(0)
 {
@@ -3751,7 +3821,7 @@
             checkForNewParameters_l();
             if (mActiveTrack == 0 && mConfigEvents.isEmpty()) {
                 if (!mStandby) {
-                    mInput->common.standby(&mInput->common);
+                    mInput->stream->common.standby(&mInput->stream->common);
                     mStandby = true;
                 }
 
@@ -3766,7 +3836,7 @@
             if (mActiveTrack != 0) {
                 if (mActiveTrack->mState == TrackBase::PAUSING) {
                     if (!mStandby) {
-                        mInput->common.standby(&mInput->common);
+                        mInput->stream->common.standby(&mInput->stream->common);
                         mStandby = true;
                     }
                     mActiveTrack.clear();
@@ -3832,10 +3902,10 @@
                         if (framesOut && mFrameCount == mRsmpInIndex) {
                             if (framesOut == mFrameCount &&
                                 ((int)mChannelCount == mReqChannelCount || mFormat != AUDIO_FORMAT_PCM_16_BIT)) {
-                                mBytesRead = mInput->read(mInput, buffer.raw, mInputBytes);
+                                mBytesRead = mInput->stream->read(mInput->stream, buffer.raw, mInputBytes);
                                 framesOut = 0;
                             } else {
-                                mBytesRead = mInput->read(mInput, mRsmpInBuffer, mInputBytes);
+                                mBytesRead = mInput->stream->read(mInput->stream, mRsmpInBuffer, mInputBytes);
                                 mRsmpInIndex = 0;
                             }
                             if (mBytesRead < 0) {
@@ -3843,7 +3913,7 @@
                                 if (mActiveTrack->mState == TrackBase::ACTIVE) {
                                     // Force input into standby so that it tries to
                                     // recover at next read attempt
-                                    mInput->common.standby(&mInput->common);
+                                    mInput->stream->common.standby(&mInput->stream->common);
                                     usleep(5000);
                                 }
                                 mRsmpInIndex = mFrameCount;
@@ -3898,7 +3968,7 @@
     }
 
     if (!mStandby) {
-        mInput->common.standby(&mInput->common);
+        mInput->stream->common.standby(&mInput->stream->common);
     }
     mActiveTrack.clear();
 
@@ -4030,13 +4100,13 @@
     int channelCount;
 
     if (framesReady == 0) {
-        mBytesRead = mInput->read(mInput, mRsmpInBuffer, mInputBytes);
+        mBytesRead = mInput->stream->read(mInput->stream, mRsmpInBuffer, mInputBytes);
         if (mBytesRead < 0) {
             LOGE("RecordThread::getNextBuffer() Error reading audio input");
             if (mActiveTrack->mState == TrackBase::ACTIVE) {
                 // Force input into standby so that it tries to
                 // recover at next read attempt
-                mInput->common.standby(&mInput->common);
+                mInput->stream->common.standby(&mInput->stream->common);
                 usleep(5000);
             }
             buffer->raw = 0;
@@ -4103,17 +4173,17 @@
             }
         }
         if (status == NO_ERROR) {
-            status = mInput->common.set_parameters(&mInput->common, keyValuePair.string());
+            status = mInput->stream->common.set_parameters(&mInput->stream->common, keyValuePair.string());
             if (status == INVALID_OPERATION) {
-               mInput->common.standby(&mInput->common);
-               status = mInput->common.set_parameters(&mInput->common, keyValuePair.string());
+               mInput->stream->common.standby(&mInput->stream->common);
+               status = mInput->stream->common.set_parameters(&mInput->stream->common, keyValuePair.string());
             }
             if (reconfig) {
                 if (status == BAD_VALUE &&
-                    reqFormat == mInput->common.get_format(&mInput->common) &&
+                    reqFormat == mInput->stream->common.get_format(&mInput->stream->common) &&
                     reqFormat == AUDIO_FORMAT_PCM_16_BIT &&
-                    ((int)mInput->common.get_sample_rate(&mInput->common) <= (2 * reqSamplingRate)) &&
-                    (popcount(mInput->common.get_channels(&mInput->common)) < 3) &&
+                    ((int)mInput->stream->common.get_sample_rate(&mInput->stream->common) <= (2 * reqSamplingRate)) &&
+                    (popcount(mInput->stream->common.get_channels(&mInput->stream->common)) < 3) &&
                     (reqChannelCount < 3)) {
                     status = NO_ERROR;
                 }
@@ -4138,7 +4208,7 @@
     char *s;
     String8 out_s8;
 
-    s = mInput->common.get_parameters(&mInput->common, keys.string());
+    s = mInput->stream->common.get_parameters(&mInput->stream->common, keys.string());
     out_s8 = String8(s);
     free(s);
     return out_s8;
@@ -4173,12 +4243,12 @@
     if (mResampler) delete mResampler;
     mResampler = 0;
 
-    mSampleRate = mInput->common.get_sample_rate(&mInput->common);
-    mChannels = mInput->common.get_channels(&mInput->common);
+    mSampleRate = mInput->stream->common.get_sample_rate(&mInput->stream->common);
+    mChannels = mInput->stream->common.get_channels(&mInput->stream->common);
     mChannelCount = (uint16_t)popcount(mChannels);
-    mFormat = mInput->common.get_format(&mInput->common);
-    mFrameSize = (uint16_t)audio_stream_frame_size(&mInput->common);
-    mInputBytes = mInput->common.get_buffer_size(&mInput->common);
+    mFormat = mInput->stream->common.get_format(&mInput->stream->common);
+    mFrameSize = (uint16_t)audio_stream_frame_size(&mInput->stream->common);
+    mInputBytes = mInput->stream->common.get_buffer_size(&mInput->stream->common);
     mFrameCount = mInputBytes / mFrameSize;
     mRsmpInBuffer = new int16_t[mFrameCount * mChannelCount];
 
@@ -4208,7 +4278,7 @@
 
 unsigned int AudioFlinger::RecordThread::getInputFramesLost()
 {
-    return mInput->get_input_frames_lost(mInput);
+    return mInput->stream->get_input_frames_lost(mInput->stream);
 }
 
 // ----------------------------------------------------------------------------
@@ -4227,7 +4297,8 @@
     uint32_t format = pFormat ? *pFormat : 0;
     uint32_t channels = pChannels ? *pChannels : 0;
     uint32_t latency = pLatencyMs ? *pLatencyMs : 0;
-    struct audio_stream_out *output;
+    audio_stream_out_t *outStream;
+    audio_hw_device_t *outHwDev;
 
     LOGV("openOutput(), Device %x, SamplingRate %d, Format %d, Channels %x, flags %x",
             pDevices ? *pDevices : 0,
@@ -4239,23 +4310,27 @@
     if (pDevices == NULL || *pDevices == 0) {
         return 0;
     }
+
     Mutex::Autolock _l(mLock);
 
-    status = mAudioHardwareDev->open_output_stream(mAudioHardwareDev, *pDevices,
-                                                   (int *)&format,
-                                                   &channels,
-                                                   &samplingRate,
-                                                   &output);
+    outHwDev = findSuitableHwDev_l(*pDevices);
+    if (outHwDev == NULL)
+        return 0;
+
+    status = outHwDev->open_output_stream(outHwDev, *pDevices, (int *)&format,
+                                          &channels, &samplingRate, &outStream);
     LOGV("openOutput() openOutputStream returned output %p, SamplingRate %d, Format %d, Channels %x, status %d",
-            output,
+            outStream,
             samplingRate,
             format,
             channels,
             status);
 
     mHardwareStatus = AUDIO_HW_IDLE;
-    if (output != 0) {
+    if (outStream != NULL) {
+        AudioStreamOut *output = new AudioStreamOut(outHwDev, outStream);
         int id = nextUniqueId_l();
+
         if ((flags & AUDIO_POLICY_OUTPUT_FLAG_DIRECT) ||
             (format != AUDIO_FORMAT_PCM_16_BIT) ||
             (channels != AUDIO_CHANNEL_OUT_STEREO)) {
@@ -4329,7 +4404,9 @@
     thread->exit();
 
     if (thread->type() != PlaybackThread::DUPLICATING) {
-        mAudioHardwareDev->close_output_stream(mAudioHardwareDev, thread->getOutput());
+        AudioStreamOut *out = thread->getOutput();
+        out->hwDev->close_output_stream(out->hwDev, out->stream);
+        delete out;
     }
     return NO_ERROR;
 }
@@ -4379,22 +4456,25 @@
     uint32_t reqSamplingRate = samplingRate;
     uint32_t reqFormat = format;
     uint32_t reqChannels = channels;
-    struct audio_stream_in *input;
+    audio_stream_in_t *inStream;
+    audio_hw_device_t *inHwDev;
 
     if (pDevices == NULL || *pDevices == 0) {
         return 0;
     }
+
     Mutex::Autolock _l(mLock);
 
-    status = mAudioHardwareDev->open_input_stream(mAudioHardwareDev,
-                                        *pDevices,
-                                        (int *)&format,
-                                        &channels,
-                                        &samplingRate,
+    inHwDev = findSuitableHwDev_l(*pDevices);
+    if (inHwDev == NULL)
+        return 0;
+
+    status = inHwDev->open_input_stream(inHwDev, *pDevices, (int *)&format,
+                                        &channels, &samplingRate,
                                         (audio_in_acoustics_t)acoustics,
-                                        &input);
+                                        &inStream);
     LOGV("openInput() openInputStream returned input %p, SamplingRate %d, Format %d, Channels %x, acoustics %x, status %d",
-            input,
+            inStream,
             samplingRate,
             format,
             channels,
@@ -4404,21 +4484,20 @@
     // If the input could not be opened with the requested parameters and we can handle the conversion internally,
     // try to open again with the proposed parameters. The AudioFlinger can resample the input and do mono to stereo
     // or stereo to mono conversions on 16 bit PCM inputs.
-    if (input == 0 && status == BAD_VALUE &&
+    if (inStream == NULL && status == BAD_VALUE &&
         reqFormat == format && format == AUDIO_FORMAT_PCM_16_BIT &&
         (samplingRate <= 2 * reqSamplingRate) &&
         (popcount(channels) < 3) && (popcount(reqChannels) < 3)) {
         LOGV("openInput() reopening with proposed sampling rate and channels");
-        status = mAudioHardwareDev->open_input_stream(mAudioHardwareDev,
-                                            *pDevices,
-                                            (int *)&format,
-                                            &channels,
-                                            &samplingRate,
+        status = inHwDev->open_input_stream(inHwDev, *pDevices, (int *)&format,
+                                            &channels, &samplingRate,
                                             (audio_in_acoustics_t)acoustics,
-                                            &input);
+                                            &inStream);
     }
 
-    if (input != 0) {
+    if (inStream != NULL) {
+        AudioStreamIn *input = new AudioStreamIn(inHwDev, inStream);
+
         int id = nextUniqueId_l();
          // Start record thread
         thread = new RecordThread(this, input, reqSamplingRate, reqChannels, id);
@@ -4428,7 +4507,7 @@
         if (pFormat) *pFormat = format;
         if (pChannels) *pChannels = reqChannels;
 
-        input->common.standby(&input->common);
+        input->stream->common.standby(&input->stream->common);
 
         // notify client processes of the new input creation
         thread->audioConfigChanged_l(AudioSystem::INPUT_OPENED);
@@ -4457,7 +4536,9 @@
     }
     thread->exit();
 
-    mAudioHardwareDev->close_input_stream(mAudioHardwareDev, thread->getInput());
+    AudioStreamIn *in = thread->getInput();
+    in->hwDev->close_input_stream(in->hwDev, in->stream);
+    delete in;
 
     return NO_ERROR;
 }
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 4ac1ee3..94f7861 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -32,12 +32,14 @@
 #include <utils/Errors.h>
 #include <utils/threads.h>
 #include <utils/SortedVector.h>
+#include <utils/TypeHelpers.h>
 #include <utils/Vector.h>
 
 #include <binder/BinderService.h>
 #include <binder/MemoryDealer.h>
 
 #include <hardware/audio.h>
+#include <hardware/audio_hal.h>
 
 #include "AudioBufferProvider.h"
 
@@ -49,7 +51,6 @@
 class AudioBuffer;
 class AudioResampler;
 
-
 // ----------------------------------------------------------------------------
 
 #define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
@@ -211,6 +212,7 @@
                             AudioFlinger();
     virtual                 ~AudioFlinger();
 
+    audio_hw_device_t*      findSuitableHwDev_l(uint32_t devices);
 
     // Internal dump utilites.
     status_t dumpPermissionDenial(int fd, const Vector<String16>& args);
@@ -268,6 +270,8 @@
     class EffectModule;
     class EffectHandle;
     class EffectChain;
+    struct AudioStreamOut;
+    struct AudioStreamIn;
 
     class ThreadBase : public Thread {
     public:
@@ -554,7 +558,7 @@
             DuplicatingThread*          mSourceThread;
         };  // end of OutputTrack
 
-        PlaybackThread (const sp<AudioFlinger>& audioFlinger, struct audio_stream_out* output, int id, uint32_t device);
+        PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device);
         virtual             ~PlaybackThread();
 
         virtual     status_t    dump(int fd, const Vector<String16>& args);
@@ -588,7 +592,7 @@
                                     int sessionId,
                                     status_t *status);
 
-                    struct audio_stream_out* getOutput() { return mOutput; }
+                    AudioStreamOut* getOutput() { return mOutput; }
 
         virtual     int         type() const { return mType; }
                     void        suspend() { mSuspended++; }
@@ -690,7 +694,7 @@
         SortedVector< sp<Track> >       mTracks;
         // mStreamTypes[] uses 1 additionnal stream type internally for the OutputTrack used by DuplicatingThread
         stream_type_t                   mStreamTypes[AUDIO_STREAM_CNT + 1];
-        struct audio_stream_out*        mOutput;
+        AudioStreamOut*                 mOutput;
         float                           mMasterVolume;
         nsecs_t                         mLastWriteTime;
         int                             mNumWrites;
@@ -703,7 +707,7 @@
     class MixerThread : public PlaybackThread {
     public:
         MixerThread (const sp<AudioFlinger>& audioFlinger,
-                     struct audio_stream_out* output,
+                     AudioStreamOut* output,
                      int id,
                      uint32_t device);
         virtual             ~MixerThread();
@@ -730,7 +734,7 @@
     class DirectOutputThread : public PlaybackThread {
     public:
 
-        DirectOutputThread (const sp<AudioFlinger>& audioFlinger, struct audio_stream_out* output, int id, uint32_t device);
+        DirectOutputThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device);
         ~DirectOutputThread();
 
         // Thread virtuals
@@ -854,7 +858,7 @@
 
 
                 RecordThread(const sp<AudioFlinger>& audioFlinger,
-                        struct audio_stream_in *input,
+                        AudioStreamIn *input,
                         uint32_t sampleRate,
                         uint32_t channels,
                         int id);
@@ -867,7 +871,7 @@
                 status_t    start(RecordTrack* recordTrack);
                 void        stop(RecordTrack* recordTrack);
                 status_t    dump(int fd, const Vector<String16>& args);
-                struct audio_stream_in* getInput() { return mInput; }
+                AudioStreamIn* getInput() { return mInput; }
 
         virtual status_t    getNextBuffer(AudioBufferProvider::Buffer* buffer);
         virtual void        releaseBuffer(AudioBufferProvider::Buffer* buffer);
@@ -879,7 +883,7 @@
 
     private:
                 RecordThread();
-                struct audio_stream_in              *mInput;
+                AudioStreamIn                       *mInput;
                 sp<RecordTrack>                     mActiveTrack;
                 Condition                           mStartStopCond;
                 AudioResampler                      *mResampler;
@@ -1159,17 +1163,32 @@
         uint32_t mStrategy; // strategy for this effect chain
     };
 
+    struct AudioStreamOut {
+        audio_hw_device_t   *hwDev;
+        audio_stream_out_t  *stream;
+
+        AudioStreamOut(audio_hw_device_t *dev, audio_stream_out_t *out) :
+            hwDev(dev), stream(out) {}
+    };
+
+    struct AudioStreamIn {
+        audio_hw_device_t   *hwDev;
+        audio_stream_in_t   *stream;
+
+        AudioStreamIn(audio_hw_device_t *dev, audio_stream_in_t *in) :
+            hwDev(dev), stream(in) {}
+    };
+
     friend class RecordThread;
     friend class PlaybackThread;
 
-
     mutable     Mutex                               mLock;
 
                 DefaultKeyedVector< pid_t, wp<Client> >     mClients;
 
                 mutable     Mutex                   mHardwareLock;
-                struct audio_hw_device*             mAudioHardwareDev;
-                Vector<struct audio_hw_device *>    mAudioHwDevs;
+                audio_hw_device_t*                  mPrimaryHardwareDev;
+                Vector<audio_hw_device_t*>          mAudioHwDevs;
     mutable     int                                 mHardwareStatus;
 
 
@@ -1186,6 +1205,7 @@
 
 };
 
+
 // ----------------------------------------------------------------------------
 
 }; // namespace android