audio policy: load audio hw modules.

Audio HW modules are now loaded upon request from audio policy manager
according to the configuration in audio_policy.conf.
Removed hard coded HW module loading by AudioFlinger at init time.
Added methods to IAudioFlinger and AudioPolicyInterface
to control the loading of audio HW modules.
Added methods to open an output or input stream on a specific hw module.

Change-Id: I361b294ece1a9b56b2fb39cc64259dbb73b804f4
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 8239b0e..9e938d1 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -29,6 +29,7 @@
 #include <media/IAudioFlingerClient.h>
 #include <system/audio.h>
 #include <system/audio_policy.h>
+#include <hardware/audio_policy.h>
 #include <hardware/audio_effect.h>
 #include <media/IEffect.h>
 #include <media/IEffectClient.h>
@@ -126,23 +127,24 @@
     // retrieve the audio recording buffer size
     virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount) const = 0;
 
-    virtual audio_io_handle_t openOutput(uint32_t *pDevices,
-                                    uint32_t *pSamplingRate,
-                                    audio_format_t *pFormat,
-                                    uint32_t *pChannels,
-                                    uint32_t *pLatencyMs,
-                                    audio_policy_output_flags_t flags) = 0;
+    virtual audio_io_handle_t openOutput(audio_module_handle_t module,
+                                         audio_devices_t *pDevices,
+                                         uint32_t *pSamplingRate,
+                                         audio_format_t *pFormat,
+                                         audio_channel_mask_t *pChannelMask,
+                                         uint32_t *pLatencyMs,
+                                         audio_policy_output_flags_t flags) = 0;
     virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1,
                                     audio_io_handle_t output2) = 0;
     virtual status_t closeOutput(audio_io_handle_t output) = 0;
     virtual status_t suspendOutput(audio_io_handle_t output) = 0;
     virtual status_t restoreOutput(audio_io_handle_t output) = 0;
 
-    virtual audio_io_handle_t openInput(uint32_t *pDevices,
-                                    uint32_t *pSamplingRate,
-                                    audio_format_t *pFormat,
-                                    uint32_t *pChannels,
-                                    audio_in_acoustics_t acoustics) = 0;
+    virtual audio_io_handle_t openInput(audio_module_handle_t module,
+                                        audio_devices_t *pDevices,
+                                        uint32_t *pSamplingRate,
+                                        audio_format_t *pFormat,
+                                        audio_channel_mask_t *pChannelMask) = 0;
     virtual status_t closeInput(audio_io_handle_t input) = 0;
 
     virtual status_t setStreamOutput(audio_stream_type_t stream, audio_io_handle_t output) = 0;
@@ -178,6 +180,8 @@
 
     virtual status_t moveEffects(int session, audio_io_handle_t srcOutput,
                                     audio_io_handle_t dstOutput) = 0;
+
+    virtual audio_module_handle_t loadHwModule(const char *name) = 0;
 };
 
 
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index ce10c8e..81e259a 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -69,7 +69,8 @@
     QUERY_EFFECT,
     GET_EFFECT_DESCRIPTOR,
     CREATE_EFFECT,
-    MOVE_EFFECTS
+    MOVE_EFFECTS,
+    LOAD_HW_MODULE
 };
 
 class BpAudioFlinger : public BpInterface<IAudioFlinger>
@@ -355,38 +356,40 @@
         return reply.readInt32();
     }
 
-    virtual audio_io_handle_t openOutput(uint32_t *pDevices,
-                            uint32_t *pSamplingRate,
-                            audio_format_t *pFormat,
-                            uint32_t *pChannels,
-                            uint32_t *pLatencyMs,
-                            audio_policy_output_flags_t flags)
+    virtual audio_io_handle_t openOutput(audio_module_handle_t module,
+                                         audio_devices_t *pDevices,
+                                         uint32_t *pSamplingRate,
+                                         audio_format_t *pFormat,
+                                         audio_channel_mask_t *pChannelMask,
+                                         uint32_t *pLatencyMs,
+                                         audio_policy_output_flags_t flags)
     {
         Parcel data, reply;
-        uint32_t devices = pDevices ? *pDevices : 0;
+        audio_devices_t devices = pDevices ? *pDevices : (audio_devices_t)0;
         uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;
         audio_format_t format = pFormat ? *pFormat : AUDIO_FORMAT_DEFAULT;
-        uint32_t channels = pChannels ? *pChannels : 0;
+        audio_channel_mask_t channelMask = pChannelMask ? *pChannelMask : (audio_channel_mask_t)0;
         uint32_t latency = pLatencyMs ? *pLatencyMs : 0;
 
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(module);
         data.writeInt32(devices);
         data.writeInt32(samplingRate);
         data.writeInt32(format);
-        data.writeInt32(channels);
+        data.writeInt32(channelMask);
         data.writeInt32(latency);
         data.writeInt32((int32_t) flags);
         remote()->transact(OPEN_OUTPUT, data, &reply);
         audio_io_handle_t output = (audio_io_handle_t) reply.readInt32();
         ALOGV("openOutput() returned output, %d", output);
-        devices = reply.readInt32();
+        devices = (audio_devices_t)reply.readInt32();
         if (pDevices) *pDevices = devices;
         samplingRate = reply.readInt32();
         if (pSamplingRate) *pSamplingRate = samplingRate;
         format = (audio_format_t) reply.readInt32();
         if (pFormat) *pFormat = format;
-        channels = reply.readInt32();
-        if (pChannels) *pChannels = channels;
+        channelMask = (audio_channel_mask_t)reply.readInt32();
+        if (pChannelMask) *pChannelMask = channelMask;
         latency = reply.readInt32();
         if (pLatencyMs) *pLatencyMs = latency;
         return output;
@@ -430,34 +433,34 @@
         return reply.readInt32();
     }
 
-    virtual audio_io_handle_t openInput(uint32_t *pDevices,
-                            uint32_t *pSamplingRate,
-                            audio_format_t *pFormat,
-                            uint32_t *pChannels,
-                            audio_in_acoustics_t acoustics)
+    virtual audio_io_handle_t openInput(audio_module_handle_t module,
+                                        audio_devices_t *pDevices,
+                                        uint32_t *pSamplingRate,
+                                        audio_format_t *pFormat,
+                                        audio_channel_mask_t *pChannelMask)
     {
         Parcel data, reply;
-        uint32_t devices = pDevices ? *pDevices : 0;
+        audio_devices_t devices = pDevices ? *pDevices : (audio_devices_t)0;
         uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;
         audio_format_t format = pFormat ? *pFormat : AUDIO_FORMAT_DEFAULT;
-        uint32_t channels = pChannels ? *pChannels : 0;
+        audio_channel_mask_t channelMask = pChannelMask ? *pChannelMask : (audio_channel_mask_t)0;
 
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(module);
         data.writeInt32(devices);
         data.writeInt32(samplingRate);
         data.writeInt32(format);
-        data.writeInt32(channels);
-        data.writeInt32((int32_t) acoustics);
+        data.writeInt32(channelMask);
         remote()->transact(OPEN_INPUT, data, &reply);
         audio_io_handle_t input = (audio_io_handle_t) reply.readInt32();
-        devices = reply.readInt32();
+        devices = (audio_devices_t)reply.readInt32();
         if (pDevices) *pDevices = devices;
         samplingRate = reply.readInt32();
         if (pSamplingRate) *pSamplingRate = samplingRate;
         format = (audio_format_t) reply.readInt32();
         if (pFormat) *pFormat = format;
-        channels = reply.readInt32();
-        if (pChannels) *pChannels = channels;
+        channelMask = (audio_channel_mask_t)reply.readInt32();
+        if (pChannelMask) *pChannelMask = channelMask;
         return input;
     }
 
@@ -668,6 +671,15 @@
         remote()->transact(MOVE_EFFECTS, data, &reply);
         return reply.readInt32();
     }
+
+    virtual audio_module_handle_t loadHwModule(const char *name)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeCString(name);
+        remote()->transact(LOAD_HW_MODULE, data, &reply);
+        return (audio_module_handle_t) reply.readInt32();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger");
@@ -837,24 +849,26 @@
         } break;
         case OPEN_OUTPUT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            uint32_t devices = data.readInt32();
+            audio_module_handle_t module = (audio_module_handle_t)data.readInt32();
+            audio_devices_t devices = (audio_devices_t)data.readInt32();
             uint32_t samplingRate = data.readInt32();
             audio_format_t format = (audio_format_t) data.readInt32();
-            uint32_t channels = data.readInt32();
+            audio_channel_mask_t channelMask = (audio_channel_mask_t)data.readInt32();
             uint32_t latency = data.readInt32();
             audio_policy_output_flags_t flags = (audio_policy_output_flags_t) data.readInt32();
-            audio_io_handle_t output = openOutput(&devices,
-                                     &samplingRate,
-                                     &format,
-                                     &channels,
-                                     &latency,
-                                     flags);
+            audio_io_handle_t output = openOutput(module,
+                                                 &devices,
+                                                 &samplingRate,
+                                                 &format,
+                                                 &channelMask,
+                                                 &latency,
+                                                 flags);
             ALOGV("OPEN_OUTPUT output, %p", output);
             reply->writeInt32((int32_t) output);
             reply->writeInt32(devices);
             reply->writeInt32(samplingRate);
             reply->writeInt32(format);
-            reply->writeInt32(channels);
+            reply->writeInt32(channelMask);
             reply->writeInt32(latency);
             return NO_ERROR;
         } break;
@@ -882,22 +896,22 @@
         } break;
         case OPEN_INPUT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            uint32_t devices = data.readInt32();
+            audio_module_handle_t module = (audio_module_handle_t)data.readInt32();
+            audio_devices_t devices = (audio_devices_t)data.readInt32();
             uint32_t samplingRate = data.readInt32();
             audio_format_t format = (audio_format_t) data.readInt32();
-            uint32_t channels = data.readInt32();
-            audio_in_acoustics_t acoustics = (audio_in_acoustics_t) data.readInt32();
+            audio_channel_mask_t channelMask = (audio_channel_mask_t)data.readInt32();
 
-            audio_io_handle_t input = openInput(&devices,
-                                     &samplingRate,
-                                     &format,
-                                     &channels,
-                                     acoustics);
+            audio_io_handle_t input = openInput(module,
+                                             &devices,
+                                             &samplingRate,
+                                             &format,
+                                             &channelMask);
             reply->writeInt32((int32_t) input);
             reply->writeInt32(devices);
             reply->writeInt32(samplingRate);
             reply->writeInt32(format);
-            reply->writeInt32(channels);
+            reply->writeInt32(channelMask);
             return NO_ERROR;
         } break;
         case CLOSE_INPUT: {
@@ -1015,6 +1029,11 @@
             reply->writeInt32(moveEffects(session, srcOutput, dstOutput));
             return NO_ERROR;
         } break;
+        case LOAD_HW_MODULE: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            reply->writeInt32(loadHwModule(data.readCString()));
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index e926292..9e6a6df 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -149,13 +149,6 @@
     return rc;
 }
 
-static const char * const audio_interfaces[] = {
-    AUDIO_HARDWARE_MODULE_ID_PRIMARY,
-    AUDIO_HARDWARE_MODULE_ID_A2DP,
-    AUDIO_HARDWARE_MODULE_ID_USB,
-};
-#define ARRAY_SIZE(x) (sizeof((x))/sizeof(((x)[0])))
-
 // ----------------------------------------------------------------------------
 
 AudioFlinger::AudioFlinger()
@@ -191,87 +184,9 @@
         }
     }
 
-    for (size_t i = 0; i < ARRAY_SIZE(audio_interfaces); i++) {
-        const hw_module_t *mod;
-        audio_hw_device_t *dev;
-
-        rc = load_audio_interface(audio_interfaces[i], &mod, &dev);
-        if (rc)
-            continue;
-
-        ALOGI("Loaded %s audio interface from %s (%s)", audio_interfaces[i],
-            mod->name, mod->id);
-        mAudioHwDevs.push(dev);
-
-        if (mPrimaryHardwareDev == NULL) {
-            mPrimaryHardwareDev = dev;
-            ALOGI("Using '%s' (%s.%s) as the primary audio interface",
-                mod->name, mod->id, audio_interfaces[i]);
-        }
-    }
-
-    if (mPrimaryHardwareDev == NULL) {
-        ALOGE("Primary audio interface not found");
-        // proceed, all later accesses to mPrimaryHardwareDev verify it's safe with initCheck()
-    }
-
-    // Currently (mPrimaryHardwareDev == NULL) == (mAudioHwDevs.size() == 0), but the way the
-    // primary HW dev is selected can change so these conditions might not always be equivalent.
-    // When that happens, re-visit all the code that assumes this.
-
-    AutoMutex lock(mHardwareLock);
-
-    // Determine the level of master volume support the primary audio HAL has,
-    // and set the initial master volume at the same time.
-    float initialVolume = 1.0;
-    mMasterVolumeSupportLvl = MVS_NONE;
-    if (0 == mPrimaryHardwareDev->init_check(mPrimaryHardwareDev)) {
-        audio_hw_device_t *dev = mPrimaryHardwareDev;
-
-        mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME;
-        if ((NULL != dev->get_master_volume) &&
-            (NO_ERROR == dev->get_master_volume(dev, &initialVolume))) {
-            mMasterVolumeSupportLvl = MVS_FULL;
-        } else {
-            mMasterVolumeSupportLvl = MVS_SETONLY;
-            initialVolume = 1.0;
-        }
-
-        mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
-        if ((NULL == dev->set_master_volume) ||
-            (NO_ERROR != dev->set_master_volume(dev, initialVolume))) {
-            mMasterVolumeSupportLvl = MVS_NONE;
-        }
-        mHardwareStatus = AUDIO_HW_IDLE;
-    }
-
-    // Set the mode for each audio HAL, and try to set the initial volume (if
-    // supported) for all of the non-primary audio HALs.
-    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);
-        mHardwareStatus = AUDIO_HW_IDLE;
-        if (rc == 0) {
-            mMode = AUDIO_MODE_NORMAL;  // assigned multiple times with same value
-            mHardwareStatus = AUDIO_HW_SET_MODE;
-            dev->set_mode(dev, mMode);
-
-            if ((dev != mPrimaryHardwareDev) &&
-                (NULL != dev->set_master_volume)) {
-                mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
-                dev->set_master_volume(dev, initialVolume);
-            }
-
-            mHardwareStatus = AUDIO_HW_IDLE;
-        }
-    }
-
-    mMasterVolumeSW = (MVS_NONE == mMasterVolumeSupportLvl)
-                    ? initialVolume
-                    : 1.0;
-    mMasterVolume   = initialVolume;
+    mMode = AUDIO_MODE_NORMAL;
+    mMasterVolumeSW = 1.0;
+    mMasterVolume   = 1.0;
     mHardwareStatus = AUDIO_HW_IDLE;
 }
 
@@ -289,18 +204,41 @@
 
     for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
         // no mHardwareLock needed, as there are no other references to this
-        audio_hw_device_close(mAudioHwDevs[i]);
+        audio_hw_device_close(mAudioHwDevs.valueAt(i)->hwDevice());
+        delete mAudioHwDevs.valueAt(i);
     }
 }
 
-audio_hw_device_t* AudioFlinger::findSuitableHwDev_l(uint32_t devices)
+static const char * const audio_interfaces[] = {
+    AUDIO_HARDWARE_MODULE_ID_PRIMARY,
+    AUDIO_HARDWARE_MODULE_ID_A2DP,
+    AUDIO_HARDWARE_MODULE_ID_USB,
+};
+#define ARRAY_SIZE(x) (sizeof((x))/sizeof(((x)[0])))
+
+audio_hw_device_t* AudioFlinger::findSuitableHwDev_l(audio_module_handle_t module, uint32_t devices)
 {
-    /* first matching HW device is returned */
+    // if module is 0, the request comes from an old policy manager and we should load
+    // well known modules
+    if (module == 0) {
+        ALOGW("findSuitableHwDev_l() loading well know audio hw modules");
+        for (size_t i = 0; i < ARRAY_SIZE(audio_interfaces); i++) {
+            loadHwModule_l(audio_interfaces[i]);
+        }
+    } else {
+        // check a match for the requested module handle
+        AudioHwDevice *audioHwdevice = mAudioHwDevs.valueFor(module);
+        if (audioHwdevice != NULL) {
+            return audioHwdevice->hwDevice();
+        }
+    }
+    // then try to find a module supporting the requested device.
     for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
-        audio_hw_device_t *dev = mAudioHwDevs[i];
+        audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();
         if ((dev->get_supported_devices(dev) & devices) == devices)
             return dev;
     }
+
     return NULL;
 }
 
@@ -411,7 +349,7 @@
 
         // dump all hardware devs
         for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
-            audio_hw_device_t *dev = mAudioHwDevs[i];
+            audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();
             dev->dump(dev, fd);
         }
         if (locked) mLock.unlock();
@@ -610,11 +548,13 @@
 
     float swmv = value;
 
+    Mutex::Autolock _l(mLock);
+
     // when hw supports master volume, don't scale in sw mixer
     if (MVS_NONE != mMasterVolumeSupportLvl) {
         for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
             AutoMutex lock(mHardwareLock);
-            audio_hw_device_t *dev = mAudioHwDevs[i];
+            audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();
 
             mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
             if (NULL != dev->set_master_volume) {
@@ -626,7 +566,6 @@
         swmv = 1.0;
     }
 
-    Mutex::Autolock _l(mLock);
     mMasterVolume   = value;
     mMasterVolumeSW = swmv;
     for (size_t i = 0; i < mPlaybackThreads.size(); i++)
@@ -853,22 +792,22 @@
 
     // ioHandle == 0 means the parameters are global to the audio hardware interface
     if (ioHandle == 0) {
+        Mutex::Autolock _l(mLock);
         status_t final_result = NO_ERROR;
         {
-        AutoMutex lock(mHardwareLock);
-        mHardwareStatus = AUDIO_HW_SET_PARAMETER;
-        for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
-            audio_hw_device_t *dev = mAudioHwDevs[i];
-            status_t result = dev->set_parameters(dev, keyValuePairs.string());
-            final_result = result ?: final_result;
-        }
-        mHardwareStatus = AUDIO_HW_IDLE;
+            AutoMutex lock(mHardwareLock);
+            mHardwareStatus = AUDIO_HW_SET_PARAMETER;
+            for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+                audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();
+                status_t result = dev->set_parameters(dev, keyValuePairs.string());
+                final_result = result ?: final_result;
+            }
+            mHardwareStatus = AUDIO_HW_IDLE;
         }
         // disable AEC and NS if the device is a BT SCO headset supporting those pre processings
         AudioParameter param = AudioParameter(keyValuePairs);
         String8 value;
         if (param.get(String8(AUDIO_PARAMETER_KEY_BT_NREC), value) == NO_ERROR) {
-            Mutex::Autolock _l(mLock);
             bool btNrecIsOff = (value == AUDIO_PARAMETER_VALUE_OFF);
             if (mBtNrecIsOff != btNrecIsOff) {
                 for (size_t i = 0; i < mRecordThreads.size(); i++) {
@@ -923,6 +862,8 @@
 //    ALOGV("getParameters() io %d, keys %s, tid %d, calling pid %d",
 //            ioHandle, keys.string(), gettid(), IPCThreadState::self()->getCallingPid());
 
+    Mutex::Autolock _l(mLock);
+
     if (ioHandle == 0) {
         String8 out_s8;
 
@@ -931,7 +872,7 @@
             {
             AutoMutex lock(mHardwareLock);
             mHardwareStatus = AUDIO_HW_GET_PARAMETER;
-            audio_hw_device_t *dev = mAudioHwDevs[i];
+            audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();
             s = dev->get_parameters(dev, keys.string());
             mHardwareStatus = AUDIO_HW_IDLE;
             }
@@ -941,8 +882,6 @@
         return out_s8;
     }
 
-    Mutex::Autolock _l(mLock);
-
     PlaybackThread *playbackThread = checkPlaybackThread_l(ioHandle);
     if (playbackThread != NULL) {
         return playbackThread->getParameters(keys);
@@ -5663,28 +5602,84 @@
 
 // ----------------------------------------------------------------------------
 
-audio_io_handle_t AudioFlinger::openOutput(uint32_t *pDevices,
-                                uint32_t *pSamplingRate,
-                                audio_format_t *pFormat,
-                                uint32_t *pChannels,
-                                uint32_t *pLatencyMs,
-                                audio_policy_output_flags_t flags)
+audio_module_handle_t AudioFlinger::loadHwModule(const char *name)
+{
+    if (!settingsAllowed()) {
+        return 0;
+    }
+    Mutex::Autolock _l(mLock);
+    return loadHwModule_l(name);
+}
+
+// loadHwModule_l() must be called with AudioFlinger::mLock held
+audio_module_handle_t AudioFlinger::loadHwModule_l(const char *name)
+{
+    for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+        if (strncmp(mAudioHwDevs.valueAt(i)->moduleName(), name, strlen(name)) == 0) {
+            ALOGW("loadHwModule() module %s already loaded", name);
+            return mAudioHwDevs.keyAt(i);
+        }
+    }
+
+    const hw_module_t *mod;
+    audio_hw_device_t *dev;
+
+    int rc = load_audio_interface(name, &mod, &dev);
+    if (rc) {
+        ALOGI("loadHwModule() error %d loading module %s ", rc, name);
+        return 0;
+    }
+
+    mHardwareStatus = AUDIO_HW_INIT;
+    rc = dev->init_check(dev);
+    mHardwareStatus = AUDIO_HW_IDLE;
+    if (rc) {
+        ALOGI("loadHwModule() init check error %d for module %s ", rc, name);
+        return 0;
+    }
+
+    if ((mMasterVolumeSupportLvl != MVS_NONE) &&
+        (NULL != dev->set_master_volume)) {
+        AutoMutex lock(mHardwareLock);
+        mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+        dev->set_master_volume(dev, mMasterVolume);
+        mHardwareStatus = AUDIO_HW_IDLE;
+    }
+
+    audio_module_handle_t handle = nextUniqueId();
+    mAudioHwDevs.add(handle, new AudioHwDevice(name, dev));
+
+    ALOGI("loadHwModule() Loaded %s audio interface from %s (%s) handle %d",
+          name, mod->name, mod->id, handle);
+
+    return handle;
+
+}
+
+audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module,
+                                           audio_devices_t *pDevices,
+                                           uint32_t *pSamplingRate,
+                                           audio_format_t *pFormat,
+                                           audio_channel_mask_t *pChannelMask,
+                                           uint32_t *pLatencyMs,
+                                           audio_policy_output_flags_t flags)
 {
     status_t status;
     PlaybackThread *thread = NULL;
     uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;
     audio_format_t format = pFormat ? *pFormat : AUDIO_FORMAT_DEFAULT;
-    uint32_t channels = pChannels ? *pChannels : 0;
+    audio_channel_mask_t channelMask = pChannelMask ? *pChannelMask : 0;
     uint32_t latency = pLatencyMs ? *pLatencyMs : 0;
     audio_stream_out_t *outStream;
     audio_hw_device_t *outHwDev;
 
-    ALOGV("openOutput(), Device %x, SamplingRate %d, Format %d, Channels %x, flags %x",
-            pDevices ? *pDevices : 0,
-            samplingRate,
-            format,
-            channels,
-            flags);
+    ALOGV("openOutput(), module %d Device %x, SamplingRate %d, Format %d, Channels %x, flags %x",
+              module,
+              pDevices ? *pDevices : 0,
+              samplingRate,
+              format,
+              channelMask,
+              flags);
 
     if (pDevices == NULL || *pDevices == 0) {
         return 0;
@@ -5692,19 +5687,19 @@
 
     Mutex::Autolock _l(mLock);
 
-    outHwDev = findSuitableHwDev_l(*pDevices);
+    outHwDev = findSuitableHwDev_l(module, *pDevices);
     if (outHwDev == NULL)
         return 0;
 
     mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
     status = outHwDev->open_output_stream(outHwDev, *pDevices, &format,
-                                          &channels, &samplingRate, &outStream);
+                                          &channelMask, &samplingRate, &outStream);
     mHardwareStatus = AUDIO_HW_IDLE;
     ALOGV("openOutput() openOutputStream returned output %p, SamplingRate %d, Format %d, Channels %x, status %d",
             outStream,
             samplingRate,
             format,
-            channels,
+            channelMask,
             status);
 
     if (outStream != NULL) {
@@ -5713,7 +5708,7 @@
 
         if ((flags & AUDIO_POLICY_OUTPUT_FLAG_DIRECT) ||
             (format != AUDIO_FORMAT_PCM_16_BIT) ||
-            (channels != AUDIO_CHANNEL_OUT_STEREO)) {
+            (channelMask != AUDIO_CHANNEL_OUT_STEREO)) {
             thread = new DirectOutputThread(this, output, id, *pDevices);
             ALOGV("openOutput() created direct output: ID %d thread %p", id, thread);
         } else {
@@ -5724,11 +5719,55 @@
 
         if (pSamplingRate != NULL) *pSamplingRate = samplingRate;
         if (pFormat != NULL) *pFormat = format;
-        if (pChannels != NULL) *pChannels = channels;
+        if (pChannelMask != NULL) *pChannelMask = channelMask;
         if (pLatencyMs != NULL) *pLatencyMs = thread->latency();
 
         // notify client processes of the new output creation
         thread->audioConfigChanged_l(AudioSystem::OUTPUT_OPENED);
+
+        // the first primary output opened designates the primary hw device
+        if ((mPrimaryHardwareDev == NULL) && (flags & AUDIO_POLICY_OUTPUT_FLAG_PRIMARY)) {
+            ALOGI("Using module %d has the primary audio interface", module);
+            mPrimaryHardwareDev = outHwDev;
+
+            AutoMutex lock(mHardwareLock);
+            mHardwareStatus = AUDIO_HW_SET_MODE;
+            outHwDev->set_mode(outHwDev, mMode);
+
+            // Determine the level of master volume support the primary audio HAL has,
+            // and set the initial master volume at the same time.
+            float initialVolume = 1.0;
+            mMasterVolumeSupportLvl = MVS_NONE;
+
+            mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME;
+            if ((NULL != outHwDev->get_master_volume) &&
+                (NO_ERROR == outHwDev->get_master_volume(outHwDev, &initialVolume))) {
+                mMasterVolumeSupportLvl = MVS_FULL;
+            } else {
+                mMasterVolumeSupportLvl = MVS_SETONLY;
+                initialVolume = 1.0;
+            }
+
+            mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+            if ((NULL == outHwDev->set_master_volume) ||
+                (NO_ERROR != outHwDev->set_master_volume(outHwDev, initialVolume))) {
+                mMasterVolumeSupportLvl = MVS_NONE;
+            }
+            // now that we have a primary device, initialize master volume on other devices
+            for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+                audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();
+
+                if ((dev != mPrimaryHardwareDev) &&
+                    (NULL != dev->set_master_volume)) {
+                    dev->set_master_volume(dev, initialVolume);
+                }
+            }
+            mHardwareStatus = AUDIO_HW_IDLE;
+            mMasterVolumeSW = (MVS_NONE == mMasterVolumeSupportLvl)
+                                    ? initialVolume
+                                    : 1.0;
+            mMasterVolume   = initialVolume;
+        }
         return id;
     }
 
@@ -5826,20 +5865,20 @@
     return NO_ERROR;
 }
 
-audio_io_handle_t AudioFlinger::openInput(uint32_t *pDevices,
-                                uint32_t *pSamplingRate,
-                                audio_format_t *pFormat,
-                                uint32_t *pChannels,
-                                audio_in_acoustics_t acoustics)
+audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module,
+                                          audio_devices_t *pDevices,
+                                          uint32_t *pSamplingRate,
+                                          audio_format_t *pFormat,
+                                          uint32_t *pChannelMask)
 {
     status_t status;
     RecordThread *thread = NULL;
     uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;
     audio_format_t format = pFormat ? *pFormat : AUDIO_FORMAT_DEFAULT;
-    uint32_t channels = pChannels ? *pChannels : 0;
+    audio_channel_mask_t channelMask = pChannelMask ? *pChannelMask : 0;
     uint32_t reqSamplingRate = samplingRate;
     audio_format_t reqFormat = format;
-    uint32_t reqChannels = channels;
+    audio_channel_mask_t reqChannels = channelMask;
     audio_stream_in_t *inStream;
     audio_hw_device_t *inHwDev;
 
@@ -5849,20 +5888,19 @@
 
     Mutex::Autolock _l(mLock);
 
-    inHwDev = findSuitableHwDev_l(*pDevices);
+    inHwDev = findSuitableHwDev_l(module, *pDevices);
     if (inHwDev == NULL)
         return 0;
 
     status = inHwDev->open_input_stream(inHwDev, *pDevices, &format,
-                                        &channels, &samplingRate,
-                                        acoustics,
+                                        &channelMask, &samplingRate,
+                                        (audio_in_acoustics_t)0,
                                         &inStream);
-    ALOGV("openInput() openInputStream returned input %p, SamplingRate %d, Format %d, Channels %x, acoustics %x, status %d",
+    ALOGV("openInput() openInputStream returned input %p, SamplingRate %d, Format %d, Channels %x, status %d",
             inStream,
             samplingRate,
             format,
-            channels,
-            acoustics,
+            channelMask,
             status);
 
     // If the input could not be opened with the requested parameters and we can handle the conversion internally,
@@ -5871,11 +5909,11 @@
     if (inStream == NULL && status == BAD_VALUE &&
         reqFormat == format && format == AUDIO_FORMAT_PCM_16_BIT &&
         (samplingRate <= 2 * reqSamplingRate) &&
-        (popcount(channels) <= FCC_2) && (popcount(reqChannels) <= FCC_2)) {
+        (popcount(channelMask) <= FCC_2) && (popcount(reqChannels) <= FCC_2)) {
         ALOGV("openInput() reopening with proposed sampling rate and channels");
         status = inHwDev->open_input_stream(inHwDev, *pDevices, &format,
-                                            &channels, &samplingRate,
-                                            acoustics,
+                                            &channelMask, &samplingRate,
+                                            (audio_in_acoustics_t)0,
                                             &inStream);
     }
 
@@ -5897,7 +5935,7 @@
         ALOGV("openInput() created record thread: ID %d thread %p", id, thread);
         if (pSamplingRate != NULL) *pSamplingRate = reqSamplingRate;
         if (pFormat != NULL) *pFormat = format;
-        if (pChannels != NULL) *pChannels = reqChannels;
+        if (pChannelMask != NULL) *pChannelMask = reqChannels;
 
         input->stream->common.standby(&input->stream->common);
 
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index c47d196..e493a9a 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -43,6 +43,7 @@
 
 #include <system/audio.h>
 #include <hardware/audio.h>
+#include <hardware/audio_policy.h>
 
 #include "AudioBufferProvider.h"
 
@@ -137,12 +138,13 @@
 
     virtual     size_t      getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount) const;
 
-    virtual audio_io_handle_t openOutput(uint32_t *pDevices,
-                                    uint32_t *pSamplingRate,
-                                    audio_format_t *pFormat,
-                                    uint32_t *pChannels,
-                                    uint32_t *pLatencyMs,
-                                    audio_policy_output_flags_t flags);
+    virtual audio_io_handle_t openOutput(audio_module_handle_t module,
+                                         audio_devices_t *pDevices,
+                                         uint32_t *pSamplingRate,
+                                         audio_format_t *pFormat,
+                                         audio_channel_mask_t *pChannelMask,
+                                         uint32_t *pLatencyMs,
+                                         audio_policy_output_flags_t flags);
 
     virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1,
                                                   audio_io_handle_t output2);
@@ -153,11 +155,11 @@
 
     virtual status_t restoreOutput(audio_io_handle_t output);
 
-    virtual audio_io_handle_t openInput(uint32_t *pDevices,
-                            uint32_t *pSamplingRate,
-                            audio_format_t *pFormat,
-                            uint32_t *pChannels,
-                            audio_in_acoustics_t acoustics);
+    virtual audio_io_handle_t openInput(audio_module_handle_t module,
+                                        audio_devices_t *pDevices,
+                                        uint32_t *pSamplingRate,
+                                        audio_format_t *pFormat,
+                                        audio_channel_mask_t *pChannelMask);
 
     virtual status_t closeInput(audio_io_handle_t input);
 
@@ -196,6 +198,8 @@
     virtual status_t moveEffects(int sessionId, audio_io_handle_t srcOutput,
                         audio_io_handle_t dstOutput);
 
+    virtual audio_module_handle_t loadHwModule(const char *name);
+
     virtual     status_t    onTransact(
                                 uint32_t code,
                                 const Parcel& data,
@@ -256,7 +260,7 @@
     // RefBase
     virtual     void        onFirstRef();
 
-    audio_hw_device_t*      findSuitableHwDev_l(uint32_t devices);
+    audio_hw_device_t*      findSuitableHwDev_l(audio_module_handle_t module, uint32_t devices);
     void                    purgeStaleEffects_l();
 
     // standby delay for MIXER and DUPLICATING playback threads is read from property
@@ -1699,15 +1703,30 @@
         MVS_FULL,
     };
 
+    class AudioHwDevice {
+    public:
+        AudioHwDevice(const char *moduleName, audio_hw_device_t *hwDevice) :
+            mModuleName(strdup(moduleName)), mHwDevice(hwDevice){}
+        ~AudioHwDevice() { free((void *)mModuleName); }
+
+        const char *moduleName() const { return mModuleName; }
+        audio_hw_device_t *hwDevice() const { return mHwDevice; }
+    private:
+        const char * const mModuleName;
+        audio_hw_device_t * const mHwDevice;
+    };
+
     mutable     Mutex                               mLock;
 
                 DefaultKeyedVector< pid_t, wp<Client> >     mClients;   // see ~Client()
 
                 mutable     Mutex                   mHardwareLock;
+                // NOTE: If both mLock and mHardwareLock mutexes must be held,
+                // always take mLock before mHardwareLock
 
                 // These two fields are immutable after onFirstRef(), so no lock needed to access
                 audio_hw_device_t*                  mPrimaryHardwareDev; // mAudioHwDevs[0] or NULL
-                Vector<audio_hw_device_t*>          mAudioHwDevs;
+                DefaultKeyedVector<audio_module_handle_t, AudioHwDevice*>  mAudioHwDevs;
 
     // for dump, indicates which hardware operation is currently in progress (but not stream ops)
     enum hardware_call_state {
@@ -1757,6 +1776,7 @@
                 float       masterVolume_l() const;
                 float       masterVolumeSW_l() const  { return mMasterVolumeSW; }
                 bool        masterMute_l() const    { return mMasterMute; }
+                audio_module_handle_t loadHwModule_l(const char *name);
 
                 Vector < sp<SyncEvent> > mPendingSyncEvents; // sync events awaiting for a session
                                                              // to be created
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index 62ab45d..15f4349 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -1329,13 +1329,9 @@
 /* implementation of the interface to the policy manager */
 extern "C" {
 
-static audio_io_handle_t aps_open_output(void *service,
-                                             uint32_t *pDevices,
-                                             uint32_t *pSamplingRate,
-                                             audio_format_t *pFormat,
-                                             uint32_t *pChannels,
-                                             uint32_t *pLatencyMs,
-                                             audio_policy_output_flags_t flags)
+
+static audio_module_handle_t aps_load_hw_module(void *service,
+                                             const char *name)
 {
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
     if (af == 0) {
@@ -1343,7 +1339,44 @@
         return 0;
     }
 
-    return af->openOutput(pDevices, pSamplingRate, pFormat, pChannels,
+    return af->loadHwModule(name);
+}
+
+// deprecated: replaced by aps_open_output_on_module()
+static audio_io_handle_t aps_open_output(void *service,
+                                         audio_devices_t *pDevices,
+                                         uint32_t *pSamplingRate,
+                                         audio_format_t *pFormat,
+                                         audio_channel_mask_t *pChannelMask,
+                                         uint32_t *pLatencyMs,
+                                         audio_policy_output_flags_t flags)
+{
+    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+    if (af == 0) {
+        ALOGW("%s: could not get AudioFlinger", __func__);
+        return 0;
+    }
+
+    return af->openOutput((audio_module_handle_t)0, pDevices, pSamplingRate, pFormat, pChannelMask,
+                          pLatencyMs, flags);
+}
+
+static audio_io_handle_t aps_open_output_on_module(void *service,
+                                                   audio_module_handle_t module,
+                                                   audio_devices_t *pDevices,
+                                                   uint32_t *pSamplingRate,
+                                                   audio_format_t *pFormat,
+                                                   audio_channel_mask_t *pChannelMask,
+                                                   uint32_t *pLatencyMs,
+                                                   audio_policy_output_flags_t flags)
+{
+    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+    if (af == 0) {
+        ALOGW("%s: could not get AudioFlinger", __func__);
+        return 0;
+    }
+    ALOGW("%s: %d", __func__, module);
+    return af->openOutput(module, pDevices, pSamplingRate, pFormat, pChannelMask,
                           pLatencyMs, flags);
 }
 
@@ -1390,12 +1423,13 @@
     return af->restoreOutput(output);
 }
 
+// deprecated: replaced by aps_open_input_on_module()
 static audio_io_handle_t aps_open_input(void *service,
-                                            uint32_t *pDevices,
-                                            uint32_t *pSamplingRate,
-                                            audio_format_t *pFormat,
-                                            uint32_t *pChannels,
-                                            audio_in_acoustics_t acoustics)
+                                        audio_devices_t *pDevices,
+                                        uint32_t *pSamplingRate,
+                                        audio_format_t *pFormat,
+                                        audio_channel_mask_t *pChannelMask,
+                                        audio_in_acoustics_t acoustics)
 {
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
     if (af == 0) {
@@ -1403,8 +1437,23 @@
         return 0;
     }
 
-    return af->openInput(pDevices, pSamplingRate, pFormat, pChannels,
-                         acoustics);
+    return af->openInput((audio_module_handle_t)0, pDevices, pSamplingRate, pFormat, pChannelMask);
+}
+
+static audio_io_handle_t aps_open_input_on_module(void *service,
+                                                  audio_module_handle_t module,
+                                                  audio_devices_t *pDevices,
+                                                  uint32_t *pSamplingRate,
+                                                  audio_format_t *pFormat,
+                                                  audio_channel_mask_t *pChannelMask)
+{
+    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+    if (af == 0) {
+        ALOGW("%s: could not get AudioFlinger", __func__);
+        return 0;
+    }
+
+    return af->openInput(module, pDevices, pSamplingRate, pFormat, pChannelMask);
 }
 
 static int aps_close_input(void *service, audio_io_handle_t input)
@@ -1503,6 +1552,9 @@
         stop_tone             : aps_stop_tone,
         set_voice_volume      : aps_set_voice_volume,
         move_effects          : aps_move_effects,
+        load_hw_module        : aps_load_hw_module,
+        open_output_on_module : aps_open_output_on_module,
+        open_input_on_module  : aps_open_input_on_module,
     };
 }; // namespace <unnamed>