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