audiopolicy: fix rsubmix / device with dynamic address regressions
Orphan devices (aka devices not declared in configuration file) used to be
managed by apm::mAvailable<Output|Input>Devices and affinity with profile
was done by type only.
As the device affinity with profile is now enforced by checking with descriptor
rather than with type, profile's supported devices list shall be dynamically
updated.
Test: manual audio smoke tests
Change-Id: I5e8092968bbdb03ac7dc1aa1a3f15a0bc1b09251
Signed-off-by: François Gaffie <francois.gaffie@renault.com>
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index 842b7e7..d4cfd1e 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -68,6 +68,7 @@
bool isSourceActive(audio_source_t source) const;
audio_source_t source() const;
bool isSoundTrigger() const;
+ audio_attributes_t getHighestPriorityAttributes() const;
void setClientActive(const sp<RecordClientDescriptor>& client, bool active);
int32_t activeCount() { return mGlobalActiveCount; }
void trackEffectEnabled(const sp<EffectDescriptor> &effect, bool enabled);
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
index bb9cad8..1b5a2d6 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
@@ -65,6 +65,7 @@
uint32_t getFlags() const { return mFlags; }
virtual void attach(const sp<HwModule>& module);
+ virtual void detach();
bool isAttached() { return mModule != 0; }
// Audio port IDs are in a different namespace than AudioFlinger unique IDs
@@ -161,7 +162,7 @@
const struct audio_port_config *srcConfig = NULL) const = 0;
virtual sp<AudioPort> getAudioPort() const = 0;
virtual bool hasSameHwModuleAs(const sp<AudioPortConfig>& other) const {
- return (other != 0) &&
+ return (other != 0) && (other->getAudioPort() != 0) && (getAudioPort() != 0) &&
(other->getAudioPort()->getModuleHandle() == getAudioPort()->getModuleHandle());
}
unsigned int mSamplingRate = 0u;
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index 9181c9a..b581665 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -53,6 +53,8 @@
// AudioPort
virtual void attach(const sp<HwModule>& module);
+ virtual void detach();
+
virtual void toAudioPort(struct audio_port *port) const;
virtual void importAudioPort(const sp<AudioPort>& port, bool force = false);
@@ -125,8 +127,6 @@
*/
DeviceVector filter(const DeviceVector &devices) const;
- DeviceVector filter(audio_devices_t deviceTypes) const;
-
/**
* @brief merge two vectors. As SortedVector Implementation is buggy (it does not check the size
* of the destination vector, only of the source, it provides a safe implementation
diff --git a/services/audiopolicy/common/managerdefinitions/include/HwModule.h b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
index 69126ba..d7dc4b0 100644
--- a/services/audiopolicy/common/managerdefinitions/include/HwModule.h
+++ b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
@@ -46,6 +46,22 @@
const DeviceVector &getDeclaredDevices() const { return mDeclaredDevices; }
void setDeclaredDevices(const DeviceVector &devices);
+ DeviceVector getAllDevices() const
+ {
+ DeviceVector devices = mDeclaredDevices;
+ devices.merge(mDynamicDevices);
+ return devices;
+ }
+ void addDynamicDevice(const sp<DeviceDescriptor> &device)
+ {
+ mDynamicDevices.add(device);
+ }
+
+ bool removeDynamicDevice(const sp<DeviceDescriptor> &device)
+ {
+ return mDynamicDevices.remove(device) >= 0;
+ }
+ DeviceVector getDynamicDevices() const { return mDynamicDevices; }
const InputProfileCollection &getInputProfiles() const { return mInputProfiles; }
const OutputProfileCollection &getOutputProfiles() const { return mOutputProfiles; }
@@ -104,6 +120,7 @@
InputProfileCollection mInputProfiles; // input profiles exposed by this module
uint32_t mHalVersion; // audio HAL API version
DeviceVector mDeclaredDevices; // devices declared in audio_policy configuration file.
+ DeviceVector mDynamicDevices; /**< devices that can be added/removed at runtime (e.g. rsbumix)*/
AudioRouteVector mRoutes;
AudioPortVector mPorts;
};
@@ -120,11 +137,51 @@
DeviceVector getAvailableDevicesFromModuleName(const char *name,
const DeviceVector &availableDevices) const;
- sp<DeviceDescriptor> getDeviceDescriptor(const audio_devices_t device,
- const char *device_address,
- const char *device_name,
+ /**
+ * @brief getDeviceDescriptor returns a device descriptor associated to the device type and
+ * device address (if matchAddress is true).
+ * It may loop twice on all modules to check if allowToCreate is true
+ * -first loop will check if the device is found on a module since declared in the list
+ * of device port in configuration file
+ * -(allowToCreate is true)second loop will check if the device is weakly supported by one
+ * or more profiles on a given module and will add as a supported device for this module.
+ * The device will also be added to the dynamic list of device of this module
+ * @param type of the device requested
+ * @param address of the device requested
+ * @param name of the device that requested
+ * @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)
+ */
+ sp<DeviceDescriptor> getDeviceDescriptor(const audio_devices_t type,
+ const char *address,
+ const char *name,
+ bool allowToCreate = false,
bool matchAddress = true) const;
+ /**
+ * @brief createDevice creates a new device from the type and address given. It checks that
+ * according to the device type, a module is supporting this device (weak check).
+ * This concerns only dynamic device, aka device with a specific address and not
+ * already supported by module/underlying profiles.
+ * @param type of the device to be created
+ * @param address of the device to be created
+ * @param name of the device to be created
+ * @return device descriptor if a module is supporting this type, nullptr otherwise.
+ */
+ sp<DeviceDescriptor> createDevice(const audio_devices_t type,
+ const char *address,
+ const char *name) const;
+
+ /**
+ * @brief cleanUpForDevice: loop on all profiles of all modules to remove device from
+ * the list of supported device. If this device is a dynamic device (aka a device not in the
+ * xml file with a runtime address), it is also removed from the module collection of dynamic
+ * devices.
+ * @param device that has been disconnected
+ */
+ void cleanUpForDevice(const sp<DeviceDescriptor> &device);
+
void dump(String8 *dst) const;
};
diff --git a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
index 7761625..d0c05a5 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
@@ -99,11 +99,6 @@
return mSupportedDevices.types() & (device & ~AUDIO_DEVICE_BIT_IN);
}
- bool supportDeviceAddress(const String8 &address) const
- {
- return mSupportedDevices[0]->address() == address;
- }
-
/**
* @brief supportsDevice
* @param device to be checked against
@@ -121,26 +116,15 @@
return mSupportedDevices.contains(device);
}
- // chose first device present in mSupportedDevices also part of deviceType
- audio_devices_t getSupportedDeviceForType(audio_devices_t deviceType) const
- {
- for (size_t k = 0; k < mSupportedDevices.size(); k++) {
- audio_devices_t profileType = mSupportedDevices[k]->type();
- if (profileType & deviceType) {
- return profileType;
- }
- }
- return AUDIO_DEVICE_NONE;
- }
-
- audio_devices_t getSupportedDevicesType() const { return mSupportedDevices.types(); }
-
void clearSupportedDevices() { mSupportedDevices.clear(); }
void addSupportedDevice(const sp<DeviceDescriptor> &device)
{
mSupportedDevices.add(device);
}
-
+ void removeSupportedDevice(const sp<DeviceDescriptor> &device)
+ {
+ mSupportedDevices.remove(device);
+ }
void setSupportedDevices(const DeviceVector &devices)
{
mSupportedDevices = devices;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index c483ffe..55d4db4 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -54,30 +54,7 @@
audio_source_t AudioInputDescriptor::source() const
{
- audio_source_t source = AUDIO_SOURCE_DEFAULT;
-
- for (bool activeOnly : { true, false }) {
- int32_t topPriority = -1;
- app_state_t topState = APP_STATE_IDLE;
- for (const auto &client : getClientIterable()) {
- if (activeOnly && !client->active()) {
- continue;
- }
- app_state_t curState = client->appState();
- if (curState >= topState) {
- int32_t curPriority = source_priority(client->source());
- if (curPriority > topPriority) {
- source = client->source();
- topPriority = curPriority;
- }
- topState = curState;
- }
- }
- if (source != AUDIO_SOURCE_DEFAULT) {
- break;
- }
- }
- return source;
+ return getHighestPriorityAttributes().source;
}
void AudioInputDescriptor::toAudioPortConfig(struct audio_port_config *dstConfig,
@@ -147,6 +124,34 @@
return false;
}
+audio_attributes_t AudioInputDescriptor::getHighestPriorityAttributes() const
+{
+ audio_attributes_t attributes = { .source = AUDIO_SOURCE_DEFAULT };
+
+ for (bool activeOnly : { true, false }) {
+ int32_t topPriority = -1;
+ app_state_t topState = APP_STATE_IDLE;
+ for (const auto &client : getClientIterable()) {
+ if (activeOnly && !client->active()) {
+ continue;
+ }
+ app_state_t curState = client->appState();
+ if (curState >= topState) {
+ int32_t curPriority = source_priority(client->source());
+ if (curPriority > topPriority) {
+ attributes = client->attributes();
+ topPriority = curPriority;
+ }
+ topState = curState;
+ }
+ }
+ if (attributes.source != AUDIO_SOURCE_DEFAULT) {
+ break;
+ }
+ }
+ return attributes;
+}
+
bool AudioInputDescriptor::isSoundTrigger() const {
// sound trigger and non sound trigger clients are not mixed on a given input
// so check only first client
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 578d493..643cbd1 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -350,10 +350,6 @@
bool SwAudioOutputDescriptor::supportsDevice(const sp<DeviceDescriptor> &device) const
{
- // Performs weak check until dynamic support of supportedDevice on Modules/Profiles
- if (!device_distinguishes_on_address(device->type())) {
- return supportedDevices().types() & (device->type());
- }
return supportedDevices().contains(device);
}
@@ -758,13 +754,6 @@
return false;
}
-audio_devices_t SwAudioOutputCollection::getSupportedDevices(audio_io_handle_t handle) const
-{
- sp<SwAudioOutputDescriptor> outputDesc = valueFor(handle);
- audio_devices_t devices = outputDesc->mProfile->getSupportedDevicesType();
- return devices;
-}
-
sp<SwAudioOutputDescriptor> SwAudioOutputCollection::getOutputForClient(audio_port_handle_t portId)
{
for (size_t i = 0; i < size(); i++) {
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
index 19dde6a..9fcf5e7 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
@@ -31,9 +31,15 @@
// --- AudioPort class implementation
void AudioPort::attach(const sp<HwModule>& module)
{
+ ALOGV("%s: attaching module %s to port %s", __FUNCTION__, getModuleName(), mName.string());
mModule = module;
}
+void AudioPort::detach()
+{
+ mModule = nullptr;
+}
+
// Note that is a different namespace than AudioFlinger unique IDs
audio_port_handle_t AudioPort::getNextUniqueId()
{
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index 7137786..01111c5 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -58,6 +58,12 @@
mId = getNextUniqueId();
}
+void DeviceDescriptor::detach()
+{
+ mId = AUDIO_PORT_HANDLE_NONE;
+ AudioPort::detach();
+}
+
bool DeviceDescriptor::equals(const sp<DeviceDescriptor>& other) const
{
// Devices are considered equal if they:
@@ -335,17 +341,6 @@
return filteredDevices;
}
-DeviceVector DeviceVector::filter(audio_devices_t deviceTypes) const
-{
- DeviceVector filteredDevices;
- for (const auto &device : *this) {
- if ((device->type() & deviceTypes) == device->type()) {
- filteredDevices.add(device);
- }
- }
- return filteredDevices;
-}
-
bool DeviceVector::containsAtLeastOne(const DeviceVector &devices) const
{
return !filter(devices).isEmpty();
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index 3547a05..7d2d094 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -52,6 +52,9 @@
sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
devDesc->setAddress(address);
+ addDynamicDevice(devDesc);
+ // Reciprocally attach the device to the module
+ devDesc->attach(this);
profile->addSupportedDevice(devDesc);
return addOutputProfile(profile);
@@ -97,6 +100,9 @@
{
for (size_t i = 0; i < mOutputProfiles.size(); i++) {
if (mOutputProfiles[i]->getName() == name) {
+ for (const auto &device : mOutputProfiles[i]->getSupportedDevices()) {
+ removeDynamicDevice(device);
+ }
mOutputProfiles.removeAt(i);
break;
}
@@ -114,6 +120,9 @@
sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
devDesc->setAddress(address);
+ addDynamicDevice(devDesc);
+ // Reciprocally attach the device to the module
+ devDesc->attach(this);
profile->addSupportedDevice(devDesc);
ALOGV("addInputProfile() name %s rate %d mask 0x%08x",
@@ -126,6 +135,9 @@
{
for (size_t i = 0; i < mInputProfiles.size(); i++) {
if (mInputProfiles[i]->getName() == name) {
+ for (const auto &device : mInputProfiles[i]->getSupportedDevices()) {
+ removeDynamicDevice(device);
+ }
mInputProfiles.removeAt(i);
break;
}
@@ -247,6 +259,7 @@
}
}
mDeclaredDevices.dump(dst, String8("Declared"), 2, true);
+ mDynamicDevices.dump(dst, String8("Dynamic"), 2, true);
mRoutes.dump(dst, 2);
}
@@ -298,30 +311,103 @@
return availableDevices.getDevicesFromHwModule(module->getHandle());
}
-sp<DeviceDescriptor> HwModuleCollection::getDeviceDescriptor(const audio_devices_t device,
- const char *device_address,
- const char *device_name,
+sp<DeviceDescriptor> HwModuleCollection::getDeviceDescriptor(const audio_devices_t deviceType,
+ const char *address,
+ const char *name,
+ bool allowToCreate,
bool matchAddress) const
{
- String8 address = (device_address == nullptr || !matchAddress) ?
- String8("") : String8(device_address);
+ String8 devAddress = (address == nullptr || !matchAddress) ? String8("") : String8(address);
// handle legacy remote submix case where the address was not always specified
- if (device_distinguishes_on_address(device) && (address.length() == 0)) {
- address = String8("0");
+ if (device_distinguishes_on_address(deviceType) && (devAddress.length() == 0)) {
+ devAddress = String8("0");
}
for (const auto& hwModule : *this) {
- DeviceVector declaredDevices = hwModule->getDeclaredDevices();
- sp<DeviceDescriptor> deviceDesc = declaredDevices.getDevice(device, address);
- if (deviceDesc) {
- return deviceDesc;
+ DeviceVector moduleDevices = hwModule->getAllDevices();
+ auto moduleDevice = moduleDevices.getDevice(deviceType, devAddress);
+ if (moduleDevice) {
+ if (allowToCreate) {
+ moduleDevice->attach(hwModule);
+ }
+ return moduleDevice;
}
}
+ if (!allowToCreate) {
+ ALOGE("%s: could not find HW module for device %s %04x address %s", __FUNCTION__,
+ name, deviceType, address);
+ return nullptr;
+ }
+ return createDevice(deviceType, address, name);
+}
- sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
- devDesc->setName(String8(device_name));
- devDesc->setAddress(address);
- return devDesc;
+sp<DeviceDescriptor> HwModuleCollection::createDevice(const audio_devices_t type,
+ const char *address,
+ const char *name) const
+{
+ sp<HwModule> hwModule = getModuleForDeviceTypes(type);
+ if (hwModule == 0) {
+ ALOGE("%s: could not find HW module for device %04x address %s", __FUNCTION__, type,
+ address);
+ return nullptr;
+ }
+ sp<DeviceDescriptor> device = new DeviceDescriptor(type, String8(name));
+ device->setName(String8(name));
+ device->setAddress(String8(address));
+
+ // Add the device to the list of dynamic devices
+ hwModule->addDynamicDevice(device);
+ // Reciprocally attach the device to the module
+ device->attach(hwModule);
+ ALOGD("%s: adding dynamic device %s to module %s", __FUNCTION__,
+ device->toString().c_str(), hwModule->getName());
+
+ const auto &profiles = (audio_is_output_device(type) ? hwModule->getOutputProfiles() :
+ hwModule->getInputProfiles());
+ for (const auto &profile : profiles) {
+ // Add the device as supported to all profile supporting "weakly" or not the device
+ // according to its type
+ 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);
+ device->importAudioPort(isoTypeDeviceForProfile, true /* force */);
+
+ ALOGV("%s: adding device %s to profile %s", __FUNCTION__,
+ device->toString().c_str(), profile->getTagName().c_str());
+ profile->addSupportedDevice(device);
+ }
+ }
+ return device;
+}
+
+void HwModuleCollection::cleanUpForDevice(const sp<DeviceDescriptor> &device)
+{
+ for (const auto& hwModule : *this) {
+ DeviceVector moduleDevices = hwModule->getAllDevices();
+ if (!moduleDevices.contains(device)) {
+ continue;
+ }
+ device->detach();
+ // Only remove from dynamic list, not from declared list!!!
+ if (!hwModule->getDynamicDevices().contains(device)) {
+ return;
+ }
+ hwModule->removeDynamicDevice(device);
+ ALOGV("%s: removed dynamic device %s from module %s", __FUNCTION__,
+ device->toString().c_str(), hwModule->getName());
+
+ const IOProfileCollection &profiles = audio_is_output_device(device->type()) ?
+ hwModule->getOutputProfiles() : hwModule->getInputProfiles();
+ for (const auto &profile : profiles) {
+ // For cleanup, strong match is required
+ if (profile->supportsDevice(device, true /*matchAdress*/)) {
+ ALOGV("%s: removing device %s from profile %s", __FUNCTION__,
+ device->toString().c_str(), profile->getTagName().c_str());
+ profile->removeSupportedDevice(device);
+ }
+ }
+ }
}
void HwModuleCollection::dump(String8 *dst) const
diff --git a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
index fc6c1e4..1934fa4 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
+++ b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
@@ -295,8 +295,8 @@
auto criterionType = criterion->getCriterionType();
int deviceAddressId;
- if (not criterionType->getNumericalValue(devDesc->mAddress.string(), deviceAddressId)) {
- ALOGE("%s: unknown device address reported (%s)", __FUNCTION__, devDesc->mAddress.c_str());
+ if (not criterionType->getNumericalValue(devDesc->address().string(), deviceAddressId)) {
+ ALOGW("%s: unknown device address reported (%s)", __FUNCTION__, devDesc->address().c_str());
return BAD_TYPE;
}
int currentValueMask = criterion->getCriterionState();
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 47e6016..d7cf88e 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -110,7 +110,11 @@
if (!audio_is_output_device(deviceType) && !audio_is_input_device(deviceType)) return BAD_VALUE;
sp<DeviceDescriptor> device =
- mHwModules.getDeviceDescriptor(deviceType, device_address, device_name);
+ mHwModules.getDeviceDescriptor(deviceType, device_address, device_name,
+ state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
+ if (device == 0) {
+ return INVALID_OPERATION;
+ }
// handle output devices
if (audio_is_output_device(deviceType)) {
@@ -132,17 +136,7 @@
ALOGV("%s() connecting device %s", __func__, device->toString().c_str());
// register new device as available
- index = mAvailableOutputDevices.add(device);
- if (index >= 0) {
- sp<HwModule> module = mHwModules.getModuleForDeviceTypes(deviceType);
- if (module == 0) {
- ALOGD("setDeviceConnectionState() could not find HW module for device %s",
- device->toString().c_str());
- mAvailableOutputDevices.remove(device);
- return INVALID_OPERATION;
- }
- mAvailableOutputDevices[index]->attach(module);
- } else {
+ if (mAvailableOutputDevices.add(device) < 0) {
return NO_MEMORY;
}
@@ -153,6 +147,8 @@
if (checkOutputsForDevice(device, state, outputs) != NO_ERROR) {
mAvailableOutputDevices.remove(device);
+ mHwModules.cleanUpForDevice(device);
+
broadcastDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE);
return INVALID_OPERATION;
}
@@ -252,26 +248,19 @@
ALOGW("%s() device already connected: %s", __func__, device->toString().c_str());
return INVALID_OPERATION;
}
- sp<HwModule> module = mHwModules.getModuleForDeviceTypes(deviceType);
- if (module == NULL) {
- ALOGW("setDeviceConnectionState(): could not find HW module for device %08x",
- deviceType);
- return INVALID_OPERATION;
- }
-
// Before checking intputs, broadcast connect event to allow HAL to retrieve dynamic
// parameters on newly connected devices (instead of opening the inputs...)
broadcastDeviceConnectionState(device, state);
if (checkInputsForDevice(device, state, inputs) != NO_ERROR) {
broadcastDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE);
+
+ mHwModules.cleanUpForDevice(device);
+
return INVALID_OPERATION;
}
- index = mAvailableInputDevices.add(device);
- if (index >= 0) {
- mAvailableInputDevices[index]->attach(module);
- } else {
+ if (mAvailableInputDevices.add(device) < 0) {
return NO_MEMORY;
}
@@ -329,7 +318,7 @@
const char *device_address)
{
sp<DeviceDescriptor> devDesc =
- mHwModules.getDeviceDescriptor(device, device_address, "",
+ mHwModules.getDeviceDescriptor(device, device_address, "", false /* allowToCreate */,
(strlen(device_address) != 0)/*matchAddress*/);
if (devDesc == 0) {
@@ -371,8 +360,7 @@
// Check if the device is currently connected
sp<DeviceDescriptor> devDesc =
mHwModules.getDeviceDescriptor(device, device_address, device_name);
- ssize_t index = mAvailableOutputDevices.indexOf(devDesc);
- if (index < 0) {
+ if (devDesc == 0 || mAvailableOutputDevices.indexOf(devDesc) < 0) {
// Nothing to do: device is not connected
return NO_ERROR;
}
@@ -430,7 +418,8 @@
}
ALOG_ASSERT(!rxDevices.isEmpty(), "updateCallRouting() no selected output device");
- auto txDevice = getDeviceAndMixForInputSource(AUDIO_SOURCE_VOICE_COMMUNICATION);
+ audio_attributes_t attr = { .source = AUDIO_SOURCE_VOICE_COMMUNICATION };
+ auto txDevice = getDeviceAndMixForAttributes(attr);
ALOGV("updateCallRouting device rxDevice %s txDevice %s",
rxDevices.toString().c_str(), txDevice->toString().c_str());
@@ -699,8 +688,7 @@
for (const auto& activeDesc : mInputs.getActiveInputs()) {
auto newDevice = getNewInputDevice(activeDesc);
// Force new input selection if the new device can not be reached via current input
- if (activeDesc->mProfile->getSupportedDevices().types() &
- (newDevice->type() & ~AUDIO_DEVICE_BIT_IN)) {
+ if (activeDesc->mProfile->getSupportedDevices().contains(newDevice)) {
setInputDevice(activeDesc->mIoHandle, newDevice);
} else {
closeInput(activeDesc->mIoHandle);
@@ -818,7 +806,7 @@
DeviceVector devices;
routing_strategy strategy;
audio_devices_t deviceType = AUDIO_DEVICE_NONE;
- const audio_port_handle_t requestedDeviceId = *selectedDeviceId;
+ const audio_port_handle_t requestedPortId = *selectedDeviceId;
DeviceVector msdDevices = getMsdAudioOutDevices();
status_t status = getAudioAttributes(resultAttr, attr, *stream);
@@ -830,17 +818,16 @@
" session %d selectedDeviceId %d",
__func__,
resultAttr->usage, resultAttr->content_type, resultAttr->tags, resultAttr->flags,
- session, requestedDeviceId);
+ session, requestedPortId);
*stream = streamTypefromAttributesInt(resultAttr);
strategy = getStrategyForAttr(resultAttr);
// First check for explicit routing (eg. setPreferredDevice)
- if (requestedDeviceId != AUDIO_PORT_HANDLE_NONE) {
- sp<DeviceDescriptor> deviceDesc =
- mAvailableOutputDevices.getDeviceFromId(requestedDeviceId);
- deviceType = deviceDesc->type();
+ sp<DeviceDescriptor> requestedDevice = mAvailableOutputDevices.getDeviceFromId(requestedPortId);
+ if (requestedDevice != nullptr) {
+ deviceType = requestedDevice->type();
} else {
// If no explict route, is there a matching dynamic policy that applies?
sp<SwAudioOutputDescriptor> desc;
@@ -880,7 +867,7 @@
(*stream == AUDIO_STREAM_MUSIC || resultAttr->usage == AUDIO_USAGE_VOICE_COMMUNICATION) &&
audio_is_linear_pcm(config->format) &&
isInCall()) {
- if (requestedDeviceId != AUDIO_PORT_HANDLE_NONE) {
+ if (requestedPortId != AUDIO_PORT_HANDLE_NONE) {
*flags = (audio_output_flags_t)AUDIO_OUTPUT_FLAG_INCALL_MUSIC;
} else {
// Get the devce type directly from the engine to bypass preferred route logic
@@ -934,7 +921,7 @@
if (*portId != AUDIO_PORT_HANDLE_NONE) {
return INVALID_OPERATION;
}
- const audio_port_handle_t requestedDeviceId = *selectedDeviceId;
+ const audio_port_handle_t requestedPortId = *selectedDeviceId;
audio_attributes_t resultAttr;
status_t status = getOutputForAttrInt(&resultAttr, output, session, attr, stream, uid,
config, flags, selectedDeviceId);
@@ -949,14 +936,14 @@
sp<TrackClientDescriptor> clientDesc =
new TrackClientDescriptor(*portId, uid, session, resultAttr, clientConfig,
- requestedDeviceId, *stream,
+ requestedPortId, *stream,
getStrategyForAttr(&resultAttr),
*flags);
sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(*output);
outputDesc->addClient(clientDesc);
ALOGV("%s returns output %d selectedDeviceId %d for port ID %d",
- __func__, *output, requestedDeviceId, *portId);
+ __func__, *output, requestedPortId, *portId);
return NO_ERROR;
}
@@ -1746,7 +1733,7 @@
status_t status = NO_ERROR;
audio_source_t halInputSource;
- audio_source_t inputSource = attr->source;
+ audio_attributes_t attributes = *attr;
AudioMix *policyMix = NULL;
sp<DeviceDescriptor> device;
sp<AudioInputDescriptor> inputDesc;
@@ -1759,8 +1746,8 @@
return INVALID_OPERATION;
}
- if (inputSource == AUDIO_SOURCE_DEFAULT) {
- inputSource = AUDIO_SOURCE_MIC;
+ if (attr->source == AUDIO_SOURCE_DEFAULT) {
+ attributes.source = AUDIO_SOURCE_MIC;
}
// Explicit routing?
@@ -1815,11 +1802,11 @@
*input = AUDIO_IO_HANDLE_NONE;
*inputType = API_INPUT_INVALID;
- halInputSource = inputSource;
+ halInputSource = attributes.source;
- if (inputSource == AUDIO_SOURCE_REMOTE_SUBMIX &&
- strncmp(attr->tags, "addr=", strlen("addr=")) == 0) {
- status = mPolicyMixes.getInputMixForAttr(*attr, &policyMix);
+ if (attributes.source == AUDIO_SOURCE_REMOTE_SUBMIX &&
+ strncmp(attributes.tags, "addr=", strlen("addr=")) == 0) {
+ status = mPolicyMixes.getInputMixForAttr(attributes, &policyMix);
if (status != NO_ERROR) {
goto error;
}
@@ -1830,10 +1817,10 @@
if (explicitRoutingDevice != nullptr) {
device = explicitRoutingDevice;
} else {
- device = getDeviceAndMixForInputSource(inputSource, &policyMix);
+ device = getDeviceAndMixForAttributes(attributes, &policyMix);
}
if (device == nullptr) {
- ALOGW("getInputForAttr() could not find device for source %d", inputSource);
+ ALOGW("getInputForAttr() could not find device for source %d", attributes.source);
status = BAD_VALUE;
goto error;
}
@@ -1854,7 +1841,7 @@
}
- *input = getInputForDevice(device, session, inputSource,
+ *input = getInputForDevice(device, session, attributes.source,
config, flags,
policyMix);
if (*input == AUDIO_IO_HANDLE_NONE) {
@@ -1867,12 +1854,13 @@
*selectedDeviceId = mAvailableInputDevices.contains(device) ?
device->getId() : AUDIO_PORT_HANDLE_NONE;
- isSoundTrigger = inputSource == AUDIO_SOURCE_HOTWORD &&
+ isSoundTrigger = attributes.source == AUDIO_SOURCE_HOTWORD &&
mSoundTriggerSessions.indexOfKey(session) > 0;
*portId = AudioPort::getNextUniqueId();
clientDesc = new RecordClientDescriptor(*portId, uid, session, *attr, *config,
- requestedDeviceId, inputSource,flags, isSoundTrigger);
+ requestedDeviceId, attributes.source, flags,
+ isSoundTrigger);
inputDesc = mInputs.valueFor(*input);
inputDesc->addClient(clientDesc);
@@ -3425,7 +3413,8 @@
{
*session = (audio_session_t)mpClientInterface->newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
*ioHandle = (audio_io_handle_t)mpClientInterface->newAudioUniqueId(AUDIO_UNIQUE_ID_USE_INPUT);
- *device = getDeviceAndMixForInputSource(AUDIO_SOURCE_HOTWORD)->type();
+ audio_attributes_t attr = { .source = AUDIO_SOURCE_HOTWORD };
+ *device = getDeviceAndMixForAttributes(attr)->type();
return mSoundTriggerSessions.acquireSession(*session, *ioHandle);
}
@@ -4349,10 +4338,9 @@
desc = mOutputs.valueAt(i);
if (!desc->isDuplicated()) {
// exact match on device
- if (device_distinguishes_on_address(deviceType) &&
- (desc->supportedDevices().types() == deviceType)) {
+ if (device_distinguishes_on_address(deviceType) && desc->supportsDevice(device)) {
outputs.add(mOutputs.keyAt(i));
- } else if (!(desc->supportedDevices().types() & mAvailableOutputDevices.types())) {
+ } else if (!mAvailableOutputDevices.containsAtLeastOne(desc->supportedDevices())) {
ALOGV("checkOutputsForDevice(): disconnecting adding output %d",
mOutputs.keyAt(i));
outputs.add(mOutputs.keyAt(i));
@@ -4494,7 +4482,7 @@
// 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->supportsDeviceTypes(mAvailableInputDevices.types()))) {
+ if (!mAvailableInputDevices.containsAtLeastOne(desc->supportedDevices())) {
ALOGV("checkInputsForDevice(): disconnecting adding input %d",
mInputs.keyAt(input_index));
inputs.add(mInputs.keyAt(input_index));
@@ -4506,7 +4494,7 @@
profile_index < hwModule->getInputProfiles().size();
profile_index++) {
sp<IOProfile> profile = hwModule->getInputProfiles()[profile_index];
- if (profile->supportsDeviceTypes(device->type())) {
+ if (profile->supportsDevice(device)) {
ALOGV("checkInputsForDevice(): clearing direct input profile %zu on module %s",
profile_index, hwModule->getName());
profile->clearAudioProfiles();
@@ -4637,8 +4625,7 @@
ALOGVV("output %zu isDuplicated=%d device=%s",
i, openOutputs.valueAt(i)->isDuplicated(),
openOutputs.valueAt(i)->supportedDevices().toString().c_str());
- if ((devices.types() & openOutputs.valueAt(i)->supportedDevices().types()) ==
- devices.types()) {
+ if (openOutputs.valueAt(i)->supportsAllDevices(devices)) {
ALOGVV("%s() found output %d", __func__, openOutputs.keyAt(i));
outputs.add(openOutputs.keyAt(i));
}
@@ -4684,7 +4671,7 @@
}
}
- if (srcOutputs != dstOutputs) {
+ if (!dstOutputs.isEmpty() && srcOutputs != dstOutputs) {
// get maximum latency of all source outputs to determine the minimum mute time guaranteeing
// audio from invalidated tracks will be rendered when unmuting
uint32_t maxLatency = 0;
@@ -4922,12 +4909,12 @@
// If we are not in call and no client is active on this input, this methods returns
// AUDIO_DEVICE_NONE, causing the patch on the input stream to be released.
- audio_source_t source = inputDesc->source();
- if (source == AUDIO_SOURCE_DEFAULT && isInCall()) {
- source = AUDIO_SOURCE_VOICE_COMMUNICATION;
+ audio_attributes_t attributes = inputDesc->getHighestPriorityAttributes();
+ if (attributes.source == AUDIO_SOURCE_DEFAULT && isInCall()) {
+ attributes.source = AUDIO_SOURCE_VOICE_COMMUNICATION;
}
- if (source != AUDIO_SOURCE_DEFAULT) {
- device = getDeviceAndMixForInputSource(source);
+ if (attributes.source != AUDIO_SOURCE_DEFAULT) {
+ device = getDeviceAndMixForAttributes(attributes);
}
return device;
@@ -5199,7 +5186,7 @@
}
// filter devices according to output selected
- DeviceVector filteredDevices = devices.filter(outputDesc->supportedDevices().types());
+ DeviceVector filteredDevices = outputDesc->filterSupportedDevices(devices);
// no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current
// output profile
@@ -5390,27 +5377,32 @@
return NULL;
}
-sp<DeviceDescriptor> AudioPolicyManager::getDeviceAndMixForInputSource(audio_source_t inputSource,
- AudioMix **policyMix)
+sp<DeviceDescriptor> AudioPolicyManager::getDeviceAndMixForAttributes(
+ const audio_attributes_t &attributes, AudioMix **policyMix)
{
// Honor explicit routing requests only if all active clients have a preferred route in which
// case the last active client route is used
sp<DeviceDescriptor> device =
- findPreferredDevice(mInputs, inputSource, mAvailableInputDevices);
+ findPreferredDevice(mInputs, attributes.source, mAvailableInputDevices);
if (device != nullptr) {
return device;
}
sp<DeviceDescriptor> selectedDeviceFromMix =
- mPolicyMixes.getDeviceAndMixForInputSource(inputSource, mAvailableInputDevices,
+ mPolicyMixes.getDeviceAndMixForInputSource(attributes.source, mAvailableInputDevices,
policyMix);
return (selectedDeviceFromMix != nullptr) ?
- selectedDeviceFromMix : getDeviceForInputSource(inputSource);
+ selectedDeviceFromMix : getDeviceForAttributes(attributes);
}
-sp<DeviceDescriptor> AudioPolicyManager::getDeviceForInputSource(audio_source_t inputSource)
+sp<DeviceDescriptor> AudioPolicyManager::getDeviceForAttributes(const audio_attributes_t &attributes)
{
- audio_devices_t device = mEngine->getDeviceForInputSource(inputSource);
+ audio_devices_t device = mEngine->getDeviceForInputSource(attributes.source);
+ if (attributes.source == AUDIO_SOURCE_REMOTE_SUBMIX &&
+ strncmp(attributes.tags, "addr=", strlen("addr=")) == 0) {
+ return mAvailableInputDevices.getDevice(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
+ String8(attributes.tags + strlen("addr=")));
+ }
return mAvailableInputDevices.getDevice(device);
}
@@ -5785,6 +5777,8 @@
releaseAudioPatch(patchDesc->mHandle, patchDesc->mUid);
}
}
+
+ mHwModules.cleanUpForDevice(deviceDesc);
}
void AudioPolicyManager::modifySurroundFormats(
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index b214f1f..e99de16 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -346,7 +346,7 @@
audio_patch_handle_t *patchHandle = NULL);
// select input device corresponding to requested audio source
- sp<DeviceDescriptor> getDeviceForInputSource(audio_source_t inputSource);
+ sp<DeviceDescriptor> getDeviceForAttributes(const audio_attributes_t &attributes);
// compute the actual volume for a given stream according to the requested index and a particular
// device
@@ -517,7 +517,7 @@
if (!hasPrimaryOutput()) {
return DeviceVector();
}
- return mAvailableOutputDevices.filter(mPrimaryOutput->supportedDevices().types());
+ return mAvailableOutputDevices.filter(mPrimaryOutput->supportedDevices());
}
DeviceVector availablePrimaryModuleInputDevices() const
{
@@ -724,8 +724,8 @@
// select input device corresponding to requested audio source and return associated policy
// mix if any. Calls getDeviceForInputSource().
- sp<DeviceDescriptor> getDeviceAndMixForInputSource(audio_source_t inputSource,
- AudioMix **policyMix = NULL);
+ sp<DeviceDescriptor> getDeviceAndMixForAttributes(const audio_attributes_t &attributes,
+ AudioMix **policyMix = NULL);
// Called by setDeviceConnectionState().
status_t setDeviceConnectionStateInt(audio_devices_t deviceType,