OSDN Git Service

am "Merge "bring nan header file, from original KitKat partner version" into m-wirele...
[android-x86/hardware-libhardware_legacy.git] / audio / AudioPolicyManagerBase.cpp
index 8be4390..85b0084 100644 (file)
 // active output devices in isStreamActiveRemotely()
 #define APM_AUDIO_OUT_DEVICE_REMOTE_ALL  AUDIO_DEVICE_OUT_REMOTE_SUBMIX
 
+#include <inttypes.h>
+#include <math.h>
+
+#include <cutils/properties.h>
 #include <utils/Log.h>
-#include <hardware_legacy/AudioPolicyManagerBase.h>
-#include <hardware/audio_effect.h>
+
 #include <hardware/audio.h>
-#include <math.h>
+#include <hardware/audio_effect.h>
 #include <hardware_legacy/audio_policy_conf.h>
-#include <cutils/properties.h>
+#include <hardware_legacy/AudioPolicyManagerBase.h>
 
 namespace android_audio_legacy {
 
@@ -50,9 +53,12 @@ status_t AudioPolicyManagerBase::setDeviceConnectionState(audio_devices_t device
                                                   AudioSystem::device_connection_state state,
                                                   const char *device_address)
 {
-    SortedVector <audio_io_handle_t> outputs;
-
-    ALOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address);
+    // device_address can be NULL and should be handled as an empty string in this case,
+    // and it is not checked by AudioPolicyInterfaceImpl.cpp
+    if (device_address == NULL) {
+        device_address = "";
+    }
+    ALOGV("setDeviceConnectionState() device: 0x%X, state %d, address %s", device, state, device_address);
 
     // connect/disconnect only 1 device at a time
     if (!audio_is_output_device(device) && !audio_is_input_device(device)) return BAD_VALUE;
@@ -64,12 +70,13 @@ status_t AudioPolicyManagerBase::setDeviceConnectionState(audio_devices_t device
 
     // handle output devices
     if (audio_is_output_device(device)) {
+        SortedVector <audio_io_handle_t> outputs;
 
-        if (!mHasA2dp && audio_is_a2dp_device(device)) {
+        if (!mHasA2dp && audio_is_a2dp_out_device(device)) {
             ALOGE("setDeviceConnectionState() invalid A2DP device: %x", device);
             return BAD_VALUE;
         }
-        if (!mHasUsb && audio_is_usb_device(device)) {
+        if (!mHasUsb && audio_is_usb_out_device(device)) {
             ALOGE("setDeviceConnectionState() invalid USB audio device: %x", device);
             return BAD_VALUE;
         }
@@ -92,12 +99,12 @@ status_t AudioPolicyManagerBase::setDeviceConnectionState(audio_devices_t device
             }
             ALOGV("setDeviceConnectionState() connecting device %x", device);
 
-            if (mHasA2dp && audio_is_a2dp_device(device)) {
+            if (mHasA2dp && audio_is_a2dp_out_device(device)) {
                 // handle A2DP device connection
                 AudioParameter param;
                 param.add(String8(AUDIO_PARAMETER_A2DP_SINK_ADDRESS), String8(device_address));
                 paramStr = param.toString();
-            } else if (mHasUsb && audio_is_usb_device(device)) {
+            } else if (mHasUsb && audio_is_usb_out_device(device)) {
                 // handle USB device connection
                 paramStr = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
             }
@@ -105,21 +112,21 @@ status_t AudioPolicyManagerBase::setDeviceConnectionState(audio_devices_t device
             if (checkOutputsForDevice(device, state, outputs, paramStr) != NO_ERROR) {
                 return INVALID_OPERATION;
             }
-            ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %d outputs",
+            ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %zu outputs",
                   outputs.size());
             // register new device as available
             mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices | device);
 
-            if (mHasA2dp && audio_is_a2dp_device(device)) {
+            if (mHasA2dp && audio_is_a2dp_out_device(device)) {
                 // handle A2DP device connection
                 mA2dpDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
                 mA2dpSuspended = false;
             } else if (audio_is_bluetooth_sco_device(device)) {
                 // handle SCO device connection
                 mScoDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
-            } else if (mHasUsb && audio_is_usb_device(device)) {
+            } else if (mHasUsb && audio_is_usb_out_device(device)) {
                 // handle USB device connection
-                mUsbCardAndDevice = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+                mUsbOutCardAndDevice = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
             }
 
             break;
@@ -133,18 +140,18 @@ status_t AudioPolicyManagerBase::setDeviceConnectionState(audio_devices_t device
             ALOGV("setDeviceConnectionState() disconnecting device %x", device);
             // remove device from available output devices
             mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices & ~device);
-
             checkOutputsForDevice(device, state, outputs, paramStr);
-            if (mHasA2dp && audio_is_a2dp_device(device)) {
+
+            if (mHasA2dp && audio_is_a2dp_out_device(device)) {
                 // handle A2DP device disconnection
                 mA2dpDeviceAddress = "";
                 mA2dpSuspended = false;
             } else if (audio_is_bluetooth_sco_device(device)) {
                 // handle SCO device disconnection
                 mScoDeviceAddress = "";
-            } else if (mHasUsb && audio_is_usb_device(device)) {
+            } else if (mHasUsb && audio_is_usb_out_device(device)) {
                 // handle USB device disconnection
-                mUsbCardAndDevice = "";
+                mUsbOutCardAndDevice = "";
             }
             // not currently handling multiple simultaneous submixes: ignoring remote submix
             //   case and address
@@ -182,19 +189,14 @@ status_t AudioPolicyManagerBase::setDeviceConnectionState(audio_devices_t device
                             0);
         }
 
-        if (device == AUDIO_DEVICE_OUT_WIRED_HEADSET) {
-            device = AUDIO_DEVICE_IN_WIRED_HEADSET;
-        } else if (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO ||
-                   device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET ||
-                   device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) {
-            device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
-        } else {
-            return NO_ERROR;
-        }
-    }
+        return NO_ERROR;
+    }  // end if is output device
+
     // handle input devices
     if (audio_is_input_device(device)) {
+        SortedVector <audio_io_handle_t> inputs;
 
+        String8 paramStr;
         switch (state)
         {
         // handle input device connection
@@ -203,6 +205,20 @@ status_t AudioPolicyManagerBase::setDeviceConnectionState(audio_devices_t device
                 ALOGW("setDeviceConnectionState() device already connected: %d", device);
                 return INVALID_OPERATION;
             }
+
+            if (mHasUsb && audio_is_usb_in_device(device)) {
+                // handle USB device connection
+                paramStr = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+            } else if (mHasA2dp && audio_is_a2dp_in_device(device)) {
+                // handle A2DP device connection
+                AudioParameter param;
+                param.add(String8(AUDIO_PARAMETER_A2DP_SOURCE_ADDRESS), String8(device_address));
+                paramStr = param.toString();
+            }
+
+            if (checkInputsForDevice(device, state, inputs, paramStr) != NO_ERROR) {
+                return INVALID_OPERATION;
+            }
             mAvailableInputDevices = mAvailableInputDevices | (device & ~AUDIO_DEVICE_BIT_IN);
             }
             break;
@@ -213,30 +229,19 @@ status_t AudioPolicyManagerBase::setDeviceConnectionState(audio_devices_t device
                 ALOGW("setDeviceConnectionState() device not connected: %d", device);
                 return INVALID_OPERATION;
             }
+            checkInputsForDevice(device, state, inputs, paramStr);
             mAvailableInputDevices = (audio_devices_t) (mAvailableInputDevices & ~device);
-            } break;
+        } break;
 
         default:
             ALOGE("setDeviceConnectionState() invalid state: %x", state);
             return BAD_VALUE;
         }
 
-        audio_io_handle_t activeInput = getActiveInput();
-        if (activeInput != 0) {
-            AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput);
-            audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
-            if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) {
-                ALOGV("setDeviceConnectionState() changing device from %x to %x for input %d",
-                        inputDesc->mDevice, newDevice, activeInput);
-                inputDesc->mDevice = newDevice;
-                AudioParameter param = AudioParameter();
-                param.addInt(String8(AudioParameter::keyRouting), (int)newDevice);
-                mpClientInterface->setParameters(activeInput, param.toString());
-            }
-        }
+        closeAllInputs();
 
         return NO_ERROR;
-    }
+    } // end if is input device
 
     ALOGW("setDeviceConnectionState() invalid device: %x", device);
     return BAD_VALUE;
@@ -245,11 +250,15 @@ status_t AudioPolicyManagerBase::setDeviceConnectionState(audio_devices_t device
 AudioSystem::device_connection_state AudioPolicyManagerBase::getDeviceConnectionState(audio_devices_t device,
                                                   const char *device_address)
 {
+    // similar to setDeviceConnectionState
+    if (device_address == NULL) {
+        device_address = "";
+    }
     AudioSystem::device_connection_state state = AudioSystem::DEVICE_STATE_UNAVAILABLE;
     String8 address = String8(device_address);
     if (audio_is_output_device(device)) {
         if (device & mAvailableOutputDevices) {
-            if (audio_is_a2dp_device(device) &&
+            if (audio_is_a2dp_out_device(device) &&
                 (!mHasA2dp || (address != "" && mA2dpDeviceAddress != address))) {
                 return state;
             }
@@ -257,8 +266,8 @@ AudioSystem::device_connection_state AudioPolicyManagerBase::getDeviceConnection
                 address != "" && mScoDeviceAddress != address) {
                 return state;
             }
-            if (audio_is_usb_device(device) &&
-                (!mHasUsb || (address != "" && mUsbCardAndDevice != address))) {
+            if (audio_is_usb_out_device(device) &&
+                (!mHasUsb || (address != "" && mUsbOutCardAndDevice != address))) {
                 ALOGE("getDeviceConnectionState() invalid device: %x", device);
                 return state;
             }
@@ -933,8 +942,8 @@ audio_io_handle_t AudioPolicyManagerBase::getInput(int inputSource,
                                          format,
                                          channelMask);
     if (profile == NULL) {
-        ALOGW("getInput() could not find profile for device %04x, samplingRate %d, format %d, "
-                "channelMask %04x",
+        ALOGW("getInput() could not find profile for device 0x%X, samplingRate %d, format %d, "
+                "channelMask 0x%X",
                 device, samplingRate, format, channelMask);
         return 0;
     }
@@ -952,6 +961,7 @@ audio_io_handle_t AudioPolicyManagerBase::getInput(int inputSource,
     inputDesc->mFormat = format;
     inputDesc->mChannelMask = channelMask;
     inputDesc->mRefCount = 0;
+
     input = mpClientInterface->openInput(profile->mModule->mHandle,
                                     &inputDesc->mDevice,
                                     &inputDesc->mSamplingRate,
@@ -963,7 +973,7 @@ audio_io_handle_t AudioPolicyManagerBase::getInput(int inputSource,
         (samplingRate != inputDesc->mSamplingRate) ||
         (format != inputDesc->mFormat) ||
         (channelMask != inputDesc->mChannelMask)) {
-        ALOGI("getInput() failed opening input: samplingRate %d, format %d, channelMask %x",
+        ALOGI("getInput() failed opening input: samplingRate %d, format %d, channelMask 0x%X",
                 samplingRate, format, channelMask);
         if (input != 0) {
             mpClientInterface->closeInput(input);
@@ -971,7 +981,8 @@ audio_io_handle_t AudioPolicyManagerBase::getInput(int inputSource,
         delete inputDesc;
         return 0;
     }
-    mInputs.add(input, inputDesc);
+    addInput(input, inputDesc);
+
     return input;
 }
 
@@ -1070,9 +1081,17 @@ void AudioPolicyManagerBase::releaseInput(audio_io_handle_t input)
     mpClientInterface->closeInput(input);
     delete mInputs.valueAt(index);
     mInputs.removeItem(input);
+
     ALOGV("releaseInput() exit");
 }
 
+void AudioPolicyManagerBase::closeAllInputs() {
+    for(size_t input_index = 0; input_index < mInputs.size(); input_index++) {
+        mpClientInterface->closeInput(mInputs.keyAt(input_index));
+    }
+    mInputs.clear();
+}
+
 void AudioPolicyManagerBase::initStreamVolume(AudioSystem::stream_type stream,
                                             int indexMin,
                                             int indexMax)
@@ -1168,7 +1187,7 @@ audio_io_handle_t AudioPolicyManagerBase::selectOutputForEffects(
 
     for (size_t i = 0; i < outputs.size(); i++) {
         AudioOutputDescriptor *desc = mOutputs.valueFor(outputs[i]);
-        ALOGV("selectOutputForEffects outputs[%d] flags %x", i, desc->mFlags);
+        ALOGV("selectOutputForEffects outputs[%zu] flags %x", i, desc->mFlags);
         if ((desc->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
             outputOffloaded = outputs[i];
         }
@@ -1377,7 +1396,7 @@ status_t AudioPolicyManagerBase::dump(int fd)
     result.append(buffer);
     snprintf(buffer, SIZE, " SCO device address: %s\n", mScoDeviceAddress.string());
     result.append(buffer);
-    snprintf(buffer, SIZE, " USB audio ALSA %s\n", mUsbCardAndDevice.string());
+    snprintf(buffer, SIZE, " USB audio ALSA %s\n", mUsbOutCardAndDevice.string());
     result.append(buffer);
     snprintf(buffer, SIZE, " Output devices: %08x\n", mAvailableOutputDevices);
     result.append(buffer);
@@ -1401,7 +1420,7 @@ status_t AudioPolicyManagerBase::dump(int fd)
     snprintf(buffer, SIZE, "\nHW Modules dump:\n");
     write(fd, buffer, strlen(buffer));
     for (size_t i = 0; i < mHwModules.size(); i++) {
-        snprintf(buffer, SIZE, "- HW Module %d:\n", i + 1);
+        snprintf(buffer, SIZE, "- HW Module %zu:\n", i + 1);
         write(fd, buffer, strlen(buffer));
         mHwModules[i]->dump(fd);
     }
@@ -1428,7 +1447,7 @@ status_t AudioPolicyManagerBase::dump(int fd)
              " Stream  Can be muted  Index Min  Index Max  Index Cur [device : index]...\n");
     write(fd, buffer, strlen(buffer));
     for (size_t i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
-        snprintf(buffer, SIZE, " %02d      ", i);
+        snprintf(buffer, SIZE, " %02zu      ", i);
         write(fd, buffer, strlen(buffer));
         mStreams[i].dump(fd);
     }
@@ -1455,7 +1474,7 @@ status_t AudioPolicyManagerBase::dump(int fd)
 bool AudioPolicyManagerBase::isOffloadSupported(const audio_offload_info_t& offloadInfo)
 {
     ALOGV("isOffloadSupported: SR=%u, CM=0x%x, Format=0x%x, StreamType=%d,"
-     " BitRate=%u, duration=%lld us, has_video=%d",
+     " BitRate=%u, duration=%" PRId64 " us, has_video=%d",
      offloadInfo.sample_rate, offloadInfo.channel_mask,
      offloadInfo.format,
      offloadInfo.stream_type, offloadInfo.bit_rate, offloadInfo.duration_us,
@@ -1541,7 +1560,7 @@ AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clien
 
     mA2dpDeviceAddress = String8("");
     mScoDeviceAddress = String8("");
-    mUsbCardAndDevice = String8("");
+    mUsbOutCardAndDevice = String8("");
 
     if (loadAudioPolicyConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE) != NO_ERROR) {
         if (loadAudioPolicyConfig(AUDIO_POLICY_CONFIG_FILE) != NO_ERROR) {
@@ -1813,6 +1832,11 @@ void AudioPolicyManagerBase::addOutput(audio_io_handle_t id, AudioOutputDescript
     mOutputs.add(id, outputDesc);
 }
 
+void AudioPolicyManagerBase::addInput(audio_io_handle_t id, AudioInputDescriptor *inputDesc)
+{
+    inputDesc->mId = id;
+    mInputs.add(id, inputDesc);
+}
 
 status_t AudioPolicyManagerBase::checkOutputsForDevice(audio_devices_t device,
                                                        AudioSystem::device_connection_state state,
@@ -1840,7 +1864,7 @@ status_t AudioPolicyManagerBase::checkOutputsForDevice(audio_devices_t device,
             for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
             {
                 if (mHwModules[i]->mOutputProfiles[j]->mSupportedDevices & device) {
-                    ALOGV("checkOutputsForDevice(): adding profile %d from module %d", j, i);
+                    ALOGV("checkOutputsForDevice(): adding profile %zu from module %zu", j, i);
                     profiles.add(mHwModules[i]->mOutputProfiles[j]);
                 }
             }
@@ -1886,83 +1910,98 @@ status_t AudioPolicyManagerBase::checkOutputsForDevice(audio_devices_t device,
                                                                        &offloadInfo);
             if (output != 0) {
                 if (!paramStr.isEmpty()) {
+                    // Here is where the out_set_parameters() for card & device gets called
                     mpClientInterface->setParameters(output, paramStr);
                 }
 
-                if (desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
-                    String8 reply;
-                    char *value;
-                    if (profile->mSamplingRates[0] == 0) {
-                        reply = mpClientInterface->getParameters(output,
-                                                String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES));
-                        ALOGV("checkOutputsForDevice() direct output sup sampling rates %s",
-                                  reply.string());
-                        value = strpbrk((char *)reply.string(), "=");
-                        if (value != NULL) {
-                            loadSamplingRates(value + 1, profile);
-                        }
+                // Here is where we step through and resolve any "dynamic" fields
+                String8 reply;
+                char *value;
+                if (profile->mSamplingRates[0] == 0) {
+                    reply = mpClientInterface->getParameters(output,
+                                            String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES));
+                    ALOGV("checkOutputsForDevice() direct output sup sampling rates %s",
+                              reply.string());
+                    value = strpbrk((char *)reply.string(), "=");
+                    if (value != NULL) {
+                        loadSamplingRates(value + 1, profile);
                     }
-                    if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
-                        reply = mpClientInterface->getParameters(output,
-                                                       String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
-                        ALOGV("checkOutputsForDevice() direct output sup formats %s",
-                                  reply.string());
-                        value = strpbrk((char *)reply.string(), "=");
-                        if (value != NULL) {
-                            loadFormats(value + 1, profile);
-                        }
-                    }
-                    if (profile->mChannelMasks[0] == 0) {
-                        reply = mpClientInterface->getParameters(output,
-                                                      String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS));
-                        ALOGV("checkOutputsForDevice() direct output sup channel masks %s",
-                                  reply.string());
-                        value = strpbrk((char *)reply.string(), "=");
-                        if (value != NULL) {
-                            loadOutChannels(value + 1, profile);
-                        }
+                }
+                if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
+                    reply = mpClientInterface->getParameters(output,
+                                                   String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
+                    ALOGV("checkOutputsForDevice() direct output sup formats %s",
+                              reply.string());
+                    value = strpbrk((char *)reply.string(), "=");
+                    if (value != NULL) {
+                        loadFormats(value + 1, profile);
                     }
-                    if (((profile->mSamplingRates[0] == 0) &&
-                             (profile->mSamplingRates.size() < 2)) ||
-                         ((profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) &&
-                             (profile->mFormats.size() < 2)) ||
-                         ((profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) &&
-                             (profile->mChannelMasks.size() < 2))) {
-                        ALOGW("checkOutputsForDevice() direct output missing param");
-                        mpClientInterface->closeOutput(output);
-                        output = 0;
-                    } else {
-                        addOutput(output, desc);
+                }
+                if (profile->mChannelMasks[0] == 0) {
+                    reply = mpClientInterface->getParameters(output,
+                                                  String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS));
+                    ALOGV("checkOutputsForDevice() direct output sup channel masks %s",
+                              reply.string());
+                    value = strpbrk((char *)reply.string(), "=");
+                    if (value != NULL) {
+                        loadOutChannels(value + 1, profile);
                     }
-                } else {
-                    audio_io_handle_t duplicatedOutput = 0;
-                    // add output descriptor
+                }
+                if (((profile->mSamplingRates[0] == 0) &&
+                         (profile->mSamplingRates.size() < 2)) ||
+                     ((profile->mFormats[0] == 0) &&
+                         (profile->mFormats.size() < 2)) ||
+                     ((profile->mChannelMasks[0] == 0) &&
+                         (profile->mChannelMasks.size() < 2))) {
+                    ALOGW("checkOutputsForDevice() direct output missing param");
+                    mpClientInterface->closeOutput(output);
+                    output = 0;
+                } else if (profile->mSamplingRates[0] == 0) {
+                    mpClientInterface->closeOutput(output);
+                    desc->mSamplingRate = profile->mSamplingRates[1];
+                    offloadInfo.sample_rate = desc->mSamplingRate;
+                    output = mpClientInterface->openOutput(
+                                                    profile->mModule->mHandle,
+                                                    &desc->mDevice,
+                                                    &desc->mSamplingRate,
+                                                    &desc->mFormat,
+                                                    &desc->mChannelMask,
+                                                    &desc->mLatency,
+                                                    desc->mFlags,
+                                                    &offloadInfo);
+                }
+
+                if (output != 0) {
                     addOutput(output, desc);
-                    // set initial stream volume for device
-                    applyStreamVolumes(output, device, 0, true);
-
-                    //TODO: configure audio effect output stage here
-
-                    // open a duplicating output thread for the new output and the primary output
-                    duplicatedOutput = mpClientInterface->openDuplicateOutput(output,
-                                                                              mPrimaryOutput);
-                    if (duplicatedOutput != 0) {
-                        // add duplicated output descriptor
-                        AudioOutputDescriptor *dupOutputDesc = new AudioOutputDescriptor(NULL);
-                        dupOutputDesc->mOutput1 = mOutputs.valueFor(mPrimaryOutput);
-                        dupOutputDesc->mOutput2 = mOutputs.valueFor(output);
-                        dupOutputDesc->mSamplingRate = desc->mSamplingRate;
-                        dupOutputDesc->mFormat = desc->mFormat;
-                        dupOutputDesc->mChannelMask = desc->mChannelMask;
-                        dupOutputDesc->mLatency = desc->mLatency;
-                        addOutput(duplicatedOutput, dupOutputDesc);
-                        applyStreamVolumes(duplicatedOutput, device, 0, true);
-                    } else {
-                        ALOGW("checkOutputsForDevice() could not open dup output for %d and %d",
-                                mPrimaryOutput, output);
-                        mpClientInterface->closeOutput(output);
-                        mOutputs.removeItem(output);
-                        output = 0;
+                    if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) {
+                        audio_io_handle_t duplicatedOutput = 0;
+
+                        // set initial stream volume for device
+                        applyStreamVolumes(output, device, 0, true);
+
+                        //TODO: configure audio effect output stage here
+
+                        // open a duplicating output thread for the new output and the primary output
+                        duplicatedOutput = mpClientInterface->openDuplicateOutput(output,
+                                                                                  mPrimaryOutput);
+                        if (duplicatedOutput != 0) {
+                            // add duplicated output descriptor
+                            AudioOutputDescriptor *dupOutputDesc = new AudioOutputDescriptor(NULL);
+                            dupOutputDesc->mOutput1 = mOutputs.valueFor(mPrimaryOutput);
+                            dupOutputDesc->mOutput2 = mOutputs.valueFor(output);
+                            dupOutputDesc->mSamplingRate = desc->mSamplingRate;
+                            dupOutputDesc->mFormat = desc->mFormat;
+                            dupOutputDesc->mChannelMask = desc->mChannelMask;
+                            dupOutputDesc->mLatency = desc->mLatency;
+                            addOutput(duplicatedOutput, dupOutputDesc);
+                            applyStreamVolumes(duplicatedOutput, device, 0, true);
+                        } else {
+                            ALOGW("checkOutputsForDevice() could not open dup output for %d and %d",
+                                    mPrimaryOutput, output);
+                            mpClientInterface->closeOutput(output);
+                            mOutputs.removeItem(output);
+                            output = 0;
+                        }
                     }
                 }
             }
@@ -1981,7 +2020,7 @@ status_t AudioPolicyManagerBase::checkOutputsForDevice(audio_devices_t device,
             ALOGW("checkOutputsForDevice(): No output available for device %04x", device);
             return BAD_VALUE;
         }
-    } else {
+    } else { // Disconnect
         // check if one opened output is not needed any more after disconnecting one device
         for (size_t i = 0; i < mOutputs.size(); i++) {
             desc = mOutputs.valueAt(i);
@@ -1991,6 +2030,7 @@ status_t AudioPolicyManagerBase::checkOutputsForDevice(audio_devices_t device,
                 outputs.add(mOutputs.keyAt(i));
             }
         }
+        // Clear any profiles associated with the disconnected device.
         for (size_t i = 0; i < mHwModules.size(); i++)
         {
             if (mHwModules[i]->mHandle == 0) {
@@ -1999,9 +2039,8 @@ status_t AudioPolicyManagerBase::checkOutputsForDevice(audio_devices_t device,
             for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
             {
                 IOProfile *profile = mHwModules[i]->mOutputProfiles[j];
-                if ((profile->mSupportedDevices & device) &&
-                        (profile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) {
-                    ALOGV("checkOutputsForDevice(): clearing direct output profile %d on module %d",
+                if (profile->mSupportedDevices & device) {
+                    ALOGV("checkOutputsForDevice(): clearing direct output profile %zu on module %zu",
                           j, i);
                     if (profile->mSamplingRates[0] == 0) {
                         profile->mSamplingRates.clear();
@@ -2022,6 +2061,184 @@ status_t AudioPolicyManagerBase::checkOutputsForDevice(audio_devices_t device,
     return NO_ERROR;
 }
 
+status_t AudioPolicyManagerBase::checkInputsForDevice(audio_devices_t device,
+                                                      AudioSystem::device_connection_state state,
+                                                      SortedVector<audio_io_handle_t>& inputs,
+                                                      const String8 paramStr)
+{
+    AudioInputDescriptor *desc;
+    if (state == AudioSystem::DEVICE_STATE_AVAILABLE) {
+        // first list already open inputs that can be routed to this device
+        for (size_t input_index = 0; input_index < mInputs.size(); input_index++) {
+            desc = mInputs.valueAt(input_index);
+            if (desc->mProfile->mSupportedDevices & (device & ~AUDIO_DEVICE_BIT_IN)) {
+                ALOGV("checkInputsForDevice(): adding opened input %d", mInputs.keyAt(input_index));
+               inputs.add(mInputs.keyAt(input_index));
+            }
+        }
+
+        // then look for input profiles that can be routed to this device
+        SortedVector<IOProfile *> profiles;
+        for (size_t module_index = 0; module_index < mHwModules.size(); module_index++)
+        {
+            if (mHwModules[module_index]->mHandle == 0) {
+                continue;
+            }
+            for (size_t profile_index = 0;
+                 profile_index < mHwModules[module_index]->mInputProfiles.size();
+                 profile_index++)
+            {
+                if (mHwModules[module_index]->mInputProfiles[profile_index]->mSupportedDevices
+                        & (device & ~AUDIO_DEVICE_BIT_IN)) {
+                    ALOGV("checkInputsForDevice(): adding profile %d from module %d",
+                          profile_index, module_index);
+                    profiles.add(mHwModules[module_index]->mInputProfiles[profile_index]);
+                }
+            }
+        }
+
+        if (profiles.isEmpty() && inputs.isEmpty()) {
+            ALOGW("checkInputsForDevice(): No input available for device 0x%X", device);
+            return BAD_VALUE;
+        }
+
+        // open inputs for matching profiles if needed. Direct inputs are also opened to
+        // query for dynamic parameters and will be closed later by setDeviceConnectionState()
+        for (ssize_t profile_index = 0; profile_index < (ssize_t)profiles.size(); profile_index++) {
+
+            IOProfile *profile = profiles[profile_index];
+            // nothing to do if one input is already opened for this profile
+            size_t input_index;
+            for (input_index = 0; input_index < mInputs.size(); input_index++) {
+                desc = mInputs.valueAt(input_index);
+                if (desc->mProfile == profile) {
+                    break;
+                }
+            }
+            if (input_index != mInputs.size()) {
+                continue;
+            }
+
+            ALOGV("opening input for device 0x%X with params %s", device, paramStr.string());
+            desc = new AudioInputDescriptor(profile);
+            desc->mDevice = device;
+
+            audio_io_handle_t input = mpClientInterface->openInput(profile->mModule->mHandle,
+                                            &desc->mDevice,
+                                            &desc->mSamplingRate,
+                                            &desc->mFormat,
+                                            &desc->mChannelMask);
+
+            if (input != 0) {
+                if (!paramStr.isEmpty()) {
+                    mpClientInterface->setParameters(input, paramStr);
+                }
+
+                // Here is where we step through and resolve any "dynamic" fields
+                String8 reply;
+                char *value;
+                if (profile->mSamplingRates[0] == 0) {
+                    reply = mpClientInterface->getParameters(input,
+                                            String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES));
+                    ALOGV("checkInputsForDevice() direct input sup sampling rates %s",
+                              reply.string());
+                    value = strpbrk((char *)reply.string(), "=");
+                    if (value != NULL) {
+                        loadSamplingRates(value + 1, profile);
+                    }
+                }
+                if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
+                    reply = mpClientInterface->getParameters(input,
+                                                   String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
+                    ALOGV("checkInputsForDevice() direct input sup formats %s", reply.string());
+                    value = strpbrk((char *)reply.string(), "=");
+                    if (value != NULL) {
+                        loadFormats(value + 1, profile);
+                    }
+                }
+                if (profile->mChannelMasks[0] == 0) {
+                    reply = mpClientInterface->getParameters(input,
+                                                  String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS));
+                    ALOGV("checkInputsForDevice() direct input sup channel masks %s",
+                              reply.string());
+                    value = strpbrk((char *)reply.string(), "=");
+                    if (value != NULL) {
+                        loadInChannels(value + 1, profile);
+                    }
+                }
+                if (((profile->mSamplingRates[0] == 0) && (profile->mSamplingRates.size() < 2)) ||
+                     ((profile->mFormats[0] == 0) && (profile->mFormats.size() < 2)) ||
+                     ((profile->mChannelMasks[0] == 0) && (profile->mChannelMasks.size() < 2))) {
+                    ALOGW("checkInputsForDevice() direct input missing param");
+                    mpClientInterface->closeInput(input);
+                    input = 0;
+                }
+
+                if (input != 0) {
+                    addInput(input, desc);
+                }
+            } // endif input != 0
+
+            if (input == 0) {
+                ALOGW("checkInputsForDevice() could not open input for device 0x%X", device);
+                delete desc;
+                profiles.removeAt(profile_index);
+                profile_index--;
+            } else {
+                inputs.add(input);
+                ALOGV("checkInputsForDevice(): adding input %d", input);
+            }
+        } // end scan profiles
+
+        if (profiles.isEmpty()) {
+            ALOGW("checkInputsForDevice(): No input available for device 0x%X", device);
+            return BAD_VALUE;
+        }
+    } else {
+        // Disconnect
+        // check if one opened input is not needed any more after disconnecting one device
+        for (size_t input_index = 0; input_index < mInputs.size(); input_index++) {
+            desc = mInputs.valueAt(input_index);
+            if (!(desc->mProfile->mSupportedDevices & mAvailableInputDevices)) {
+                ALOGV("checkInputsForDevice(): disconnecting adding input %d",
+                      mInputs.keyAt(input_index));
+                inputs.add(mInputs.keyAt(input_index));
+            }
+        }
+        // Clear any profiles associated with the disconnected device.
+        for (size_t module_index = 0; module_index < mHwModules.size(); module_index++)
+        {
+            if (mHwModules[module_index]->mHandle == 0) {
+                continue;
+            }
+            for (size_t profile_index = 0;
+                 profile_index < mHwModules[module_index]->mInputProfiles.size();
+                 profile_index++)
+            {
+                IOProfile *profile = mHwModules[module_index]->mInputProfiles[profile_index];
+                if (profile->mSupportedDevices & device) {
+                    ALOGV("checkInputsForDevice(): clearing direct input profile %d on module %d",
+                          profile_index, module_index);
+                    if (profile->mSamplingRates[0] == 0) {
+                        profile->mSamplingRates.clear();
+                        profile->mSamplingRates.add(0);
+                    }
+                    if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
+                        profile->mFormats.clear();
+                        profile->mFormats.add(AUDIO_FORMAT_DEFAULT);
+                    }
+                    if (profile->mChannelMasks[0] == 0) {
+                        profile->mChannelMasks.clear();
+                        profile->mChannelMasks.add(0);
+                    }
+                }
+            }
+        }
+    } // end disconnect
+
+    return NO_ERROR;
+}
+
 void AudioPolicyManagerBase::closeOutput(audio_io_handle_t output)
 {
     ALOGV("closeOutput(%d)", output);
@@ -2143,9 +2360,7 @@ void AudioPolicyManagerBase::checkOutputForStrategy(routing_strategy strategy)
         // Move tracks associated to this strategy from previous output to new output
         for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) {
             if (getStrategy((AudioSystem::stream_type)i) == strategy) {
-                //FIXME see fixme on name change
-                mpClientInterface->setStreamOutput((AudioSystem::stream_type)i,
-                                                   dstOutputs[0] /* ignored */);
+                mpClientInterface->invalidateStream((AudioSystem::stream_type)i);
             }
         }
     }
@@ -2639,7 +2854,22 @@ uint32_t AudioPolicyManagerBase::setOutputDevice(audio_io_handle_t output,
 
     if (device != AUDIO_DEVICE_NONE) {
         outputDesc->mDevice = device;
+
+        // Force routing if previously asked for this output
+        if (outputDesc->mForceRouting) {
+            ALOGV("Force routing to current device as previous device was null for this output");
+            force = true;
+
+            // Request consumed. Reset mForceRouting to false
+            outputDesc->mForceRouting = false;
+        }
+    }
+    else {
+        // Device is null and does not reflect the routing. Save the necessity to force
+        // re-routing upon next attempt to select a non-null device for this output
+        outputDesc->mForceRouting = true;
     }
+
     muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
 
     // Do not change the routing if:
@@ -2669,7 +2899,6 @@ AudioPolicyManagerBase::IOProfile *AudioPolicyManagerBase::getInputProfile(audio
 {
     // Choose an input profile based on the requested capture parameters: select the first available
     // profile supporting all requested parameters.
-
     for (size_t i = 0; i < mHwModules.size(); i++)
     {
         if (mHwModules[i]->mHandle == 0) {
@@ -2678,6 +2907,7 @@ AudioPolicyManagerBase::IOProfile *AudioPolicyManagerBase::getInputProfile(audio
         for (size_t j = 0; j < mHwModules[i]->mInputProfiles.size(); j++)
         {
             IOProfile *profile = mHwModules[i]->mInputProfiles[j];
+            // profile->log();
             if (profile->isCompatibleProfile(device, samplingRate, format,
                                              channelMask, AUDIO_OUTPUT_FLAG_NONE)) {
                 return profile;
@@ -2701,6 +2931,12 @@ audio_devices_t AudioPolicyManagerBase::getDeviceForInputSource(int inputSource)
 
     case AUDIO_SOURCE_DEFAULT:
     case AUDIO_SOURCE_MIC:
+    if (mAvailableInputDevices & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {
+        device = AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
+        break;
+    }
+    // FALL THROUGH
+
     case AUDIO_SOURCE_VOICE_RECOGNITION:
     case AUDIO_SOURCE_HOTWORD:
     case AUDIO_SOURCE_VOICE_COMMUNICATION:
@@ -2709,6 +2945,8 @@ audio_devices_t AudioPolicyManagerBase::getDeviceForInputSource(int inputSource)
             device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
         } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_WIRED_HEADSET) {
             device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+        } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_USB_DEVICE) {
+            device = AUDIO_DEVICE_IN_USB_DEVICE;
         } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BUILTIN_MIC) {
             device = AUDIO_DEVICE_IN_BUILTIN_MIC;
         }
@@ -2915,7 +3153,7 @@ const AudioPolicyManagerBase::VolumeCurvePoint
 };
 
 const AudioPolicyManagerBase::VolumeCurvePoint
-            *AudioPolicyManagerBase::sVolumeProfiles[AUDIO_STREAM_CNT]
+            *AudioPolicyManagerBase::sVolumeProfiles[AudioSystem::NUM_STREAM_TYPES]
                                                    [AudioPolicyManagerBase::DEVICE_CATEGORY_CNT] = {
     { // AUDIO_STREAM_VOICE_CALL
         sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET
@@ -2971,7 +3209,7 @@ const AudioPolicyManagerBase::VolumeCurvePoint
 
 void AudioPolicyManagerBase::initializeVolumeCurves()
 {
-    for (int i = 0; i < AUDIO_STREAM_CNT; i++) {
+    for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
         for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) {
             mStreams[i].mVolumeCurve[j] =
                     sVolumeProfiles[i][j];
@@ -3008,9 +3246,7 @@ float AudioPolicyManagerBase::computeVolume(int stream,
     if (stream == AudioSystem::MUSIC &&
         index != mStreams[stream].mIndexMin &&
         (device == AUDIO_DEVICE_OUT_AUX_DIGITAL ||
-         device == AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET ||
-         device == AUDIO_DEVICE_OUT_USB_ACCESSORY ||
-         device == AUDIO_DEVICE_OUT_USB_DEVICE)) {
+         device == AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET)) {
         return 1.0;
     }
 
@@ -3254,7 +3490,8 @@ AudioPolicyManagerBase::AudioOutputDescriptor::AudioOutputDescriptor(
     : mId(0), mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT),
       mChannelMask(0), mLatency(0),
     mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE),
-    mOutput1(0), mOutput2(0), mProfile(profile), mDirectOpenCount(0)
+    mOutput1(0), mOutput2(0), mProfile(profile), mDirectOpenCount(0),
+    mForceRouting(false)
 {
     // clear usage count for all stream types
     for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
@@ -3403,10 +3640,15 @@ status_t AudioPolicyManagerBase::AudioOutputDescriptor::dump(int fd)
 // --- AudioInputDescriptor class implementation
 
 AudioPolicyManagerBase::AudioInputDescriptor::AudioInputDescriptor(const IOProfile *profile)
-    : mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT), mChannelMask(0),
+    :  mId(0), mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT), mChannelMask(0),
       mDevice(AUDIO_DEVICE_NONE), mRefCount(0),
       mInputSource(0), mProfile(profile)
 {
+    if (profile != NULL) {
+         mSamplingRate = profile->mSamplingRates[0];
+         mFormat = profile->mFormats[0];
+         mChannelMask = profile->mChannelMasks[0];
+     }
 }
 
 status_t AudioPolicyManagerBase::AudioInputDescriptor::dump(int fd)
@@ -3523,7 +3765,7 @@ void AudioPolicyManagerBase::HwModule::dump(int fd)
     if (mOutputProfiles.size()) {
         write(fd, "  - outputs:\n", strlen("  - outputs:\n"));
         for (size_t i = 0; i < mOutputProfiles.size(); i++) {
-            snprintf(buffer, SIZE, "    output %d:\n", i);
+            snprintf(buffer, SIZE, "    output %zu:\n", i);
             write(fd, buffer, strlen(buffer));
             mOutputProfiles[i]->dump(fd);
         }
@@ -3531,7 +3773,7 @@ void AudioPolicyManagerBase::HwModule::dump(int fd)
     if (mInputProfiles.size()) {
         write(fd, "  - inputs:\n", strlen("  - inputs:\n"));
         for (size_t i = 0; i < mInputProfiles.size(); i++) {
-            snprintf(buffer, SIZE, "    input %d:\n", i);
+            snprintf(buffer, SIZE, "    input %zu:\n", i);
             write(fd, buffer, strlen(buffer));
             mInputProfiles[i]->dump(fd);
         }
@@ -3635,6 +3877,31 @@ void AudioPolicyManagerBase::IOProfile::dump(int fd)
     write(fd, result.string(), result.size());
 }
 
+void AudioPolicyManagerBase::IOProfile::log()
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    ALOGV("    - sampling rates: ");
+    for (size_t i = 0; i < mSamplingRates.size(); i++) {
+        ALOGV("  %d", mSamplingRates[i]);
+    }
+
+    ALOGV("    - channel masks: ");
+    for (size_t i = 0; i < mChannelMasks.size(); i++) {
+        ALOGV("  0x%04x", mChannelMasks[i]);
+    }
+
+    ALOGV("    - formats: ");
+    for (size_t i = 0; i < mFormats.size(); i++) {
+        ALOGV("  0x%08x", mFormats[i]);
+    }
+
+    ALOGV("    - devices: 0x%04x\n", mSupportedDevices);
+    ALOGV("    - flags: 0x%04x\n", mFlags);
+}
+
 // --- audio_policy.conf file parsing
 
 struct StringToEnum {
@@ -3669,6 +3936,8 @@ const struct StringToEnum sDeviceNameToEnumTable[] = {
     STRING_TO_ENUM(AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET),
     STRING_TO_ENUM(AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET),
     STRING_TO_ENUM(AUDIO_DEVICE_IN_USB_ACCESSORY),
+    STRING_TO_ENUM(AUDIO_DEVICE_IN_USB_DEVICE),
+    STRING_TO_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_A2DP),
 };
 
 const struct StringToEnum sFlagNameToEnumTable[] = {
@@ -3683,9 +3952,18 @@ const struct StringToEnum sFlagNameToEnumTable[] = {
 const struct StringToEnum sFormatNameToEnumTable[] = {
     STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT),
     STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_BIT),
+    STRING_TO_ENUM(AUDIO_FORMAT_PCM_32_BIT),
+    STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_24_BIT),
+    STRING_TO_ENUM(AUDIO_FORMAT_PCM_FLOAT),
+    STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_PACKED),
     STRING_TO_ENUM(AUDIO_FORMAT_MP3),
     STRING_TO_ENUM(AUDIO_FORMAT_AAC),
     STRING_TO_ENUM(AUDIO_FORMAT_VORBIS),
+    STRING_TO_ENUM(AUDIO_FORMAT_HE_AAC_V1),
+    STRING_TO_ENUM(AUDIO_FORMAT_HE_AAC_V2),
+    STRING_TO_ENUM(AUDIO_FORMAT_OPUS),
+    STRING_TO_ENUM(AUDIO_FORMAT_AC3),
+    STRING_TO_ENUM(AUDIO_FORMAT_E_AC3),
 };
 
 const struct StringToEnum sOutChannelsNameToEnumTable[] = {
@@ -3888,7 +4166,7 @@ status_t AudioPolicyManagerBase::loadInput(cnode *root, HwModule *module)
             (profile->mSamplingRates.size() != 0) &&
             (profile->mFormats.size() != 0)) {
 
-        ALOGV("loadInput() adding input mSupportedDevices %04x", profile->mSupportedDevices);
+        ALOGV("loadInput() adding input mSupportedDevices 0x%X", profile->mSupportedDevices);
 
         module->mInputProfiles.add(profile);
         return NO_ERROR;