diff options
author | Eric Laurent <elaurent@google.com> | 2014-03-27 01:22:16 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2014-03-27 01:22:16 +0000 |
commit | ec31c8d17f587cba01d5516ccd336aa54323c668 (patch) | |
tree | 7c18ea28c41e59211b5cc99f2ef42b897977d83c /services | |
parent | c9b8d90dabdf1234be0117c592f635a92c4eb0d9 (diff) | |
parent | 3a4311c68348f728558e87b5db67d47605783890 (diff) | |
download | frameworks_av-ec31c8d17f587cba01d5516ccd336aa54323c668.zip frameworks_av-ec31c8d17f587cba01d5516ccd336aa54323c668.tar.gz frameworks_av-ec31c8d17f587cba01d5516ccd336aa54323c668.tar.bz2 |
Merge "audio policy: use new audio device representation"
Diffstat (limited to 'services')
-rw-r--r-- | services/audiopolicy/AudioPolicyManager.cpp | 764 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyManager.h | 66 |
2 files changed, 549 insertions, 281 deletions
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp index 5ac9d9e..eeba124 100644 --- a/services/audiopolicy/AudioPolicyManager.cpp +++ b/services/audiopolicy/AudioPolicyManager.cpp @@ -43,6 +43,117 @@ namespace android { // ---------------------------------------------------------------------------- +// Definitions for audio_policy.conf file parsing +// ---------------------------------------------------------------------------- + +struct StringToEnum { + const char *name; + uint32_t value; +}; + +#define STRING_TO_ENUM(string) { #string, string } +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +const StringToEnum sDeviceNameToEnumTable[] = { + STRING_TO_ENUM(AUDIO_DEVICE_OUT_EARPIECE), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_SPEAKER), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADSET), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADPHONE), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_SCO), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_SCO), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_A2DP), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_AUX_DIGITAL), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_USB_ACCESSORY), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_USB_DEVICE), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_USB), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_REMOTE_SUBMIX), + STRING_TO_ENUM(AUDIO_DEVICE_IN_BUILTIN_MIC), + STRING_TO_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET), + STRING_TO_ENUM(AUDIO_DEVICE_IN_ALL_SCO), + STRING_TO_ENUM(AUDIO_DEVICE_IN_WIRED_HEADSET), + STRING_TO_ENUM(AUDIO_DEVICE_IN_AUX_DIGITAL), + STRING_TO_ENUM(AUDIO_DEVICE_IN_VOICE_CALL), + STRING_TO_ENUM(AUDIO_DEVICE_IN_BACK_MIC), + STRING_TO_ENUM(AUDIO_DEVICE_IN_REMOTE_SUBMIX), + 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), +}; + +const StringToEnum sFlagNameToEnumTable[] = { + STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DIRECT), + STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_PRIMARY), + STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_FAST), + STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DEEP_BUFFER), + STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD), + STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_NON_BLOCKING), +}; + +const 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), +}; + +const StringToEnum sOutChannelsNameToEnumTable[] = { + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_MONO), + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO), + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1), + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1), +}; + +const StringToEnum sInChannelsNameToEnumTable[] = { + STRING_TO_ENUM(AUDIO_CHANNEL_IN_MONO), + STRING_TO_ENUM(AUDIO_CHANNEL_IN_STEREO), + STRING_TO_ENUM(AUDIO_CHANNEL_IN_FRONT_BACK), +}; + + +uint32_t AudioPolicyManager::stringToEnum(const struct StringToEnum *table, + size_t size, + const char *name) +{ + for (size_t i = 0; i < size; i++) { + if (strcmp(table[i].name, name) == 0) { + ALOGV("stringToEnum() found %s", table[i].name); + return table[i].value; + } + } + return 0; +} + +const char *AudioPolicyManager::enumToString(const struct StringToEnum *table, + size_t size, + uint32_t value) +{ + for (size_t i = 0; i < size; i++) { + if (table[i].value == value) { + return table[i].name; + } + } + return ""; +} + +bool AudioPolicyManager::stringToBool(const char *value) +{ + return ((strcasecmp("true", value) == 0) || (strcmp("1", value) == 0)); +} + + +// ---------------------------------------------------------------------------- // AudioPolicyInterface implementation // ---------------------------------------------------------------------------- @@ -52,6 +163,7 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, const char *device_address) { SortedVector <audio_io_handle_t> outputs; + String8 address = String8(device_address); ALOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address); @@ -79,74 +191,50 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, return BAD_VALUE; } + sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device, + address, + AUDIO_CHANNEL_NONE); + ssize_t index = mAvailableOutputDevices.indexOf(devDesc); + // save a copy of the opened output descriptors before any output is opened or closed // by checkOutputsForDevice(). This will be needed by checkOutputForAllStrategies() mPreviousOutputs = mOutputs; - String8 paramStr; switch (state) { // handle output device connection case AUDIO_POLICY_DEVICE_STATE_AVAILABLE: - if (mAvailableOutputDevices & device) { + if (index >= 0) { ALOGW("setDeviceConnectionState() device already connected: %x", device); return INVALID_OPERATION; } ALOGV("setDeviceConnectionState() connecting device %x", device); - if (mHasA2dp && audio_is_a2dp_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)) { - // handle USB device connection - paramStr = String8(device_address, MAX_DEVICE_ADDRESS_LEN); - } - - if (checkOutputsForDevice(device, state, outputs, paramStr) != NO_ERROR) { + if (checkOutputsForDevice(device, state, outputs, address) != NO_ERROR) { return INVALID_OPERATION; } ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %d outputs", outputs.size()); // register new device as available - mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices | device); - - if (mHasA2dp && audio_is_a2dp_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)) { - // handle USB device connection - mUsbCardAndDevice = String8(device_address, MAX_DEVICE_ADDRESS_LEN); + index = mAvailableOutputDevices.add(devDesc); + if (index >= 0) { + mAvailableOutputDevices[index]->mId = nextUniqueId(); + } else { + return NO_MEMORY; } break; // handle output device disconnection case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE: { - if (!(mAvailableOutputDevices & device)) { + if (index < 0) { ALOGW("setDeviceConnectionState() device not connected: %x", device); return INVALID_OPERATION; } 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)) { - // 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)) { - // handle USB device disconnection - mUsbCardAndDevice = ""; - } + mAvailableOutputDevices.remove(devDesc); + + checkOutputsForDevice(device, state, outputs, address); // not currently handling multiple simultaneous submixes: ignoring remote submix // case and address } break; @@ -156,6 +244,8 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, return BAD_VALUE; } + // checkA2dpSuspend must run before checkOutputForAllStrategies so that A2DP + // output is suspended before any tracks are moved to it checkA2dpSuspend(); checkOutputForAllStrategies(); // outputs must be closed after checkOutputForAllStrategies() is executed @@ -170,6 +260,8 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, closeOutput(outputs[i]); } } + // check again after closing A2DP output to reset mA2dpSuspended if needed + checkA2dpSuspend(); } updateDevicesAndOutputs(); @@ -195,26 +287,35 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, } // handle input devices if (audio_is_input_device(device)) { + sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device, + address, + AUDIO_CHANNEL_NONE); + ssize_t index = mAvailableInputDevices.indexOf(devDesc); switch (state) { // handle input device connection case AUDIO_POLICY_DEVICE_STATE_AVAILABLE: { - if (mAvailableInputDevices & device) { + if (index >= 0) { ALOGW("setDeviceConnectionState() device already connected: %d", device); return INVALID_OPERATION; } - mAvailableInputDevices = mAvailableInputDevices | (device & ~AUDIO_DEVICE_BIT_IN); + index = mAvailableInputDevices.add(devDesc); + if (index >= 0) { + mAvailableInputDevices[index]->mId = nextUniqueId(); + } else { + return NO_MEMORY; + } } break; // handle input device disconnection case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE: { - if (!(mAvailableInputDevices & device)) { + if (index < 0) { ALOGW("setDeviceConnectionState() device not connected: %d", device); return INVALID_OPERATION; } - mAvailableInputDevices = (audio_devices_t) (mAvailableInputDevices & ~device); + mAvailableInputDevices.remove(devDesc); } break; default: @@ -248,33 +349,27 @@ audio_policy_dev_state_t AudioPolicyManager::getDeviceConnectionState(audio_devi { audio_policy_dev_state_t state = AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE; String8 address = String8(device_address); + sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device, + String8(device_address), + AUDIO_CHANNEL_NONE); + ssize_t index; + DeviceVector *deviceVector; + if (audio_is_output_device(device)) { - if (device & mAvailableOutputDevices) { - if (audio_is_a2dp_device(device) && - (!mHasA2dp || (address != "" && mA2dpDeviceAddress != address))) { - return state; - } - if (audio_is_bluetooth_sco_device(device) && - address != "" && mScoDeviceAddress != address) { - return state; - } - if (audio_is_usb_device(device) && - (!mHasUsb || (address != "" && mUsbCardAndDevice != address))) { - ALOGE("getDeviceConnectionState() invalid device: %x", device); - return state; - } - if (audio_is_remote_submix_device((audio_devices_t)device) && !mHasRemoteSubmix) { - return state; - } - state = AUDIO_POLICY_DEVICE_STATE_AVAILABLE; - } + deviceVector = &mAvailableOutputDevices; } else if (audio_is_input_device(device)) { - if (device & mAvailableInputDevices) { - state = AUDIO_POLICY_DEVICE_STATE_AVAILABLE; - } + deviceVector = &mAvailableInputDevices; + } else { + ALOGW("getDeviceConnectionState() invalid device type %08x", device); + return AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE; } - return state; + index = deviceVector->indexOf(devDesc); + if (index >= 0) { + return AUDIO_POLICY_DEVICE_STATE_AVAILABLE; + } else { + return AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE; + } } void AudioPolicyManager::setPhoneState(audio_mode_t state) @@ -505,23 +600,23 @@ AudioPolicyManager::IOProfile *AudioPolicyManager::getProfileForDirectOutput( } for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) { IOProfile *profile = mHwModules[i]->mOutputProfiles[j]; + bool found = false; if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) { if (profile->isCompatibleProfile(device, samplingRate, format, channelMask, AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) { - if (mAvailableOutputDevices & profile->mSupportedDevices) { - return mHwModules[i]->mOutputProfiles[j]; - } + found = true; } } else { if (profile->isCompatibleProfile(device, samplingRate, format, channelMask, AUDIO_OUTPUT_FLAG_DIRECT)) { - if (mAvailableOutputDevices & profile->mSupportedDevices) { - return mHwModules[i]->mOutputProfiles[j]; - } + found = true; } } + if (found && (mAvailableOutputDevices.types() & profile->mSupportedDevices.types())) { + return profile; + } } } return 0; @@ -1377,16 +1472,6 @@ status_t AudioPolicyManager::dump(int fd) snprintf(buffer, SIZE, " Primary Output: %d\n", mPrimaryOutput); result.append(buffer); - snprintf(buffer, SIZE, " A2DP device address: %s\n", mA2dpDeviceAddress.string()); - 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()); - result.append(buffer); - snprintf(buffer, SIZE, " Output devices: %08x\n", mAvailableOutputDevices); - result.append(buffer); - snprintf(buffer, SIZE, " Input devices: %08x\n", mAvailableInputDevices); - result.append(buffer); snprintf(buffer, SIZE, " Phone state: %d\n", mPhoneState); result.append(buffer); snprintf(buffer, SIZE, " Force use for communications %d\n", @@ -1400,8 +1485,20 @@ status_t AudioPolicyManager::dump(int fd) result.append(buffer); snprintf(buffer, SIZE, " Force use for system %d\n", mForceUse[AUDIO_POLICY_FORCE_FOR_SYSTEM]); result.append(buffer); - write(fd, result.string(), result.size()); + snprintf(buffer, SIZE, " Available output devices:\n"); + result.append(buffer); + write(fd, result.string(), result.size()); + DeviceDescriptor::dumpHeader(fd, 2); + for (size_t i = 0; i < mAvailableOutputDevices.size(); i++) { + mAvailableOutputDevices[i]->dump(fd, 2); + } + snprintf(buffer, SIZE, "\n Available input devices:\n"); + write(fd, buffer, strlen(buffer)); + DeviceDescriptor::dumpHeader(fd, 2); + for (size_t i = 0; i < mAvailableInputDevices.size(); i++) { + mAvailableInputDevices[i]->dump(fd, 2); + } snprintf(buffer, SIZE, "\nHW Modules dump:\n"); write(fd, buffer, strlen(buffer)); @@ -1525,18 +1622,22 @@ bool AudioPolicyManager::isOffloadSupported(const audio_offload_info_t& offloadI // AudioPolicyManager // ---------------------------------------------------------------------------- +uint32_t AudioPolicyManager::nextUniqueId() +{ + return android_atomic_inc(&mNextUniqueId); +} + AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface) : #ifdef AUDIO_POLICY_TEST Thread(false), #endif //AUDIO_POLICY_TEST mPrimaryOutput((audio_io_handle_t)0), - mAvailableOutputDevices(AUDIO_DEVICE_NONE), mPhoneState(AUDIO_MODE_NORMAL), mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f), mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0), - mA2dpSuspended(false), mHasA2dp(false), mHasUsb(false), mHasRemoteSubmix(false), - mSpeakerDrcEnabled(false) + mA2dpSuspended(false), + mSpeakerDrcEnabled(false), mNextUniqueId(0) { mpClientInterface = clientInterface; @@ -1544,21 +1645,21 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa mForceUse[i] = AUDIO_POLICY_FORCE_NONE; } - mA2dpDeviceAddress = String8(""); - mScoDeviceAddress = String8(""); - mUsbCardAndDevice = String8(""); - + mDefaultOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPEAKER); if (loadAudioPolicyConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE) != NO_ERROR) { if (loadAudioPolicyConfig(AUDIO_POLICY_CONFIG_FILE) != NO_ERROR) { ALOGE("could not load audio policy configuration file, setting defaults"); defaultAudioPolicyConfig(); } } + // mAvailableOutputDevices and mAvailableInputDevices now contain all attached devices // must be done after reading the policy initializeVolumeCurves(); // open all output streams needed to access attached devices + audio_devices_t outputDeviceTypes = mAvailableOutputDevices.types(); + audio_devices_t inputDeviceTypes = mAvailableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN; for (size_t i = 0; i < mHwModules.size(); i++) { mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->mName); if (mHwModules[i]->mHandle == 0) { @@ -1568,15 +1669,22 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa // open all output streams needed to access attached devices // except for direct output streams that are only opened when they are actually // required by an app. + // This also validates mAvailableOutputDevices list for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) { const IOProfile *outProfile = mHwModules[i]->mOutputProfiles[j]; - if ((outProfile->mSupportedDevices & mAttachedOutputDevices) && + if (outProfile->mSupportedDevices.isEmpty()) { + ALOGW("Output profile contains no device on module %s", mHwModules[i]->mName); + continue; + } + + audio_devices_t profileTypes = outProfile->mSupportedDevices.types(); + if ((profileTypes & outputDeviceTypes) && ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0)) { AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(outProfile); - outputDesc->mDevice = (audio_devices_t)(mDefaultOutputDevice & - outProfile->mSupportedDevices); + + outputDesc->mDevice = (audio_devices_t)(mDefaultOutputDevice->mType & profileTypes); audio_io_handle_t output = mpClientInterface->openOutput( outProfile->mModule->mHandle, &outputDesc->mDevice, @@ -1586,27 +1694,96 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa &outputDesc->mLatency, outputDesc->mFlags); if (output == 0) { + ALOGW("Cannot open output stream for device %08x on hw module %s", + outputDesc->mDevice, + mHwModules[i]->mName); delete outputDesc; } else { - mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices | - (outProfile->mSupportedDevices & mAttachedOutputDevices)); + for (size_t i = 0; i < outProfile->mSupportedDevices.size(); i++) { + audio_devices_t type = outProfile->mSupportedDevices[i]->mType; + ssize_t index = + mAvailableOutputDevices.indexOf(outProfile->mSupportedDevices[i]); + // give a valid ID to an attached device once confirmed it is reachable + if ((index >= 0) && (mAvailableOutputDevices[index]->mId == 0)) { + mAvailableOutputDevices[index]->mId = nextUniqueId(); + } + } if (mPrimaryOutput == 0 && outProfile->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY) { mPrimaryOutput = output; } addOutput(output, outputDesc); setOutputDevice(output, - (audio_devices_t)(mDefaultOutputDevice & - outProfile->mSupportedDevices), + outputDesc->mDevice, true); } } } - } + // open input streams needed to access attached devices to validate + // mAvailableInputDevices list + for (size_t j = 0; j < mHwModules[i]->mInputProfiles.size(); j++) + { + const IOProfile *inProfile = mHwModules[i]->mInputProfiles[j]; + + if (inProfile->mSupportedDevices.isEmpty()) { + ALOGW("Input profile contains no device on module %s", mHwModules[i]->mName); + continue; + } - ALOGE_IF((mAttachedOutputDevices & ~mAvailableOutputDevices), - "Not output found for attached devices %08x", - (mAttachedOutputDevices & ~mAvailableOutputDevices)); + audio_devices_t profileTypes = inProfile->mSupportedDevices.types(); + if (profileTypes & inputDeviceTypes) { + AudioInputDescriptor *inputDesc = new AudioInputDescriptor(inProfile); + + inputDesc->mInputSource = AUDIO_SOURCE_MIC; + inputDesc->mDevice = inProfile->mSupportedDevices[0]->mType; + audio_io_handle_t input = mpClientInterface->openInput( + inProfile->mModule->mHandle, + &inputDesc->mDevice, + &inputDesc->mSamplingRate, + &inputDesc->mFormat, + &inputDesc->mChannelMask); + + if (input != 0) { + for (size_t i = 0; i < inProfile->mSupportedDevices.size(); i++) { + audio_devices_t type = inProfile->mSupportedDevices[i]->mType; + ssize_t index = + mAvailableInputDevices.indexOf(inProfile->mSupportedDevices[i]); + // give a valid ID to an attached device once confirmed it is reachable + if ((index >= 0) && (mAvailableInputDevices[index]->mId == 0)) { + mAvailableInputDevices[index]->mId = nextUniqueId(); + } + } + mpClientInterface->closeInput(input); + } else { + ALOGW("Cannot open input stream for device %08x on hw module %s", + inputDesc->mDevice, + mHwModules[i]->mName); + } + delete inputDesc; + } + } + } + // make sure all attached devices have been allocated a unique ID + for (size_t i = 0; i < mAvailableOutputDevices.size();) { + if (mAvailableOutputDevices[i]->mId == 0) { + ALOGW("Input device %08x unreachable", mAvailableOutputDevices[i]->mType); + mAvailableOutputDevices.remove(mAvailableOutputDevices[i]); + continue; + } + i++; + } + for (size_t i = 0; i < mAvailableInputDevices.size();) { + if (mAvailableInputDevices[i]->mId == 0) { + ALOGW("Input device %08x unreachable", mAvailableInputDevices[i]->mType); + mAvailableInputDevices.remove(mAvailableInputDevices[i]); + continue; + } + i++; + } + // make sure default device is reachable + if (mAvailableOutputDevices.indexOf(mDefaultOutputDevice) < 0) { + ALOGE("Default device %08x is unreachable", mDefaultOutputDevice->mType); + } ALOGE_IF((mPrimaryOutput == 0), "Failed to open primary output"); @@ -1653,6 +1830,8 @@ AudioPolicyManager::~AudioPolicyManager() for (size_t i = 0; i < mHwModules.size(); i++) { delete mHwModules[i]; } + mAvailableOutputDevices.clear(); + mAvailableInputDevices.clear(); } status_t AudioPolicyManager::initCheck() @@ -1819,10 +1998,18 @@ void AudioPolicyManager::addOutput(audio_io_handle_t id, AudioOutputDescriptor * } +String8 AudioPolicyManager::addressToParameter(audio_devices_t device, const String8 address) +{ + if (device & AUDIO_DEVICE_OUT_ALL_A2DP) { + return String8("a2dp_sink_address=")+address; + } + return address; +} + status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device, audio_policy_dev_state_t state, SortedVector<audio_io_handle_t>& outputs, - const String8 paramStr) + const String8 address) { AudioOutputDescriptor *desc; @@ -1830,7 +2017,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device, // first list already open outputs that can be routed to this device for (size_t i = 0; i < mOutputs.size(); i++) { desc = mOutputs.valueAt(i); - if (!desc->isDuplicated() && (desc->mProfile->mSupportedDevices & device)) { + if (!desc->isDuplicated() && (desc->mProfile->mSupportedDevices.types() & device)) { ALOGV("checkOutputsForDevice(): adding opened output %d", mOutputs.keyAt(i)); outputs.add(mOutputs.keyAt(i)); } @@ -1844,7 +2031,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device, } for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) { - if (mHwModules[i]->mOutputProfiles[j]->mSupportedDevices & device) { + if (mHwModules[i]->mOutputProfiles[j]->mSupportedDevices.types() & device) { ALOGV("checkOutputsForDevice(): adding profile %d from module %d", j, i); profiles.add(mHwModules[i]->mOutputProfiles[j]); } @@ -1873,7 +2060,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device, continue; } - ALOGV("opening output for device %08x with params %s", device, paramStr.string()); + ALOGV("opening output for device %08x with params %s", device, address.string()); desc = new AudioOutputDescriptor(profile); desc->mDevice = device; audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER; @@ -1890,8 +2077,8 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device, desc->mFlags, &offloadInfo); if (output != 0) { - if (!paramStr.isEmpty()) { - mpClientInterface->setParameters(output, paramStr); + if (!address.isEmpty()) { + mpClientInterface->setParameters(output, addressToParameter(device, address)); } if (desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) { @@ -1991,7 +2178,8 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device, for (size_t i = 0; i < mOutputs.size(); i++) { desc = mOutputs.valueAt(i); if (!desc->isDuplicated() && - !(desc->mProfile->mSupportedDevices & mAvailableOutputDevices)) { + !(desc->mProfile->mSupportedDevices.types() & + mAvailableOutputDevices.types())) { ALOGV("checkOutputsForDevice(): disconnecting adding output %d", mOutputs.keyAt(i)); outputs.add(mOutputs.keyAt(i)); } @@ -2004,7 +2192,7 @@ status_t AudioPolicyManager::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) && + if ((profile->mSupportedDevices.types() & device) && (profile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) { ALOGV("checkOutputsForDevice(): clearing direct output profile %d on module %d", j, i); @@ -2187,9 +2375,12 @@ void AudioPolicyManager::checkA2dpSuspend() } audio_io_handle_t a2dpOutput = getA2dpOutput(); if (a2dpOutput == 0) { + mA2dpSuspended = false; return; } + bool isScoConnected = + (mAvailableInputDevices.types() & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) != 0; // suspend A2DP output if: // (NOT already suspended) && // ((SCO device is connected && @@ -2203,7 +2394,7 @@ void AudioPolicyManager::checkA2dpSuspend() // (phone state is NOT ringing && NOT in call) // if (mA2dpSuspended) { - if (((mScoDeviceAddress == "") || + if ((!isScoConnected || ((mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION] != AUDIO_POLICY_FORCE_BT_SCO) && (mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD] != AUDIO_POLICY_FORCE_BT_SCO))) && ((mPhoneState != AUDIO_MODE_IN_CALL) && @@ -2213,7 +2404,7 @@ void AudioPolicyManager::checkA2dpSuspend() mA2dpSuspended = false; } } else { - if (((mScoDeviceAddress != "") && + if ((isScoConnected && ((mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION] == AUDIO_POLICY_FORCE_BT_SCO) || (mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD] == AUDIO_POLICY_FORCE_BT_SCO))) || ((mPhoneState == AUDIO_MODE_IN_CALL) || @@ -2328,7 +2519,7 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate strategy, mDeviceForStrategy[strategy]); return mDeviceForStrategy[strategy]; } - + audio_devices_t availableOutputDeviceTypes = mAvailableOutputDevices.types(); switch (strategy) { case STRATEGY_SONIFICATION_RESPECTFUL: @@ -2366,45 +2557,45 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate switch (mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION]) { case AUDIO_POLICY_FORCE_BT_SCO: if (!isInCall() || strategy != STRATEGY_DTMF) { - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT; + device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT; if (device) break; } - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET; + device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET; if (device) break; - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO; + device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_SCO; if (device) break; // if SCO device is requested but no SCO device is available, fall back to default case // FALL THROUGH default: // FORCE_NONE // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP - if (mHasA2dp && !isInCall() && + if (!isInCall() && (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) && (getA2dpOutput() != 0) && !mA2dpSuspended) { - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP; + device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP; if (device) break; - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; + device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; if (device) break; } - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE; + device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_WIRED_HEADPHONE; if (device) break; - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADSET; + device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_WIRED_HEADSET; if (device) break; if (mPhoneState != AUDIO_MODE_IN_CALL) { - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY; + device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_USB_ACCESSORY; if (device) break; - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE; + device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_USB_DEVICE; if (device) break; - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET; + device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET; if (device) break; - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL; + device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_AUX_DIGITAL; if (device) break; - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; + device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; if (device) break; } - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_EARPIECE; + device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_EARPIECE; if (device) break; - device = mDefaultOutputDevice; + device = mDefaultOutputDevice->mType; if (device == AUDIO_DEVICE_NONE) { ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE"); } @@ -2413,27 +2604,27 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate case AUDIO_POLICY_FORCE_SPEAKER: // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to // A2DP speaker when forcing to speaker output - if (mHasA2dp && !isInCall() && + if (!isInCall() && (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) && (getA2dpOutput() != 0) && !mA2dpSuspended) { - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; + device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; if (device) break; } if (mPhoneState != AUDIO_MODE_IN_CALL) { - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY; + device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_USB_ACCESSORY; if (device) break; - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE; + device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_USB_DEVICE; if (device) break; - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET; + device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET; if (device) break; - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL; + device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_AUX_DIGITAL; if (device) break; - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; + device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; if (device) break; } - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER; + device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_SPEAKER; if (device) break; - device = mDefaultOutputDevice; + device = mDefaultOutputDevice->mType; if (device == AUDIO_DEVICE_NONE) { ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE, FORCE_SPEAKER"); } @@ -2459,7 +2650,7 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate if ((strategy == STRATEGY_SONIFICATION) || (mForceUse[AUDIO_POLICY_FORCE_FOR_SYSTEM] == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)) { - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER; + device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_SPEAKER; if (device == AUDIO_DEVICE_NONE) { ALOGE("getDeviceForStrategy() speaker device not found for STRATEGY_SONIFICATION"); } @@ -2471,52 +2662,51 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate uint32_t device2 = AUDIO_DEVICE_NONE; if (strategy != STRATEGY_SONIFICATION) { // no sonification on remote submix (e.g. WFD) - device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_REMOTE_SUBMIX; + device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_REMOTE_SUBMIX; } if ((device2 == AUDIO_DEVICE_NONE) && - mHasA2dp && (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) && (getA2dpOutput() != 0) && !mA2dpSuspended) { - device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP; + device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP; if (device2 == AUDIO_DEVICE_NONE) { - device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; + device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; } if (device2 == AUDIO_DEVICE_NONE) { - device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; + device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; } } if (device2 == AUDIO_DEVICE_NONE) { - device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE; + device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_WIRED_HEADPHONE; } if (device2 == AUDIO_DEVICE_NONE) { - device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADSET; + device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_WIRED_HEADSET; } if (device2 == AUDIO_DEVICE_NONE) { - device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY; + device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_USB_ACCESSORY; } if (device2 == AUDIO_DEVICE_NONE) { - device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE; + device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_USB_DEVICE; } if (device2 == AUDIO_DEVICE_NONE) { - device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET; + device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET; } if ((device2 == AUDIO_DEVICE_NONE) && (strategy != STRATEGY_SONIFICATION)) { // no sonification on aux digital (e.g. HDMI) - device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL; + device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_AUX_DIGITAL; } if ((device2 == AUDIO_DEVICE_NONE) && (mForceUse[AUDIO_POLICY_FORCE_FOR_DOCK] == AUDIO_POLICY_FORCE_ANALOG_DOCK)) { - device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; + device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; } if (device2 == AUDIO_DEVICE_NONE) { - device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER; + device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_SPEAKER; } // device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION or // STRATEGY_ENFORCED_AUDIBLE, AUDIO_DEVICE_NONE otherwise device |= device2; if (device) break; - device = mDefaultOutputDevice; + device = mDefaultOutputDevice->mType; if (device == AUDIO_DEVICE_NONE) { ALOGE("getDeviceForStrategy() no device found for STRATEGY_MEDIA"); } @@ -2630,12 +2820,12 @@ uint32_t AudioPolicyManager::setOutputDevice(audio_io_handle_t output, // no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current // output profile if ((device != AUDIO_DEVICE_NONE) && - ((device & outputDesc->mProfile->mSupportedDevices) == 0)) { + ((device & outputDesc->mProfile->mSupportedDevices.types()) == 0)) { return 0; } // filter devices according to output selected - device = (audio_devices_t)(device & outputDesc->mProfile->mSupportedDevices); + device = (audio_devices_t)(device & outputDesc->mProfile->mSupportedDevices.types()); audio_devices_t prevDevice = outputDesc->mDevice; @@ -2694,10 +2884,11 @@ AudioPolicyManager::IOProfile *AudioPolicyManager::getInputProfile(audio_devices audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t inputSource) { uint32_t device = AUDIO_DEVICE_NONE; - + audio_devices_t availableDeviceTypes = mAvailableInputDevices.types() & + ~AUDIO_DEVICE_BIT_IN; switch (inputSource) { case AUDIO_SOURCE_VOICE_UPLINK: - if (mAvailableInputDevices & AUDIO_DEVICE_IN_VOICE_CALL) { + if (availableDeviceTypes & AUDIO_DEVICE_IN_VOICE_CALL) { device = AUDIO_DEVICE_IN_VOICE_CALL; break; } @@ -2709,29 +2900,29 @@ audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t input case AUDIO_SOURCE_HOTWORD: case AUDIO_SOURCE_VOICE_COMMUNICATION: if (mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD] == AUDIO_POLICY_FORCE_BT_SCO && - mAvailableInputDevices & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) { + availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) { device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET; - } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_WIRED_HEADSET) { + } else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) { device = AUDIO_DEVICE_IN_WIRED_HEADSET; - } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BUILTIN_MIC) { + } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) { device = AUDIO_DEVICE_IN_BUILTIN_MIC; } break; case AUDIO_SOURCE_CAMCORDER: - if (mAvailableInputDevices & AUDIO_DEVICE_IN_BACK_MIC) { + if (availableDeviceTypes & AUDIO_DEVICE_IN_BACK_MIC) { device = AUDIO_DEVICE_IN_BACK_MIC; - } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BUILTIN_MIC) { + } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) { device = AUDIO_DEVICE_IN_BUILTIN_MIC; } break; case AUDIO_SOURCE_VOICE_DOWNLINK: case AUDIO_SOURCE_VOICE_CALL: - if (mAvailableInputDevices & AUDIO_DEVICE_IN_VOICE_CALL) { + if (availableDeviceTypes & AUDIO_DEVICE_IN_VOICE_CALL) { device = AUDIO_DEVICE_IN_VOICE_CALL; } break; case AUDIO_SOURCE_REMOTE_SUBMIX: - if (mAvailableInputDevices & AUDIO_DEVICE_IN_REMOTE_SUBMIX) { + if (availableDeviceTypes & AUDIO_DEVICE_IN_REMOTE_SUBMIX) { device = AUDIO_DEVICE_IN_REMOTE_SUBMIX; } break; @@ -3335,7 +3526,7 @@ audio_devices_t AudioPolicyManager::AudioOutputDescriptor::supportedDevices() if (isDuplicated()) { return (audio_devices_t)(mOutput1->supportedDevices() | mOutput2->supportedDevices()); } else { - return mProfile->mSupportedDevices ; + return mProfile->mSupportedDevices.types() ; } } @@ -3418,6 +3609,11 @@ AudioPolicyManager::AudioInputDescriptor::AudioInputDescriptor(const IOProfile * mDevice(AUDIO_DEVICE_NONE), mRefCount(0), mInputSource(AUDIO_SOURCE_DEFAULT), mProfile(profile) { + if (profile != NULL) { + mSamplingRate = profile->mSamplingRates[0]; + mFormat = profile->mFormats[0]; + mChannelMask = profile->mChannelMasks[0]; + } } status_t AudioPolicyManager::AudioInputDescriptor::dump(int fd) @@ -3512,10 +3708,12 @@ AudioPolicyManager::HwModule::HwModule(const char *name) AudioPolicyManager::HwModule::~HwModule() { for (size_t i = 0; i < mOutputProfiles.size(); i++) { - delete mOutputProfiles[i]; + mOutputProfiles[i]->mSupportedDevices.clear(); + delete mOutputProfiles[i]; } for (size_t i = 0; i < mInputProfiles.size(); i++) { - delete mInputProfiles[i]; + mInputProfiles[i]->mSupportedDevices.clear(); + delete mInputProfiles[i]; } free((void *)mName); } @@ -3571,7 +3769,7 @@ bool AudioPolicyManager::IOProfile::isCompatibleProfile(audio_devices_t device, return false; } - if ((mSupportedDevices & device) != device) { + if ((mSupportedDevices.types() & device) != device) { return false; } if ((mFlags & flags) != flags) { @@ -3638,103 +3836,129 @@ void AudioPolicyManager::IOProfile::dump(int fd) result.append(i == (mFormats.size() - 1) ? "\n" : ", "); } - snprintf(buffer, SIZE, " - devices: 0x%04x\n", mSupportedDevices); + snprintf(buffer, SIZE, " - devices:\n"); result.append(buffer); + write(fd, result.string(), result.size()); + DeviceDescriptor::dumpHeader(fd, 6); + for (size_t i = 0; i < mSupportedDevices.size(); i++) { + mSupportedDevices[i]->dump(fd, 6); + } + snprintf(buffer, SIZE, " - flags: 0x%04x\n", mFlags); result.append(buffer); write(fd, result.string(), result.size()); } -// --- audio_policy.conf file parsing +// --- DeviceDescriptor implementation -struct StringToEnum { - const char *name; - uint32_t value; -}; - -#define STRING_TO_ENUM(string) { #string, string } -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +bool AudioPolicyManager::DeviceDescriptor::equals(const sp<DeviceDescriptor>& other) const +{ + // Devices are considered equal if they: + // - are of the same type (a device type cannot be AUDIO_DEVICE_NONE) + // - have the same address or one device does not specify the address + // - have the same channel mask or one device does not specify the channel mask + return (mType == other->mType) && + (mAddress == "" || other->mAddress == "" || mAddress == other->mAddress) && + (mChannelMask == AUDIO_CHANNEL_NONE || other->mChannelMask == AUDIO_CHANNEL_NONE || + mChannelMask == other->mChannelMask); +} -const struct StringToEnum sDeviceNameToEnumTable[] = { - STRING_TO_ENUM(AUDIO_DEVICE_OUT_EARPIECE), - STRING_TO_ENUM(AUDIO_DEVICE_OUT_SPEAKER), - STRING_TO_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADSET), - STRING_TO_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADPHONE), - STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_SCO), - STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_A2DP), - STRING_TO_ENUM(AUDIO_DEVICE_OUT_AUX_DIGITAL), - STRING_TO_ENUM(AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET), - STRING_TO_ENUM(AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET), - STRING_TO_ENUM(AUDIO_DEVICE_OUT_USB_DEVICE), - STRING_TO_ENUM(AUDIO_DEVICE_OUT_USB_ACCESSORY), - STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_USB), - STRING_TO_ENUM(AUDIO_DEVICE_OUT_REMOTE_SUBMIX), - STRING_TO_ENUM(AUDIO_DEVICE_IN_BUILTIN_MIC), - STRING_TO_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET), - STRING_TO_ENUM(AUDIO_DEVICE_IN_WIRED_HEADSET), - STRING_TO_ENUM(AUDIO_DEVICE_IN_AUX_DIGITAL), - STRING_TO_ENUM(AUDIO_DEVICE_IN_VOICE_CALL), - STRING_TO_ENUM(AUDIO_DEVICE_IN_BACK_MIC), - STRING_TO_ENUM(AUDIO_DEVICE_IN_REMOTE_SUBMIX), - 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), -}; +void AudioPolicyManager::DeviceVector::refreshTypes() +{ + mTypes = AUDIO_DEVICE_NONE; + for(size_t i = 0; i < size(); i++) { + mTypes |= itemAt(i)->mType; + } + ALOGV("DeviceVector::refreshTypes() mTypes %08x", mTypes); +} -const struct StringToEnum sFlagNameToEnumTable[] = { - STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DIRECT), - STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_PRIMARY), - STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_FAST), - STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DEEP_BUFFER), - STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD), - STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_NON_BLOCKING), -}; +ssize_t AudioPolicyManager::DeviceVector::indexOf(const sp<DeviceDescriptor>& item) const +{ + for(size_t i = 0; i < size(); i++) { + if (item->equals(itemAt(i))) { + return i; + } + } + return -1; +} -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), -}; +ssize_t AudioPolicyManager::DeviceVector::add(const sp<DeviceDescriptor>& item) +{ + ssize_t ret = indexOf(item); -const struct StringToEnum sOutChannelsNameToEnumTable[] = { - STRING_TO_ENUM(AUDIO_CHANNEL_OUT_MONO), - STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO), - STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1), - STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1), -}; + if (ret < 0) { + ret = SortedVector::add(item); + if (ret >= 0) { + refreshTypes(); + } + } else { + ALOGW("DeviceVector::add device %08x already in", item->mType); + ret = -1; + } + return ret; +} -const struct StringToEnum sInChannelsNameToEnumTable[] = { - STRING_TO_ENUM(AUDIO_CHANNEL_IN_MONO), - STRING_TO_ENUM(AUDIO_CHANNEL_IN_STEREO), - STRING_TO_ENUM(AUDIO_CHANNEL_IN_FRONT_BACK), -}; +ssize_t AudioPolicyManager::DeviceVector::remove(const sp<DeviceDescriptor>& item) +{ + size_t i; + ssize_t ret = indexOf(item); + if (ret < 0) { + ALOGW("DeviceVector::remove device %08x not in", item->mType); + } else { + ret = SortedVector::removeAt(ret); + if (ret >= 0) { + refreshTypes(); + } + } + return ret; +} -uint32_t AudioPolicyManager::stringToEnum(const struct StringToEnum *table, - size_t size, - const char *name) +void AudioPolicyManager::DeviceVector::loadDevicesFromType(audio_devices_t types) { - for (size_t i = 0; i < size; i++) { - if (strcmp(table[i].name, name) == 0) { - ALOGV("stringToEnum() found %s", table[i].name); - return table[i].value; - } + DeviceVector deviceList; + + uint32_t role_bit = AUDIO_DEVICE_BIT_IN & types; + types &= ~role_bit; + + while (types) { + uint32_t i = 31 - __builtin_clz(types); + uint32_t type = 1 << i; + types &= ~type; + add(new DeviceDescriptor(type | role_bit)); } - return 0; } -bool AudioPolicyManager::stringToBool(const char *value) +void AudioPolicyManager::DeviceDescriptor::dumpHeader(int fd, int spaces) { - return ((strcasecmp("true", value) == 0) || (strcmp("1", value) == 0)); + const size_t SIZE = 256; + char buffer[SIZE]; + + snprintf(buffer, SIZE, "%*s%-48s %-2s %-8s %-32s \n", + spaces, "", "Type", "ID", "Cnl Mask", "Address"); + write(fd, buffer, strlen(buffer)); } +status_t AudioPolicyManager::DeviceDescriptor::dump(int fd, int spaces) const +{ + const size_t SIZE = 256; + char buffer[SIZE]; + + snprintf(buffer, SIZE, "%*s%-48s %2d %08x %-32s \n", + spaces, "", + enumToString(sDeviceNameToEnumTable, + ARRAY_SIZE(sDeviceNameToEnumTable), + mType), + mId, mChannelMask, mAddress.string()); + write(fd, buffer, strlen(buffer)); + + return NO_ERROR; +} + + +// --- audio_policy.conf file parsing + audio_output_flags_t AudioPolicyManager::parseFlagNames(char *name) { uint32_t flag = 0; @@ -3770,9 +3994,9 @@ audio_devices_t AudioPolicyManager::parseDeviceNames(char *name) device |= stringToEnum(sDeviceNameToEnumTable, ARRAY_SIZE(sDeviceNameToEnumTable), devName); - } + } devName = strtok(NULL, "|"); - } + } return device; } @@ -3886,11 +4110,11 @@ status_t AudioPolicyManager::loadInput(cnode *root, HwModule *module) } else if (strcmp(node->name, CHANNELS_TAG) == 0) { loadInChannels((char *)node->value, profile); } else if (strcmp(node->name, DEVICES_TAG) == 0) { - profile->mSupportedDevices = parseDeviceNames((char *)node->value); + profile->mSupportedDevices.loadDevicesFromType(parseDeviceNames((char *)node->value)); } node = node->next; } - ALOGW_IF(profile->mSupportedDevices == AUDIO_DEVICE_NONE, + ALOGW_IF(profile->mSupportedDevices.isEmpty(), "loadInput() invalid supported devices"); ALOGW_IF(profile->mChannelMasks.size() == 0, "loadInput() invalid supported channel masks"); @@ -3898,12 +4122,13 @@ status_t AudioPolicyManager::loadInput(cnode *root, HwModule *module) "loadInput() invalid supported sampling rates"); ALOGW_IF(profile->mFormats.size() == 0, "loadInput() invalid supported formats"); - if ((profile->mSupportedDevices != AUDIO_DEVICE_NONE) && + if (!profile->mSupportedDevices.isEmpty() && (profile->mChannelMasks.size() != 0) && (profile->mSamplingRates.size() != 0) && (profile->mFormats.size() != 0)) { - ALOGV("loadInput() adding input mSupportedDevices %04x", profile->mSupportedDevices); + ALOGV("loadInput() adding input Supported Devices %04x", + profile->mSupportedDevices.types()); module->mInputProfiles.add(profile); return NO_ERROR; @@ -3927,13 +4152,13 @@ status_t AudioPolicyManager::loadOutput(cnode *root, HwModule *module) } else if (strcmp(node->name, CHANNELS_TAG) == 0) { loadOutChannels((char *)node->value, profile); } else if (strcmp(node->name, DEVICES_TAG) == 0) { - profile->mSupportedDevices = parseDeviceNames((char *)node->value); + profile->mSupportedDevices.loadDevicesFromType(parseDeviceNames((char *)node->value)); } else if (strcmp(node->name, FLAGS_TAG) == 0) { profile->mFlags = parseFlagNames((char *)node->value); } node = node->next; } - ALOGW_IF(profile->mSupportedDevices == AUDIO_DEVICE_NONE, + ALOGW_IF(profile->mSupportedDevices.isEmpty(), "loadOutput() invalid supported devices"); ALOGW_IF(profile->mChannelMasks.size() == 0, "loadOutput() invalid supported channel masks"); @@ -3941,13 +4166,13 @@ status_t AudioPolicyManager::loadOutput(cnode *root, HwModule *module) "loadOutput() invalid supported sampling rates"); ALOGW_IF(profile->mFormats.size() == 0, "loadOutput() invalid supported formats"); - if ((profile->mSupportedDevices != AUDIO_DEVICE_NONE) && + if (!profile->mSupportedDevices.isEmpty() && (profile->mChannelMasks.size() != 0) && (profile->mSamplingRates.size() != 0) && (profile->mFormats.size() != 0)) { - ALOGV("loadOutput() adding output mSupportedDevices %04x, mFlags %04x", - profile->mSupportedDevices, profile->mFlags); + ALOGV("loadOutput() adding output Supported Devices %04x, mFlags %04x", + profile->mSupportedDevices.types(), profile->mFlags); module->mOutputProfiles.add(profile); return NO_ERROR; @@ -4026,20 +4251,22 @@ void AudioPolicyManager::loadGlobalConfig(cnode *root) node = node->first_child; while (node) { if (strcmp(ATTACHED_OUTPUT_DEVICES_TAG, node->name) == 0) { - mAttachedOutputDevices = parseDeviceNames((char *)node->value); - ALOGW_IF(mAttachedOutputDevices == AUDIO_DEVICE_NONE, - "loadGlobalConfig() no attached output devices"); - ALOGV("loadGlobalConfig() mAttachedOutputDevices %04x", mAttachedOutputDevices); + mAvailableOutputDevices.loadDevicesFromType(parseDeviceNames((char *)node->value)); + ALOGV("loadGlobalConfig() Attached Output Devices %08x", + mAvailableOutputDevices.types()); } else if (strcmp(DEFAULT_OUTPUT_DEVICE_TAG, node->name) == 0) { - mDefaultOutputDevice = (audio_devices_t)stringToEnum(sDeviceNameToEnumTable, + audio_devices_t device = (audio_devices_t)stringToEnum(sDeviceNameToEnumTable, ARRAY_SIZE(sDeviceNameToEnumTable), (char *)node->value); - ALOGW_IF(mDefaultOutputDevice == AUDIO_DEVICE_NONE, - "loadGlobalConfig() default device not specified"); - ALOGV("loadGlobalConfig() mDefaultOutputDevice %04x", mDefaultOutputDevice); + if (device != AUDIO_DEVICE_NONE) { + mDefaultOutputDevice = new DeviceDescriptor(device); + } else { + ALOGW("loadGlobalConfig() default device not specified"); + } + ALOGV("loadGlobalConfig() mDefaultOutputDevice %08x", mDefaultOutputDevice->mType); } else if (strcmp(ATTACHED_INPUT_DEVICES_TAG, node->name) == 0) { - mAvailableInputDevices = parseDeviceNames((char *)node->value) & ~AUDIO_DEVICE_BIT_IN; - ALOGV("loadGlobalConfig() mAvailableInputDevices %04x", mAvailableInputDevices); + mAvailableInputDevices.loadDevicesFromType(parseDeviceNames((char *)node->value)); + ALOGV("loadGlobalConfig() Available InputDevices %08x", mAvailableInputDevices.types()); } else if (strcmp(SPEAKER_DRC_ENABLED_TAG, node->name) == 0) { mSpeakerDrcEnabled = stringToBool((char *)node->value); ALOGV("loadGlobalConfig() mSpeakerDrcEnabled = %d", mSpeakerDrcEnabled); @@ -4076,10 +4303,9 @@ void AudioPolicyManager::defaultAudioPolicyConfig(void) { HwModule *module; IOProfile *profile; - - mDefaultOutputDevice = AUDIO_DEVICE_OUT_SPEAKER; - mAttachedOutputDevices = AUDIO_DEVICE_OUT_SPEAKER; - mAvailableInputDevices = AUDIO_DEVICE_IN_BUILTIN_MIC & ~AUDIO_DEVICE_BIT_IN; + sp<DeviceDescriptor> defaultInputDevice = new DeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC); + mAvailableOutputDevices.add(mDefaultOutputDevice); + mAvailableInputDevices.add(defaultInputDevice); module = new HwModule("primary"); @@ -4087,7 +4313,7 @@ void AudioPolicyManager::defaultAudioPolicyConfig(void) profile->mSamplingRates.add(44100); profile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT); profile->mChannelMasks.add(AUDIO_CHANNEL_OUT_STEREO); - profile->mSupportedDevices = AUDIO_DEVICE_OUT_SPEAKER; + profile->mSupportedDevices.add(mDefaultOutputDevice); profile->mFlags = AUDIO_OUTPUT_FLAG_PRIMARY; module->mOutputProfiles.add(profile); @@ -4095,7 +4321,7 @@ void AudioPolicyManager::defaultAudioPolicyConfig(void) profile->mSamplingRates.add(8000); profile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT); profile->mChannelMasks.add(AUDIO_CHANNEL_IN_MONO); - profile->mSupportedDevices = AUDIO_DEVICE_IN_BUILTIN_MIC; + profile->mSupportedDevices.add(defaultInputDevice); module->mInputProfiles.add(profile); mHwModules.add(module); diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h index e00d8ab..4c366bd 100644 --- a/services/audiopolicy/AudioPolicyManager.h +++ b/services/audiopolicy/AudioPolicyManager.h @@ -175,6 +175,47 @@ protected: class IOProfile; + class DeviceDescriptor: public RefBase + { + public: + DeviceDescriptor(audio_devices_t type, String8 address, + audio_channel_mask_t channelMask) : + mType(type), mAddress(address), + mChannelMask(channelMask), mId(0) {} + + DeviceDescriptor(audio_devices_t type) : + mType(type), mAddress(""), + mChannelMask(AUDIO_CHANNEL_NONE), mId(0) {} + + status_t dump(int fd, int spaces) const; + static void dumpHeader(int fd, int spaces); + + bool equals(const sp<DeviceDescriptor>& other) const; + + audio_devices_t mType; + String8 mAddress; + audio_channel_mask_t mChannelMask; + uint32_t mId; + }; + + class DeviceVector : public SortedVector< sp<DeviceDescriptor> > + { + public: + DeviceVector() : SortedVector(), mTypes(AUDIO_DEVICE_NONE) {} + + ssize_t add(const sp<DeviceDescriptor>& item); + ssize_t remove(const sp<DeviceDescriptor>& item); + ssize_t indexOf(const sp<DeviceDescriptor>& item) const; + + audio_devices_t types() const { return mTypes; } + + void loadDevicesFromType(audio_devices_t types); + + private: + void refreshTypes(); + audio_devices_t mTypes; + }; + class HwModule { public: HwModule(const char *name); @@ -213,8 +254,8 @@ protected: Vector <uint32_t> mSamplingRates; // supported sampling rates Vector <audio_channel_mask_t> mChannelMasks; // supported channel masks Vector <audio_format_t> mFormats; // supported audio formats - audio_devices_t mSupportedDevices; // supported devices (devices this output can be - // routed to) + DeviceVector mSupportedDevices; // supported devices + // (devices this output can be routed to) audio_output_flags_t mFlags; // attribute flags (e.g primary output, // direct output...). For outputs only. HwModule *mModule; // audio HW module exposing this I/O stream @@ -411,7 +452,7 @@ protected: status_t checkOutputsForDevice(audio_devices_t device, audio_policy_dev_state_t state, SortedVector<audio_io_handle_t>& outputs, - const String8 paramStr); + const String8 address); // close an output and its companion duplicating output. void closeOutput(audio_io_handle_t output); @@ -496,6 +537,9 @@ protected: static uint32_t stringToEnum(const struct StringToEnum *table, size_t size, const char *name); + static const char *enumToString(const struct StringToEnum *table, + size_t size, + uint32_t value); static bool stringToBool(const char *value); static audio_output_flags_t parseFlagNames(char *name); static audio_devices_t parseDeviceNames(char *name); @@ -520,18 +564,14 @@ protected: // reset to mOutputs when updateDevicesAndOutputs() is called. DefaultKeyedVector<audio_io_handle_t, AudioOutputDescriptor *> mPreviousOutputs; DefaultKeyedVector<audio_io_handle_t, AudioInputDescriptor *> mInputs; // list of input descriptors - audio_devices_t mAvailableOutputDevices; // bit field of all available output devices - audio_devices_t mAvailableInputDevices; // bit field of all available input devices + DeviceVector mAvailableOutputDevices; // bit field of all available output devices + DeviceVector mAvailableInputDevices; // bit field of all available input devices // without AUDIO_DEVICE_BIT_IN to allow direct bit // field comparisons int mPhoneState; // current phone state audio_policy_forced_cfg_t mForceUse[AUDIO_POLICY_FORCE_USE_CNT]; // current forced use configuration StreamDescriptor mStreams[AUDIO_STREAM_CNT]; // stream descriptors for volume control - String8 mA2dpDeviceAddress; // A2DP device MAC address - String8 mScoDeviceAddress; // SCO device MAC address - String8 mUsbCardAndDevice; // USB audio ALSA card and device numbers: - // card=<card_number>;device=<><device_number> bool mLimitRingtoneVolume; // limit ringtone volume to music volume if headset connected audio_devices_t mDeviceForStrategy[NUM_STRATEGIES]; float mLastVoiceVolume; // last voice volume value sent to audio HAL @@ -547,13 +587,12 @@ protected: bool mHasA2dp; // true on platforms with support for bluetooth A2DP bool mHasUsb; // true on platforms with support for USB audio bool mHasRemoteSubmix; // true on platforms with support for remote presentation of a submix - audio_devices_t mAttachedOutputDevices; // output devices always available on the platform - audio_devices_t mDefaultOutputDevice; // output device selected by default at boot time - // (must be in mAttachedOutputDevices) + sp<DeviceDescriptor> mDefaultOutputDevice; // output device selected by default at boot time bool mSpeakerDrcEnabled;// true on devices that use DRC on the DEVICE_CATEGORY_SPEAKER path // to boost soft sounds, used to adjust volume curves accordingly Vector <HwModule *> mHwModules; + volatile int32_t mNextUniqueId; #ifdef AUDIO_POLICY_TEST Mutex mLock; @@ -577,6 +616,9 @@ private: // routing of notifications void handleNotificationRoutingForStream(audio_stream_type_t stream); static bool isVirtualInputDevice(audio_devices_t device); + uint32_t nextUniqueId(); + // converts device address to string sent to audio HAL via setParameters + static String8 addressToParameter(audio_devices_t device, const String8 address); }; }; |