audiopolicy: engine: Add ProductStrategy common code
-Adds new Engine APIs for Product Strategy management
-Adds a common engine code to handle product strategies
-Adds a parsing configuration library to feed the strategies
-Prepare both engine for the switch
Test: make
Change-Id: I00f57ece798893bc6f9aa9ed54a3e5237e8d5cf1
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.cpp b/services/audiopolicy/engineconfigurable/src/Engine.cpp
index 009cf90..815de25 100644
--- a/services/audiopolicy/engineconfigurable/src/Engine.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Engine.cpp
@@ -29,6 +29,8 @@
#include "Stream.h"
#include "InputSource.h"
#include "Usage.h"
+
+#include <EngineConfig.h>
#include <policy.h>
#include <ParameterManagerWrapper.h>
@@ -80,12 +82,12 @@
return mInputSourceCollection;
}
-Engine::Engine()
- : mManagerInterface(this),
- mPluginInterface(this),
- mPolicyParameterMgr(new ParameterManagerWrapper()),
- mApmObserver(NULL)
+Engine::Engine() : mPolicyParameterMgr(new ParameterManagerWrapper())
{
+ status_t loadResult = loadAudioPolicyEngineConfig();
+ if (loadResult < 0) {
+ ALOGE("Policy Engine configuration is invalid.");
+ }
}
Engine::~Engine()
@@ -96,20 +98,13 @@
mUsageCollection.clear();
}
-
-void Engine::setObserver(AudioPolicyManagerObserver *observer)
-{
- ALOG_ASSERT(observer != NULL, "Invalid Audio Policy Manager observer");
- mApmObserver = observer;
-}
-
status_t Engine::initCheck()
{
- if (mPolicyParameterMgr == NULL || mPolicyParameterMgr->start() != NO_ERROR) {
+ if (mPolicyParameterMgr == nullptr || mPolicyParameterMgr->start() != NO_ERROR) {
ALOGE("%s: could not start Policy PFW", __FUNCTION__);
return NO_INIT;
}
- return (mApmObserver != NULL)? NO_ERROR : NO_INIT;
+ return EngineBase::initCheck();
}
template <typename Key>
@@ -137,14 +132,14 @@
return element->template get<Property>();
}
-routing_strategy Engine::ManagerInterfaceImpl::getStrategyForUsage(audio_usage_t usage)
+routing_strategy Engine::getStrategyForUsage(audio_usage_t usage)
{
- return mPolicyEngine->getPropertyForKey<routing_strategy, audio_usage_t>(usage);
+ return getPropertyForKey<routing_strategy, audio_usage_t>(usage);
}
-audio_devices_t Engine::ManagerInterfaceImpl::getDeviceForStrategy(routing_strategy strategy) const
+audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const
{
- const SwAudioOutputCollection &outputs = mPolicyEngine->mApmObserver->getOutputs();
+ const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
/** This is the only case handled programmatically because the PFW is unable to know the
* activity of streams.
@@ -161,31 +156,28 @@
!outputs.isStreamActiveRemotely(AUDIO_STREAM_MUSIC,
SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY) &&
outputs.isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
- return mPolicyEngine->getPropertyForKey<audio_devices_t, routing_strategy>(STRATEGY_MEDIA);
+ return getPropertyForKey<audio_devices_t, routing_strategy>(STRATEGY_MEDIA);
}
if (strategy == STRATEGY_ACCESSIBILITY &&
(outputs.isStreamActive(AUDIO_STREAM_RING) || outputs.isStreamActive(AUDIO_STREAM_ALARM))) {
// do not route accessibility prompts to a digital output currently configured with a
// compressed format as they would likely not be mixed and dropped.
// Device For Sonification conf file has HDMI, SPDIF and HDMI ARC unreacheable.
- return mPolicyEngine->getPropertyForKey<audio_devices_t, routing_strategy>(
- STRATEGY_SONIFICATION);
+ return getPropertyForKey<audio_devices_t, routing_strategy>(STRATEGY_SONIFICATION);
}
- return mPolicyEngine->getPropertyForKey<audio_devices_t, routing_strategy>(strategy);
+ return getPropertyForKey<audio_devices_t, routing_strategy>(strategy);
}
-bool Engine::PluginInterfaceImpl::setVolumeProfileForStream(const audio_stream_type_t &stream,
- const audio_stream_type_t &profile)
+bool Engine::setVolumeProfileForStream(const audio_stream_type_t &stream,
+ const audio_stream_type_t &profile)
{
- if (mPolicyEngine->setPropertyForKey<audio_stream_type_t, audio_stream_type_t>(stream,
- profile)) {
- mPolicyEngine->mApmObserver->getVolumeCurves().switchVolumeCurve(profile, stream);
+ if (setPropertyForKey<audio_stream_type_t, audio_stream_type_t>(stream, profile)) {
+ getApmObserver()->getVolumeCurves().switchVolumeCurve(profile, stream);
return true;
}
return false;
}
-
template <typename Property, typename Key>
bool Engine::setPropertyForKey(const Property &property, const Key &key)
{
@@ -199,7 +191,11 @@
status_t Engine::setPhoneState(audio_mode_t mode)
{
- return mPolicyParameterMgr->setPhoneState(mode);
+ status_t status = mPolicyParameterMgr->setPhoneState(mode);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ return EngineBase::setPhoneState(mode);
}
audio_mode_t Engine::getPhoneState() const
@@ -210,7 +206,11 @@
status_t Engine::setForceUse(audio_policy_force_use_t usage,
audio_policy_forced_cfg_t config)
{
- return mPolicyParameterMgr->setForceUse(usage, config);
+ status_t status = mPolicyParameterMgr->setForceUse(usage, config);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ return EngineBase::setForceUse(usage, config);
}
audio_policy_forced_cfg_t Engine::getForceUse(audio_policy_force_use_t usage) const
@@ -225,24 +225,144 @@
if (audio_is_output_device(devDesc->type())) {
return mPolicyParameterMgr->setAvailableOutputDevices(
- mApmObserver->getAvailableOutputDevices().types());
+ getApmObserver()->getAvailableOutputDevices().types());
} else if (audio_is_input_device(devDesc->type())) {
return mPolicyParameterMgr->setAvailableInputDevices(
- mApmObserver->getAvailableInputDevices().types());
+ getApmObserver()->getAvailableInputDevices().types());
}
return BAD_TYPE;
}
+status_t Engine::loadAudioPolicyEngineConfig()
+{
+ auto result = EngineBase::loadAudioPolicyEngineConfig();
+
+ return result.nbSkippedElement == 0? NO_ERROR : BAD_VALUE;
+}
+
+DeviceVector Engine::getDevicesForProductStrategy(product_strategy_t ps) const
+{
+ const auto productStrategies = getProductStrategies();
+ if (productStrategies.find(ps) == productStrategies.end()) {
+ ALOGE("%s: Trying to get device on invalid strategy %d", __FUNCTION__, ps);
+ return {};
+ }
+ const DeviceVector &availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
+ const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
+ uint32_t availableOutputDevicesType = availableOutputDevices.types();
+
+ /** This is the only case handled programmatically because the PFW is unable to know the
+ * activity of streams.
+ *
+ * -While media is playing on a remote device, use the the sonification behavior.
+ * Note that we test this usecase before testing if media is playing because
+ * the isStreamActive() method only informs about the activity of a stream, not
+ * if it's for local playback. Note also that we use the same delay between both tests
+ *
+ * -When media is not playing anymore, fall back on the sonification behavior
+ */
+ audio_devices_t devices = AUDIO_DEVICE_NONE;
+ if (ps == getProductStrategyForStream(AUDIO_STREAM_NOTIFICATION) &&
+ !is_state_in_call(getPhoneState()) &&
+ !outputs.isStreamActiveRemotely(AUDIO_STREAM_MUSIC,
+ SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY) &&
+ outputs.isStreamActive(AUDIO_STREAM_MUSIC,
+ SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
+ product_strategy_t strategyForMedia =
+ getProductStrategyForStream(AUDIO_STREAM_MUSIC);
+ devices = productStrategies.getDeviceTypesForProductStrategy(strategyForMedia);
+ } else if (ps == getProductStrategyForStream(AUDIO_STREAM_ACCESSIBILITY) &&
+ (outputs.isStreamActive(AUDIO_STREAM_RING) ||
+ outputs.isStreamActive(AUDIO_STREAM_ALARM))) {
+ // do not route accessibility prompts to a digital output currently configured with a
+ // compressed format as they would likely not be mixed and dropped.
+ // Device For Sonification conf file has HDMI, SPDIF and HDMI ARC unreacheable.
+ product_strategy_t strategyNotification = getProductStrategyForStream(AUDIO_STREAM_RING);
+ devices = productStrategies.getDeviceTypesForProductStrategy(strategyNotification);
+ } else {
+ devices = productStrategies.getDeviceTypesForProductStrategy(ps);
+ }
+ if (devices == AUDIO_DEVICE_NONE ||
+ (devices & availableOutputDevicesType) == AUDIO_DEVICE_NONE) {
+ devices = getApmObserver()->getDefaultOutputDevice()->type();
+ ALOGE_IF(devices == AUDIO_DEVICE_NONE, "%s: no valid default device defined", __FUNCTION__);
+ return DeviceVector(getApmObserver()->getDefaultOutputDevice());
+ }
+ if (/*device_distinguishes_on_address(devices)*/ devices == AUDIO_DEVICE_OUT_BUS) {
+ // We do expect only one device for these types of devices
+ // Criterion device address garantee this one is available
+ // If this criterion is not wished, need to ensure this device is available
+ const String8 address(productStrategies.getDeviceAddressForProductStrategy(ps).c_str());
+ ALOGV("%s:device 0x%x %s %d", __FUNCTION__, devices, address.c_str(), ps);
+ return DeviceVector(availableOutputDevices.getDevice(devices,
+ address,
+ AUDIO_FORMAT_DEFAULT));
+ }
+ ALOGV("%s:device 0x%x %d", __FUNCTION__, devices, ps);
+ return availableOutputDevices.getDevicesFromTypeMask(devices);
+}
+
+DeviceVector Engine::getOutputDevicesForAttributes(const audio_attributes_t &attributes,
+ const sp<DeviceDescriptor> &preferredDevice,
+ bool fromCache) const
+{
+ // First check for explict routing device
+ if (preferredDevice != nullptr) {
+ ALOGV("%s explicit Routing on device %s", __func__, preferredDevice->toString().c_str());
+ return DeviceVector(preferredDevice);
+ }
+ product_strategy_t strategy = EngineBase::getProductStrategyForAttributes(attributes);
+ //
+ // @TODO: manage dynamic mix
+ //
+ return fromCache? mDevicesForStrategies.at(strategy) : getDevicesForProductStrategy(strategy);
+}
+
+DeviceVector Engine::getOutputDevicesForStream(audio_stream_type_t stream, bool fromCache) const
+{
+ auto attributes = EngineBase::getAttributesForStreamType(stream);
+ return getOutputDevicesForAttributes(attributes, nullptr, fromCache);
+}
+
+sp<DeviceDescriptor> Engine::getInputDeviceForAttributes(const audio_attributes_t &attr,
+ AudioMix **/*mix*/) const
+{
+ const auto &availInputDevices = getApmObserver()->getAvailableInputDevices();
+ std::string address;
+ //
+ // @TODO: manage explicit routing and dynamic mix
+ //
+ audio_devices_t deviceType = getPropertyForKey<audio_devices_t, audio_source_t>(attr.source);
+
+ if (audio_is_remote_submix_device(deviceType)) {
+ address = "0";
+ std::size_t pos;
+ std::string tags { attr.tags };
+ if ((pos = tags.find("addr=")) != std::string::npos) {
+ address = tags.substr(pos + std::strlen("addr="));
+ }
+ }
+ return availInputDevices.getDevice(deviceType, String8(address.c_str()), AUDIO_FORMAT_DEFAULT);
+}
+
+void Engine::updateDeviceSelectionCache()
+{
+ for (const auto &iter : getProductStrategies()) {
+ const auto &strategy = iter.second;
+ mDevicesForStrategies[strategy->getId()] = getDevicesForProductStrategy(strategy->getId());
+ }
+}
+
template <>
AudioPolicyManagerInterface *Engine::queryInterface()
{
- return &mManagerInterface;
+ return this;
}
template <>
AudioPolicyPluginInterface *Engine::queryInterface()
{
- return &mPluginInterface;
+ return this;
}
} // namespace audio_policy
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.h b/services/audiopolicy/engineconfigurable/src/Engine.h
index ba4f889..aebf27d 100644
--- a/services/audiopolicy/engineconfigurable/src/Engine.h
+++ b/services/audiopolicy/engineconfigurable/src/Engine.h
@@ -16,7 +16,7 @@
#pragma once
-
+#include "EngineBase.h"
#include <AudioPolicyManagerInterface.h>
#include <AudioPolicyPluginInterface.h>
#include "Collection.h"
@@ -29,7 +29,7 @@
class ParameterManagerWrapper;
class VolumeProfile;
-class Engine
+class Engine : public EngineBase, AudioPolicyPluginInterface
{
public:
Engine();
@@ -38,129 +38,93 @@
template <class RequestedInterface>
RequestedInterface *queryInterface();
-private:
- /// Interface members
- class ManagerInterfaceImpl : public AudioPolicyManagerInterface
+ ///
+ /// from EngineBase
+ ///
+ android::status_t initCheck() override;
+
+ audio_devices_t getDeviceForInputSource(audio_source_t inputSource) const override
{
- public:
- ManagerInterfaceImpl(Engine *policyEngine)
- : mPolicyEngine(policyEngine) {}
+ return getPropertyForKey<audio_devices_t, audio_source_t>(inputSource);
+ }
- virtual android::status_t initCheck()
- {
- return mPolicyEngine->initCheck();
- }
- virtual void setObserver(AudioPolicyManagerObserver *observer)
- {
- mPolicyEngine->setObserver(observer);
- }
- virtual audio_devices_t getDeviceForInputSource(audio_source_t inputSource) const
- {
- return mPolicyEngine->getPropertyForKey<audio_devices_t, audio_source_t>(inputSource);
- }
- virtual audio_devices_t getDeviceForStrategy(routing_strategy stategy) const;
- virtual routing_strategy getStrategyForStream(audio_stream_type_t stream)
- {
- return mPolicyEngine->getPropertyForKey<routing_strategy, audio_stream_type_t>(stream);
- }
- virtual routing_strategy getStrategyForUsage(audio_usage_t usage);
- virtual status_t setPhoneState(audio_mode_t mode)
- {
- return mPolicyEngine->setPhoneState(mode);
- }
- virtual audio_mode_t getPhoneState() const
- {
- return mPolicyEngine->getPhoneState();
- }
- virtual status_t setForceUse(audio_policy_force_use_t usage,
- audio_policy_forced_cfg_t config)
- {
- return mPolicyEngine->setForceUse(usage, config);
- }
- virtual audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage) const
- {
- return mPolicyEngine->getForceUse(usage);
- }
- virtual android::status_t setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
- audio_policy_dev_state_t state)
- {
- return mPolicyEngine->setDeviceConnectionState(devDesc, state);
- }
+ audio_devices_t getDeviceForStrategy(routing_strategy stategy) const override;
- private:
- Engine *mPolicyEngine;
- } mManagerInterface;
-
- class PluginInterfaceImpl : public AudioPolicyPluginInterface
+ routing_strategy getStrategyForStream(audio_stream_type_t stream) override
{
- public:
- PluginInterfaceImpl(Engine *policyEngine)
- : mPolicyEngine(policyEngine) {}
+ return getPropertyForKey<routing_strategy, audio_stream_type_t>(stream);
+ }
- virtual status_t addStrategy(const std::string &name, routing_strategy strategy)
- {
- return mPolicyEngine->add<routing_strategy>(name, strategy);
- }
- virtual status_t addStream(const std::string &name, audio_stream_type_t stream)
- {
- return mPolicyEngine->add<audio_stream_type_t>(name, stream);
- }
- virtual status_t addUsage(const std::string &name, audio_usage_t usage)
- {
- return mPolicyEngine->add<audio_usage_t>(name, usage);
- }
- virtual status_t addInputSource(const std::string &name, audio_source_t source)
- {
- return mPolicyEngine->add<audio_source_t>(name, source);
- }
- virtual bool setDeviceForStrategy(const routing_strategy &strategy, audio_devices_t devices)
- {
- return mPolicyEngine->setPropertyForKey<audio_devices_t, routing_strategy>(devices,
- strategy);
- }
- virtual bool setStrategyForStream(const audio_stream_type_t &stream,
- routing_strategy strategy)
- {
- return mPolicyEngine->setPropertyForKey<routing_strategy, audio_stream_type_t>(strategy,
- stream);
- }
- virtual bool setVolumeProfileForStream(const audio_stream_type_t &stream,
- const audio_stream_type_t &volumeProfile);
+ routing_strategy getStrategyForUsage(audio_usage_t usage) override;
- virtual bool setStrategyForUsage(const audio_usage_t &usage, routing_strategy strategy)
- {
- return mPolicyEngine->setPropertyForKey<routing_strategy, audio_usage_t>(strategy,
- usage);
- }
- virtual bool setDeviceForInputSource(const audio_source_t &inputSource,
- audio_devices_t device)
- {
- return mPolicyEngine->setPropertyForKey<audio_devices_t, audio_source_t>(device,
- inputSource);
- }
+ status_t setPhoneState(audio_mode_t mode) override;
- private:
- Engine *mPolicyEngine;
- } mPluginInterface;
+ audio_mode_t getPhoneState() const override;
+
+ status_t setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config) override;
+
+ audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage) const override;
+
+ android::status_t setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
+ audio_policy_dev_state_t state) override;
+
+ DeviceVector getOutputDevicesForAttributes(const audio_attributes_t &attr,
+ const sp<DeviceDescriptor> &preferedDevice = nullptr,
+ bool fromCache = false) const override;
+
+ DeviceVector getOutputDevicesForStream(audio_stream_type_t stream,
+ bool fromCache = false) const override;
+
+ sp<DeviceDescriptor> getInputDeviceForAttributes(
+ const audio_attributes_t &attr, AudioMix **mix = nullptr) const override;
+
+ void updateDeviceSelectionCache() override;
+
+ ///
+ /// from AudioPolicyPluginInterface
+ ///
+ status_t addStrategy(const std::string &name, routing_strategy strategy) override
+ {
+ return add<routing_strategy>(name, strategy);
+ }
+ status_t addStream(const std::string &name, audio_stream_type_t stream) override
+ {
+ return add<audio_stream_type_t>(name, stream);
+ }
+ status_t addUsage(const std::string &name, audio_usage_t usage) override
+ {
+ return add<audio_usage_t>(name, usage);
+ }
+ status_t addInputSource(const std::string &name, audio_source_t source) override
+ {
+ return add<audio_source_t>(name, source);
+ }
+ bool setDeviceForStrategy(const routing_strategy &strategy, audio_devices_t devices) override
+ {
+ return setPropertyForKey<audio_devices_t, routing_strategy>(devices, strategy);
+ }
+ bool setStrategyForStream(const audio_stream_type_t &stream,
+ routing_strategy strategy) override
+ {
+ return setPropertyForKey<routing_strategy, audio_stream_type_t>(strategy, stream);
+ }
+ bool setVolumeProfileForStream(const audio_stream_type_t &stream,
+ const audio_stream_type_t &volumeProfile) override;
+
+ bool setStrategyForUsage(const audio_usage_t &usage, routing_strategy strategy) override
+ {
+ return setPropertyForKey<routing_strategy, audio_usage_t>(strategy, usage);
+ }
+ bool setDeviceForInputSource(const audio_source_t &inputSource, audio_devices_t device) override
+ {
+ return setPropertyForKey<audio_devices_t, audio_source_t>(device, inputSource);
+ }
private:
/* Copy facilities are put private to disable copy. */
Engine(const Engine &object);
Engine &operator=(const Engine &object);
- void setObserver(AudioPolicyManagerObserver *observer);
-
- bool setVolumeProfileForStream(const audio_stream_type_t &stream,
- device_category deviceCategory,
- const VolumeCurvePoints &points);
-
- status_t initCheck();
- status_t setPhoneState(audio_mode_t mode);
- audio_mode_t getPhoneState() const;
- status_t setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config);
- audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage) const;
- status_t setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
- audio_policy_dev_state_t state);
StrategyCollection mStrategyCollection; /**< Strategies indexed by their enum id. */
StreamCollection mStreamCollection; /**< Streams indexed by their enum id. */
UsageCollection mUsageCollection; /**< Usages indexed by their enum id. */
@@ -184,12 +148,16 @@
template <typename Property, typename Key>
bool setPropertyForKey(const Property &property, const Key &key);
+ status_t loadAudioPolicyEngineConfig();
+
+ DeviceVector getDevicesForProductStrategy(product_strategy_t strategy) const;
+
/**
* Policy Parameter Manager hidden through a wrapper.
*/
ParameterManagerWrapper *mPolicyParameterMgr;
- AudioPolicyManagerObserver *mApmObserver;
+ DeviceStrategyMap mDevicesForStrategies;
};
} // namespace audio_policy