Allow to set/get/remove disabled devices for strategy/capture preset.
Cache the disabled devices as a list for strategy/capture preset. The
preferred devices list and disabled devices list are mutually exclusive.
Once a device is in a list, it must be removed from the other list.
Bug: 184065221
Test: atest AudioServiceHostTest, audiopolicy_tests
Change-Id: I3477c089f8a1c89f82c692637295c1cf25a91593
diff --git a/services/audiopolicy/engine/common/include/EngineBase.h b/services/audiopolicy/engine/common/include/EngineBase.h
index 9bef97c..0f8b0a5 100644
--- a/services/audiopolicy/engine/common/include/EngineBase.h
+++ b/services/audiopolicy/engine/common/include/EngineBase.h
@@ -170,11 +170,13 @@
status_t getMediaDevicesForRole(device_role_t role, const DeviceVector& availableDevices,
DeviceVector& devices) const;
+ void dumpCapturePresetDevicesRoleMap(String8 *dst, int spaces) const;
+
AudioPolicyManagerObserver *mApmObserver = nullptr;
ProductStrategyMap mProductStrategies;
- ProductStrategyPreferredRoutingMap mProductStrategyPreferredDevices;
- CapturePresetDevicesRoleMap mCapturePresetDevicesRole;
+ ProductStrategyDevicesRoleMap mProductStrategyDeviceRoleMap;
+ CapturePresetDevicesRoleMap mCapturePresetDevicesRoleMap;
VolumeGroupMap mVolumeGroups;
LastRemovableMediaDevices mLastRemovableMediaDevices;
audio_mode_t mPhoneState = AUDIO_MODE_NORMAL; /**< current phone state. */
diff --git a/services/audiopolicy/engine/common/include/ProductStrategy.h b/services/audiopolicy/engine/common/include/ProductStrategy.h
index 54625ea..2aa2f9a 100644
--- a/services/audiopolicy/engine/common/include/ProductStrategy.h
+++ b/services/audiopolicy/engine/common/include/ProductStrategy.h
@@ -18,20 +18,20 @@
#include "VolumeGroup.h"
-#include <system/audio.h>
-#include <utils/RefBase.h>
-#include <HandleGenerator.h>
-#include <string>
-#include <vector>
#include <map>
-#include <utils/Errors.h>
-#include <utils/String8.h>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <HandleGenerator.h>
#include <media/AudioAttributes.h>
#include <media/AudioContainers.h>
#include <media/AudioDeviceTypeAddr.h>
#include <media/AudioPolicy.h>
-
-#include <vector>
+#include <system/audio.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
namespace android {
@@ -170,11 +170,12 @@
product_strategy_t mDefaultStrategy = PRODUCT_STRATEGY_NONE;
};
-class ProductStrategyPreferredRoutingMap : public std::map<product_strategy_t,
- AudioDeviceTypeAddrVector>
-{
-public:
- void dump(String8 *dst, int spaces = 0) const;
-};
+using ProductStrategyDevicesRoleMap =
+ std::map<std::pair<product_strategy_t, device_role_t>, AudioDeviceTypeAddrVector>;
+
+void dumpProductStrategyDevicesRoleMap(
+ const ProductStrategyDevicesRoleMap& productStrategyDeviceRoleMap,
+ String8 *dst,
+ int spaces);
} // namespace android
diff --git a/services/audiopolicy/engine/common/src/EngineBase.cpp b/services/audiopolicy/engine/common/src/EngineBase.cpp
index aa43691..150a9a8 100644
--- a/services/audiopolicy/engine/common/src/EngineBase.cpp
+++ b/services/audiopolicy/engine/common/src/EngineBase.cpp
@@ -17,6 +17,8 @@
#define LOG_TAG "APM::AudioPolicyEngine/Base"
//#define LOG_NDEBUG 0
+#include <functional>
+#include <string>
#include <sys/stat.h>
#include "EngineBase.h"
@@ -349,23 +351,33 @@
return NO_ERROR;
}
-status_t EngineBase::setDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role,
- const AudioDeviceTypeAddrVector &devices)
-{
- // verify strategy exists
- if (mProductStrategies.find(strategy) == mProductStrategies.end()) {
- ALOGE("%s invalid strategy %u", __func__, strategy);
+namespace {
+template <typename T>
+status_t setDevicesRoleForT(
+ std::map<std::pair<T, device_role_t>, AudioDeviceTypeAddrVector>& tDevicesRoleMap,
+ T t, device_role_t role, const AudioDeviceTypeAddrVector &devices,
+ const std::string& logStr, std::function<bool(T)> p) {
+ if (!p(t)) {
+ ALOGE("%s invalid %s %u", __func__, logStr.c_str(), t);
return BAD_VALUE;
}
switch (role) {
case DEVICE_ROLE_PREFERRED:
- mProductStrategyPreferredDevices[strategy] = devices;
- break;
- case DEVICE_ROLE_DISABLED:
- // TODO (b/184065221): support set devices role as disabled for strategy.
- ALOGI("%s no implemented for role as %d", __func__, role);
- break;
+ case DEVICE_ROLE_DISABLED: {
+ tDevicesRoleMap[std::make_pair(t, role)] = devices;
+ // The preferred devices and disabled devices are mutually exclusive. Once a device is added
+ // the a list, it must be removed from the other one.
+ const device_role_t roleToRemove = role == DEVICE_ROLE_PREFERRED ? DEVICE_ROLE_DISABLED
+ : DEVICE_ROLE_PREFERRED;
+ auto it = tDevicesRoleMap.find(std::make_pair(t, roleToRemove));
+ if (it != tDevicesRoleMap.end()) {
+ it->second = excludeDeviceTypeAddrsFrom(it->second, devices);
+ if (it->second.empty()) {
+ tDevicesRoleMap.erase(it);
+ }
+ }
+ } break;
case DEVICE_ROLE_NONE:
// Intentionally fall-through as it is no need to set device role as none for a strategy.
default:
@@ -375,28 +387,26 @@
return NO_ERROR;
}
-status_t EngineBase::removeDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role)
-{
- // verify strategy exists
- if (mProductStrategies.find(strategy) == mProductStrategies.end()) {
- ALOGE("%s invalid strategy %u", __func__, strategy);
+template <typename T>
+status_t removeAllDevicesRoleForT(
+ std::map<std::pair<T, device_role_t>, AudioDeviceTypeAddrVector>& tDevicesRoleMap,
+ T t, device_role_t role, const std::string& logStr, std::function<bool(T)> p) {
+ if (!p(t)) {
+ ALOGE("%s invalid %s %u", __func__, logStr.c_str(), t);
return BAD_VALUE;
}
switch (role) {
case DEVICE_ROLE_PREFERRED:
- if (mProductStrategyPreferredDevices.erase(strategy) == 0) {
- // no preferred device was set
+ case DEVICE_ROLE_DISABLED:
+ if (tDevicesRoleMap.erase(std::make_pair(t, role)) == 0) {
+ // no preferred/disabled device was set
return NAME_NOT_FOUND;
}
break;
- case DEVICE_ROLE_DISABLED:
- // TODO (b/184065221): support remove devices role as disabled for strategy.
- ALOGI("%s no implemented for role as %d", __func__, role);
- break;
case DEVICE_ROLE_NONE:
// Intentionally fall-through as it makes no sense to remove devices with
- // role as DEVICE_ROLE_NONE for a strategy
+ // role as DEVICE_ROLE_NONE
default:
ALOGE("%s invalid role %d", __func__, role);
return BAD_VALUE;
@@ -404,30 +414,27 @@
return NO_ERROR;
}
-status_t EngineBase::getDevicesForRoleAndStrategy(product_strategy_t strategy, device_role_t role,
- AudioDeviceTypeAddrVector &devices) const
-{
- // verify strategy exists
- if (mProductStrategies.find(strategy) == mProductStrategies.end()) {
- ALOGE("%s unknown strategy %u", __func__, strategy);
+template <typename T>
+status_t getDevicesRoleForT(
+ const std::map<std::pair<T, device_role_t>, AudioDeviceTypeAddrVector>& tDevicesRoleMap,
+ T t, device_role_t role, AudioDeviceTypeAddrVector &devices, const std::string& logStr,
+ std::function<bool(T)> p) {
+ if (!p(t)) {
+ ALOGE("%s invalid %s %u", __func__, logStr.c_str(), t);
return BAD_VALUE;
}
switch (role) {
- case DEVICE_ROLE_PREFERRED: {
- // preferred device for this strategy?
- auto devIt = mProductStrategyPreferredDevices.find(strategy);
- if (devIt == mProductStrategyPreferredDevices.end()) {
- ALOGV("%s no preferred device for strategy %u", __func__, strategy);
+ case DEVICE_ROLE_PREFERRED:
+ case DEVICE_ROLE_DISABLED: {
+ auto it = tDevicesRoleMap.find(std::make_pair(t, role));
+ if (it == tDevicesRoleMap.end()) {
+ ALOGV("%s no device as role %u for %s %u", __func__, role, logStr.c_str(), t);
return NAME_NOT_FOUND;
}
- devices = devIt->second;
+ devices = it->second;
} break;
- case DEVICE_ROLE_DISABLED:
- // TODO (b/184065221): support devices role as disabled for strategy.
- ALOGV("%s no implemented for role as %d", __func__, role);
- break;
case DEVICE_ROLE_NONE:
// Intentionally fall-through as the DEVICE_ROLE_NONE is never set
default:
@@ -437,32 +444,45 @@
return NO_ERROR;
}
+} // namespace
+
+status_t EngineBase::setDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role,
+ const AudioDeviceTypeAddrVector &devices)
+{
+ std::function<bool(product_strategy_t)> p = [this](product_strategy_t strategy) {
+ return mProductStrategies.find(strategy) != mProductStrategies.end();
+ };
+ return setDevicesRoleForT(
+ mProductStrategyDeviceRoleMap, strategy, role, devices, "strategy" /*logStr*/, p);
+}
+
+status_t EngineBase::removeDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role)
+{
+ std::function<bool(product_strategy_t)> p = [this](product_strategy_t strategy) {
+ return mProductStrategies.find(strategy) != mProductStrategies.end();
+ };
+ return removeAllDevicesRoleForT(
+ mProductStrategyDeviceRoleMap, strategy, role, "strategy" /*logStr*/, p);
+}
+
+status_t EngineBase::getDevicesForRoleAndStrategy(product_strategy_t strategy, device_role_t role,
+ AudioDeviceTypeAddrVector &devices) const
+{
+ std::function<bool(product_strategy_t)> p = [this](product_strategy_t strategy) {
+ return mProductStrategies.find(strategy) != mProductStrategies.end();
+ };
+ return getDevicesRoleForT(
+ mProductStrategyDeviceRoleMap, strategy, role, devices, "strategy" /*logStr*/, p);
+}
+
status_t EngineBase::setDevicesRoleForCapturePreset(audio_source_t audioSource, device_role_t role,
const AudioDeviceTypeAddrVector &devices)
{
- // verify if the audio source is valid
- if (!audio_is_valid_audio_source(audioSource)) {
- ALOGE("%s unknown audio source %u", __func__, audioSource);
- }
-
- switch (role) {
- case DEVICE_ROLE_PREFERRED:
- mCapturePresetDevicesRole[audioSource][role] = devices;
- // When the devices are set as preferred devices, remove them from the disabled devices.
- doRemoveDevicesRoleForCapturePreset(
- audioSource, DEVICE_ROLE_DISABLED, devices, false /*forceMatched*/);
- break;
- case DEVICE_ROLE_DISABLED:
- // TODO: support setting devices role as disabled for capture preset.
- ALOGI("%s no implemented for role as %d", __func__, role);
- break;
- case DEVICE_ROLE_NONE:
- // Intentionally fall-through as it is no need to set device role as none
- default:
- ALOGE("%s invalid role %d", __func__, role);
- return BAD_VALUE;
- }
- return NO_ERROR;
+ std::function<bool(audio_source_t)> p = [](audio_source_t audioSource) {
+ return audio_is_valid_audio_source(audioSource);
+ };
+ return setDevicesRoleForT(
+ mCapturePresetDevicesRoleMap, audioSource, role, devices, "audio source" /*logStr*/, p);
}
status_t EngineBase::addDevicesRoleForCapturePreset(audio_source_t audioSource, device_role_t role,
@@ -475,19 +495,20 @@
switch (role) {
case DEVICE_ROLE_PREFERRED:
- mCapturePresetDevicesRole[audioSource][role] = excludeDeviceTypeAddrsFrom(
- mCapturePresetDevicesRole[audioSource][role], devices);
- for (const auto& device : devices) {
- mCapturePresetDevicesRole[audioSource][role].push_back(device);
+ case DEVICE_ROLE_DISABLED: {
+ const auto audioSourceRole = std::make_pair(audioSource, role);
+ mCapturePresetDevicesRoleMap[audioSourceRole] = excludeDeviceTypeAddrsFrom(
+ mCapturePresetDevicesRoleMap[audioSourceRole], devices);
+ for (const auto &device : devices) {
+ mCapturePresetDevicesRoleMap[audioSourceRole].push_back(device);
}
// When the devices are set as preferred devices, remove them from the disabled devices.
doRemoveDevicesRoleForCapturePreset(
- audioSource, DEVICE_ROLE_DISABLED, devices, false /*forceMatched*/);
- break;
- case DEVICE_ROLE_DISABLED:
- // TODO: support setting devices role as disabled for capture preset.
- ALOGI("%s no implemented for role as %d", __func__, role);
- break;
+ audioSource,
+ role == DEVICE_ROLE_PREFERRED ? DEVICE_ROLE_DISABLED : DEVICE_ROLE_PREFERRED,
+ devices,
+ false /*forceMatched*/);
+ } break;
case DEVICE_ROLE_NONE:
// Intentionally fall-through as it is no need to set device role as none
default:
@@ -513,21 +534,22 @@
switch (role) {
case DEVICE_ROLE_PREFERRED:
case DEVICE_ROLE_DISABLED: {
- if (mCapturePresetDevicesRole.count(audioSource) == 0 ||
- mCapturePresetDevicesRole[audioSource].count(role) == 0) {
+ const auto audioSourceRole = std::make_pair(audioSource, role);
+ if (mCapturePresetDevicesRoleMap.find(audioSourceRole) ==
+ mCapturePresetDevicesRoleMap.end()) {
return NAME_NOT_FOUND;
}
AudioDeviceTypeAddrVector remainingDevices = excludeDeviceTypeAddrsFrom(
- mCapturePresetDevicesRole[audioSource][role], devices);
+ mCapturePresetDevicesRoleMap[audioSourceRole], devices);
if (forceMatched && remainingDevices.size() !=
- mCapturePresetDevicesRole[audioSource][role].size() - devices.size()) {
+ mCapturePresetDevicesRoleMap[audioSourceRole].size() - devices.size()) {
// There are some devices from `devicesToRemove` that are not shown in the cached record
return BAD_VALUE;
}
- mCapturePresetDevicesRole[audioSource][role] = remainingDevices;
- if (mCapturePresetDevicesRole[audioSource][role].empty()) {
+ mCapturePresetDevicesRoleMap[audioSourceRole] = remainingDevices;
+ if (mCapturePresetDevicesRoleMap[audioSourceRole].empty()) {
// Remove the role when device list is empty
- mCapturePresetDevicesRole[audioSource].erase(role);
+ mCapturePresetDevicesRoleMap.erase(audioSourceRole);
}
} break;
case DEVICE_ROLE_NONE:
@@ -543,63 +565,21 @@
status_t EngineBase::clearDevicesRoleForCapturePreset(audio_source_t audioSource,
device_role_t role)
{
- // verify if the audio source is valid
- if (!audio_is_valid_audio_source(audioSource)) {
- ALOGE("%s unknown audio source %u", __func__, audioSource);
- }
-
- switch (role) {
- case DEVICE_ROLE_PREFERRED:
- if (mCapturePresetDevicesRole.count(audioSource) == 0 ||
- mCapturePresetDevicesRole[audioSource].erase(role) == 0) {
- // no preferred device for the given audio source
- return NAME_NOT_FOUND;
- }
- break;
- case DEVICE_ROLE_DISABLED:
- // TODO: support remove devices role as disabled for strategy.
- ALOGI("%s no implemented for role as %d", __func__, role);
- break;
- case DEVICE_ROLE_NONE:
- // Intentionally fall-through as it makes no sense to remove devices with
- // role as DEVICE_ROLE_NONE for a strategy
- default:
- ALOGE("%s invalid role %d", __func__, role);
- return BAD_VALUE;
- }
- return NO_ERROR;
+ std::function<bool(audio_source_t)> p = [](audio_source_t audioSource) {
+ return audio_is_valid_audio_source(audioSource);
+ };
+ return removeAllDevicesRoleForT(
+ mCapturePresetDevicesRoleMap, audioSource, role, "audio source" /*logStr*/, p);
}
status_t EngineBase::getDevicesForRoleAndCapturePreset(audio_source_t audioSource,
device_role_t role, AudioDeviceTypeAddrVector &devices) const
{
- // verify if the audio source is valid
- if (!audio_is_valid_audio_source(audioSource)) {
- ALOGE("%s unknown audio source %u", __func__, audioSource);
- return BAD_VALUE;
- }
-
- switch (role) {
- case DEVICE_ROLE_PREFERRED:
- case DEVICE_ROLE_DISABLED: {
- if (mCapturePresetDevicesRole.count(audioSource) == 0) {
- return NAME_NOT_FOUND;
- }
- auto devIt = mCapturePresetDevicesRole.at(audioSource).find(role);
- if (devIt == mCapturePresetDevicesRole.at(audioSource).end()) {
- ALOGV("%s no devices role(%d) for capture preset %u", __func__, role, audioSource);
- return NAME_NOT_FOUND;
- }
-
- devices = devIt->second;
- } break;
- case DEVICE_ROLE_NONE:
- // Intentionally fall-through as the DEVICE_ROLE_NONE is never set
- default:
- ALOGE("%s invalid role %d", __func__, role);
- return BAD_VALUE;
- }
- return NO_ERROR;
+ std::function<bool(audio_source_t)> p = [](audio_source_t audioSource) {
+ return audio_is_valid_audio_source(audioSource);
+ };
+ return getDevicesRoleForT(
+ mCapturePresetDevicesRoleMap, audioSource, role, devices, "audio source" /*logStr*/, p);
}
status_t EngineBase::getMediaDevicesForRole(device_role_t role,
@@ -641,10 +621,22 @@
return activeDevices;
}
+void EngineBase::dumpCapturePresetDevicesRoleMap(String8 *dst, int spaces) const
+{
+ dst->appendFormat("\n%*sDevice role per capture preset dump:", spaces, "");
+ for (const auto& [capturePresetRolePair, devices] : mCapturePresetDevicesRoleMap) {
+ dst->appendFormat("\n%*sCapture preset(%u) Device Role(%u) Devices(%s)", spaces + 2, "",
+ capturePresetRolePair.first, capturePresetRolePair.second,
+ dumpAudioDeviceTypeAddrVector(devices, true /*includeSensitiveInfo*/).c_str());
+ }
+ dst->appendFormat("\n");
+}
+
void EngineBase::dump(String8 *dst) const
{
mProductStrategies.dump(dst, 2);
- mProductStrategyPreferredDevices.dump(dst, 2);
+ dumpProductStrategyDevicesRoleMap(mProductStrategyDeviceRoleMap, dst, 2);
+ dumpCapturePresetDevicesRoleMap(dst, 2);
mVolumeGroups.dump(dst, 2);
}
diff --git a/services/audiopolicy/engine/common/src/ProductStrategy.cpp b/services/audiopolicy/engine/common/src/ProductStrategy.cpp
index d4cea5a..b3d144f 100644
--- a/services/audiopolicy/engine/common/src/ProductStrategy.cpp
+++ b/services/audiopolicy/engine/common/src/ProductStrategy.cpp
@@ -320,14 +320,15 @@
}
}
-void ProductStrategyPreferredRoutingMap::dump(android::String8* dst, int spaces) const {
- dst->appendFormat("\n%*sPreferred devices per product strategy dump:", spaces, "");
- for (const auto& iter : *this) {
- dst->appendFormat("\n%*sStrategy %u %s",
- spaces + 2, "",
- (uint32_t) iter.first,
- dumpAudioDeviceTypeAddrVector(iter.second, true /*includeSensitiveInfo*/)
- .c_str());
+void dumpProductStrategyDevicesRoleMap(
+ const ProductStrategyDevicesRoleMap& productStrategyDeviceRoleMap,
+ String8 *dst,
+ int spaces) {
+ dst->appendFormat("\n%*sDevice role per product strategy dump:", spaces, "");
+ for (const auto& [strategyRolePair, devices] : productStrategyDeviceRoleMap) {
+ dst->appendFormat("\n%*sStrategy(%u) Device Role(%u) Devices(%s)", spaces + 2, "",
+ strategyRolePair.first, strategyRolePair.second,
+ dumpAudioDeviceTypeAddrVector(devices, true /*includeSensitiveInfo*/).c_str());
}
dst->appendFormat("\n");
}
diff --git a/services/audiopolicy/engine/interface/EngineInterface.h b/services/audiopolicy/engine/interface/EngineInterface.h
index f0a01d3..6a1d269 100644
--- a/services/audiopolicy/engine/interface/EngineInterface.h
+++ b/services/audiopolicy/engine/interface/EngineInterface.h
@@ -16,6 +16,8 @@
#pragma once
+#include <utility>
+
#include <AudioPolicyManagerObserver.h>
#include <media/AudioProductStrategy.h>
#include <media/AudioVolumeGroup.h>
@@ -35,7 +37,7 @@
using StrategyVector = std::vector<product_strategy_t>;
using VolumeGroupVector = std::vector<volume_group_t>;
using CapturePresetDevicesRoleMap =
- std::map<audio_source_t, std::map<device_role_t, AudioDeviceTypeAddrVector>>;
+ std::map<std::pair<audio_source_t, device_role_t>, AudioDeviceTypeAddrVector>;
/**
* This interface is dedicated to the policy manager that a Policy Engine shall implement.