audiopolicy: Add support for hybrid mode on A2DP
Add support in AudioPolicyManager to select a module,
device or output based on device type and codec.
Implement hybrid mode with A2DP which enables runtime
switching between HALs for A2DP based on offload support
for specific A2DP codecs.
Optimize A2DP active device change and device config
change in AudioPolicyManager.
Bug: 111812273
Test: make
Change-Id: I246d71dd08bacbca6ed9b0012e7d7698bd8a0953
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index 46a2a40..837ca47 100644
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -76,6 +76,21 @@
}
/**
+ * Check whether audio device has encoding capability.
+ *
+ * @param[in] device to consider
+ *
+ * @return true if device has encoding capability, false otherwise..
+ */
+static inline bool device_has_encoding_capability(audio_devices_t device)
+{
+ if (device & AUDIO_DEVICE_OUT_ALL_A2DP) {
+ return true;
+ }
+ return false;
+}
+
+/**
* Returns the priority of a given audio source for capture. The priority is used when more than one
* capture session is active on a given input stream to determine which session drives routing and
* effect configuration.
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 14b995b..e1ecc61 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -154,6 +154,7 @@
void setDevices(const DeviceVector &devices) { mDevices = devices; }
bool sharesHwModuleWith(const sp<SwAudioOutputDescriptor>& outputDesc);
virtual DeviceVector supportedDevices() const;
+ virtual bool deviceSupportsEncodedFormats(audio_devices_t device);
virtual uint32_t latency();
virtual bool isDuplicated() const { return (mOutput1 != NULL && mOutput2 != NULL); }
virtual bool isFixedVolume(audio_devices_t device);
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index b581665..cc43fe6 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -44,8 +44,18 @@
const FormatVector& encodedFormats() const { return mEncodedFormats; }
+ audio_format_t getEncodedFormat() { return mCurrentEncodedFormat; }
+
+ void setEncodedFormat(audio_format_t format) {
+ mCurrentEncodedFormat = format;
+ }
+
bool equals(const sp<DeviceDescriptor>& other) const;
+ bool hasCurrentEncodedFormat() const;
+
+ bool supportsFormat(audio_format_t format);
+
// AudioPortConfig
virtual sp<AudioPort> getAudioPort() const { return (AudioPort*) this; }
virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
@@ -69,6 +79,7 @@
audio_devices_t mDeviceType;
FormatVector mEncodedFormats;
audio_port_handle_t mId = AUDIO_PORT_HANDLE_NONE;
+ audio_format_t mCurrentEncodedFormat;
};
class DeviceVector : public SortedVector<sp<DeviceDescriptor> >
@@ -88,9 +99,10 @@
audio_devices_t types() const { return mDeviceTypes; }
- // If 'address' is empty, a device with a non-empty address may be returned
- // if there is no device with the specified 'type' and empty address.
- sp<DeviceDescriptor> getDevice(audio_devices_t type, const String8 &address = {}) const;
+ // If 'address' is empty and 'codec' is AUDIO_FORMAT_DEFAULT, a device with a non-empty
+ // address may be returned if there is no device with the specified 'type' and empty address.
+ sp<DeviceDescriptor> getDevice(audio_devices_t type, const String8 &address,
+ audio_format_t codec) const;
DeviceVector getDevicesFromTypeMask(audio_devices_t types) const;
/**
diff --git a/services/audiopolicy/common/managerdefinitions/include/HwModule.h b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
index d7dc4b0..eb34da4 100644
--- a/services/audiopolicy/common/managerdefinitions/include/HwModule.h
+++ b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
@@ -130,9 +130,11 @@
public:
sp<HwModule> getModuleFromName(const char *name) const;
- sp<HwModule> getModuleForDeviceTypes(audio_devices_t device) const;
+ sp<HwModule> getModuleForDeviceTypes(audio_devices_t device,
+ audio_format_t encodedFormat) const;
- sp<HwModule> getModuleForDevice(const sp<DeviceDescriptor> &device) const;
+ sp<HwModule> getModuleForDevice(const sp<DeviceDescriptor> &device,
+ audio_format_t encodedFormat) const;
DeviceVector getAvailableDevicesFromModuleName(const char *name,
const DeviceVector &availableDevices) const;
@@ -149,6 +151,7 @@
* @param type of the device requested
* @param address of the device requested
* @param name of the device that requested
+ * @param encodedFormat if not AUDIO_FORMAT_DEFAULT, must match one supported format
* @param matchAddress true if a strong match is required
* @param allowToCreate true if allowed to create dynamic device (e.g. hdmi, usb...)
* @return device descriptor associated to the type (and address if matchAddress is true)
@@ -156,6 +159,7 @@
sp<DeviceDescriptor> getDeviceDescriptor(const audio_devices_t type,
const char *address,
const char *name,
+ audio_format_t encodedFormat,
bool allowToCreate = false,
bool matchAddress = true) const;
@@ -171,7 +175,8 @@
*/
sp<DeviceDescriptor> createDevice(const audio_devices_t type,
const char *address,
- const char *name) const;
+ const char *name,
+ const audio_format_t encodedFormat) const;
/**
* @brief cleanUpForDevice: loop on all profiles of all modules to remove device from
diff --git a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
index d0c05a5..dc409a7 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
@@ -94,7 +94,10 @@
bool supportsDeviceTypes(audio_devices_t device) const
{
if (audio_is_output_devices(device)) {
- return mSupportedDevices.types() & device;
+ if (deviceSupportsEncodedFormats(device)) {
+ return mSupportedDevices.types() & device;
+ }
+ return false;
}
return mSupportedDevices.types() & (device & ~AUDIO_DEVICE_BIT_IN);
}
@@ -116,6 +119,16 @@
return mSupportedDevices.contains(device);
}
+ bool deviceSupportsEncodedFormats(audio_devices_t device) const
+ {
+ DeviceVector deviceList =
+ mSupportedDevices.getDevicesFromTypeMask(device);
+ if (!deviceList.empty()) {
+ return deviceList.itemAt(0)->hasCurrentEncodedFormat();
+ }
+ return false;
+ }
+
void clearSupportedDevices() { mSupportedDevices.clear(); }
void addSupportedDevice(const sp<DeviceDescriptor> &device)
{
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 643cbd1..57328f0 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -364,6 +364,16 @@
return filteredDevices.filter(devices);
}
+bool SwAudioOutputDescriptor::deviceSupportsEncodedFormats(audio_devices_t device)
+{
+ if (isDuplicated()) {
+ return (mOutput1->deviceSupportsEncodedFormats(device)
+ || mOutput2->deviceSupportsEncodedFormats(device));
+ } else {
+ return mProfile->deviceSupportsEncodedFormats(device);
+ }
+}
+
uint32_t SwAudioOutputDescriptor::latency()
{
if (isDuplicated()) {
@@ -687,7 +697,9 @@
for (size_t i = 0; i < size(); i++) {
sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
if (!outputDesc->isDuplicated() &&
- outputDesc->devices().types() & AUDIO_DEVICE_OUT_ALL_A2DP) {
+ outputDesc->devices().types() & AUDIO_DEVICE_OUT_ALL_A2DP &&
+ outputDesc->deviceSupportsEncodedFormats(
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP)) {
return this->keyAt(i);
}
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index d18091c..799950c 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -296,7 +296,8 @@
// assuming PolicyMix only for remote submix for input
// so mix->mDeviceType can only be AUDIO_DEVICE_OUT_REMOTE_SUBMIX
audio_devices_t device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
- auto mixDevice = availDevices.getDevice(device, mix->mDeviceAddress);
+ auto mixDevice =
+ availDevices.getDevice(device, mix->mDeviceAddress, AUDIO_FORMAT_DEFAULT);
if (mixDevice != nullptr) {
if (policyMix != NULL) {
*policyMix = mix;
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index 01111c5..2ed8455 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -18,6 +18,7 @@
//#define LOG_NDEBUG 0
#include <audio_utils/string.h>
+#include <set>
#include "DeviceDescriptor.h"
#include "TypeConverter.h"
#include "AudioGain.h"
@@ -37,6 +38,7 @@
AUDIO_PORT_ROLE_SOURCE),
mTagName(tagName), mDeviceType(type), mEncodedFormats(encodedFormats)
{
+ mCurrentEncodedFormat = AUDIO_FORMAT_DEFAULT;
if (type == AUDIO_DEVICE_IN_REMOTE_SUBMIX || type == AUDIO_DEVICE_OUT_REMOTE_SUBMIX ) {
mAddress = String8("0");
}
@@ -45,6 +47,12 @@
mEncodedFormats.add(AUDIO_FORMAT_AC3);
mEncodedFormats.add(AUDIO_FORMAT_IEC61937);
}
+ // For backward compatibility always indicate support for SBC and AAC if no
+ // supported format is listed in the configuration file
+ if ((type & AUDIO_DEVICE_OUT_ALL_A2DP) != 0 && mEncodedFormats.isEmpty()) {
+ mEncodedFormats.add(AUDIO_FORMAT_SBC);
+ mEncodedFormats.add(AUDIO_FORMAT_AAC);
+ }
}
audio_port_handle_t DeviceDescriptor::getId() const
@@ -58,21 +66,49 @@
mId = getNextUniqueId();
}
-void DeviceDescriptor::detach()
-{
+void DeviceDescriptor::detach() {
mId = AUDIO_PORT_HANDLE_NONE;
AudioPort::detach();
}
+template<typename T>
+bool checkEqual(const T& f1, const T& f2)
+{
+ std::set<typename T::value_type> s1(f1.begin(), f1.end());
+ std::set<typename T::value_type> s2(f2.begin(), f2.end());
+ return s1 == s2;
+}
+
bool 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
+ // - have the same encodingFormats (if device supports encoding)
if (other == 0) {
return false;
}
- return (mDeviceType == other->mDeviceType) && (mAddress == other->mAddress);
+
+ return (mDeviceType == other->mDeviceType) && (mAddress == other->mAddress) &&
+ checkEqual(mEncodedFormats, other->mEncodedFormats);
+}
+
+bool DeviceDescriptor::hasCurrentEncodedFormat() const
+{
+ if (!device_has_encoding_capability(type())) {
+ return true;
+ }
+ return (mCurrentEncodedFormat != AUDIO_FORMAT_DEFAULT);
+}
+
+bool DeviceDescriptor::supportsFormat(audio_format_t format)
+{
+ for (const auto& devFormat : mEncodedFormats) {
+ if (devFormat == format) {
+ return true;
+ }
+ }
+ return false;
}
void DeviceVector::refreshTypes()
@@ -167,12 +203,17 @@
return deviceTypes;
}
-sp<DeviceDescriptor> DeviceVector::getDevice(audio_devices_t type, const String8& address) const
+sp<DeviceDescriptor> DeviceVector::getDevice(audio_devices_t type, const String8& address,
+ audio_format_t format) const
{
sp<DeviceDescriptor> device;
for (size_t i = 0; i < size(); i++) {
if (itemAt(i)->type() == type) {
- if (address == "" || itemAt(i)->address() == address) {
+ // Assign device if address is empty or matches and
+ // format is default or matches
+ if (((address == "" || itemAt(i)->address() == address) &&
+ format == AUDIO_FORMAT_DEFAULT) ||
+ itemAt(i)->supportsFormat(format)) {
device = itemAt(i);
if (itemAt(i)->address() == address) {
break;
@@ -180,8 +221,8 @@
}
}
}
- ALOGV("DeviceVector::%s() for type %08x address \"%s\" found %p",
- __func__, type, address.string(), device.get());
+ ALOGV("DeviceVector::%s() for type %08x address \"%s\" found %p format %08x",
+ __func__, type, address.string(), device.get(), format);
return device;
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index 7d2d094..85d9bce 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -273,32 +273,34 @@
return nullptr;
}
-sp <HwModule> HwModuleCollection::getModuleForDeviceTypes(audio_devices_t device) const
+sp <HwModule> HwModuleCollection::getModuleForDeviceTypes(audio_devices_t type,
+ audio_format_t encodedFormat) const
{
for (const auto& module : *this) {
- const auto& profiles = audio_is_output_device(device) ?
+ const auto& profiles = audio_is_output_device(type) ?
module->getOutputProfiles() : module->getInputProfiles();
for (const auto& profile : profiles) {
- if (profile->supportsDeviceTypes(device)) {
- return module;
+ if (profile->supportsDeviceTypes(type)) {
+ if (encodedFormat != AUDIO_FORMAT_DEFAULT) {
+ DeviceVector declaredDevices = module->getDeclaredDevices();
+ sp <DeviceDescriptor> deviceDesc =
+ declaredDevices.getDevice(type, String8(), encodedFormat);
+ if (deviceDesc) {
+ return module;
+ }
+ } else {
+ return module;
+ }
}
}
}
return nullptr;
}
-sp <HwModule> HwModuleCollection::getModuleForDevice(const sp<DeviceDescriptor> &device) const
+sp<HwModule> HwModuleCollection::getModuleForDevice(const sp<DeviceDescriptor> &device,
+ audio_format_t encodedFormat) const
{
- for (const auto& module : *this) {
- const auto& profiles = audio_is_output_device(device->type()) ?
- module->getOutputProfiles() : module->getInputProfiles();
- for (const auto& profile : profiles) {
- if (profile->supportsDevice(device)) {
- return module;
- }
- }
- }
- return nullptr;
+ return getModuleForDeviceTypes(device->type(), encodedFormat);
}
DeviceVector HwModuleCollection::getAvailableDevicesFromModuleName(
@@ -314,6 +316,7 @@
sp<DeviceDescriptor> HwModuleCollection::getDeviceDescriptor(const audio_devices_t deviceType,
const char *address,
const char *name,
+ const audio_format_t encodedFormat,
bool allowToCreate,
bool matchAddress) const
{
@@ -325,8 +328,14 @@
for (const auto& hwModule : *this) {
DeviceVector moduleDevices = hwModule->getAllDevices();
- auto moduleDevice = moduleDevices.getDevice(deviceType, devAddress);
+ auto moduleDevice = moduleDevices.getDevice(deviceType, devAddress, encodedFormat);
if (moduleDevice) {
+ if (encodedFormat != AUDIO_FORMAT_DEFAULT) {
+ moduleDevice->setEncodedFormat(encodedFormat);
+ if (moduleDevice->address() != devAddress) {
+ moduleDevice->setAddress(devAddress);
+ }
+ }
if (allowToCreate) {
moduleDevice->attach(hwModule);
}
@@ -338,14 +347,15 @@
name, deviceType, address);
return nullptr;
}
- return createDevice(deviceType, address, name);
+ return createDevice(deviceType, address, name, encodedFormat);
}
sp<DeviceDescriptor> HwModuleCollection::createDevice(const audio_devices_t type,
const char *address,
- const char *name) const
+ const char *name,
+ const audio_format_t encodedFormat) const
{
- sp<HwModule> hwModule = getModuleForDeviceTypes(type);
+ sp<HwModule> hwModule = getModuleForDeviceTypes(type, encodedFormat);
if (hwModule == 0) {
ALOGE("%s: could not find HW module for device %04x address %s", __FUNCTION__, type,
address);
@@ -354,8 +364,9 @@
sp<DeviceDescriptor> device = new DeviceDescriptor(type, String8(name));
device->setName(String8(name));
device->setAddress(String8(address));
+ device->setEncodedFormat(encodedFormat);
- // Add the device to the list of dynamic devices
+ // Add the device to the list of dynamic devices
hwModule->addDynamicDevice(device);
// Reciprocally attach the device to the module
device->attach(hwModule);
@@ -370,7 +381,8 @@
if (profile->supportsDevice(device, false /*matchAdress*/)) {
// @todo quid of audio profile? import the profile from device of the same type?
- const auto &isoTypeDeviceForProfile = profile->getSupportedDevices().getDevice(type);
+ const auto &isoTypeDeviceForProfile =
+ profile->getSupportedDevices().getDevice(type, String8(), AUDIO_FORMAT_DEFAULT);
device->importAudioPort(isoTypeDeviceForProfile, true /* force */);
ALOGV("%s: adding device %s to profile %s", __FUNCTION__,
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index 1154654..98d375c 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -140,6 +140,8 @@
static constexpr const char *roleSource = "source"; /**< <attribute role source value>. */
/** optional: device address, char string less than 64. */
static constexpr const char *address = "address";
+ /** optional: the list of encoded audio formats that are known to be supported. */
+ static constexpr const char *encodedFormats = "encodedFormats";
};
static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
@@ -511,7 +513,13 @@
ALOGW("%s: bad type %08x", __func__, type);
return Status::fromStatusT(BAD_VALUE);
}
- Element deviceDesc = new DeviceDescriptor(type, String8(name.c_str()));
+ std::string encodedFormatsLiteral = getXmlAttribute(cur, Attributes::encodedFormats);
+ ALOGV("%s: %s %s=%s", __func__, tag, Attributes::encodedFormats, encodedFormatsLiteral.c_str());
+ FormatVector encodedFormats;
+ if (!encodedFormatsLiteral.empty()) {
+ encodedFormats = formatsFromString(encodedFormatsLiteral, " ");
+ }
+ Element deviceDesc = new DeviceDescriptor(type, encodedFormats, String8(name.c_str()));
std::string address = getXmlAttribute(cur, Attributes::address);
if (!address.empty()) {