Add a configurable version of the policy engine based on PFW

This patch adds a configurable version of the policy engine
based on the parameter framework.
This configurable engine shall be activated with a flag
USE_CONFIGURABLE_AUDIO_POLICY within BoardConfig.mk

This patch provides the generic configuration as an example.
This configuration provides the same user experience as the default
policy engine.

Change-Id: Ic8217333ae370b89bfdd2ad11320c5f14ea4da34
Signed-off-by: François Gaffie <francois.gaffie@intel.com>
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.cpp b/services/audiopolicy/engineconfigurable/src/Engine.cpp
new file mode 100755
index 0000000..c5cccfd
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/src/Engine.cpp
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "APM::AudioPolicyEngine"
+//#define LOG_NDEBUG 0
+
+//#define VERY_VERBOSE_LOGGING
+#ifdef VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+#include "Engine.h"
+#include "Strategy.h"
+#include "Stream.h"
+#include "InputSource.h"
+#include "Usage.h"
+#include <policy.h>
+#include <ParameterManagerWrapper.h>
+
+using std::string;
+using std::map;
+
+namespace android
+{
+namespace audio_policy
+{
+template <>
+StrategyCollection &Engine::getCollection<routing_strategy>()
+{
+    return mStrategyCollection;
+}
+template <>
+StreamCollection &Engine::getCollection<audio_stream_type_t>()
+{
+    return mStreamCollection;
+}
+template <>
+UsageCollection &Engine::getCollection<audio_usage_t>()
+{
+    return mUsageCollection;
+}
+template <>
+InputSourceCollection &Engine::getCollection<audio_source_t>()
+{
+    return mInputSourceCollection;
+}
+
+template <>
+const StrategyCollection &Engine::getCollection<routing_strategy>() const
+{
+    return mStrategyCollection;
+}
+template <>
+const StreamCollection &Engine::getCollection<audio_stream_type_t>() const
+{
+    return mStreamCollection;
+}
+template <>
+const UsageCollection &Engine::getCollection<audio_usage_t>() const
+{
+    return mUsageCollection;
+}
+template <>
+const InputSourceCollection &Engine::getCollection<audio_source_t>() const
+{
+    return mInputSourceCollection;
+}
+
+Engine::Engine()
+    : mManagerInterface(this),
+      mPluginInterface(this),
+      mPolicyParameterMgr(new ParameterManagerWrapper()),
+      mApmObserver(NULL)
+{
+    if (mPolicyParameterMgr->start() != NO_ERROR) {
+        ALOGE("%s: could not start Policy PFW", __FUNCTION__);
+        delete mPolicyParameterMgr;
+        mPolicyParameterMgr = NULL;
+    }
+}
+
+Engine::~Engine()
+{
+    mStrategyCollection.clear();
+    mStreamCollection.clear();
+    mInputSourceCollection.clear();
+    mUsageCollection.clear();
+}
+
+
+void Engine::setObserver(AudioPolicyManagerObserver *observer)
+{
+    ALOG_ASSERT(observer != NULL, "Invalid Audio Policy Manager observer");
+    mApmObserver = observer;
+}
+
+status_t Engine::initCheck()
+{
+    return (mPolicyParameterMgr != NULL) &&
+            mPolicyParameterMgr->isStarted() &&
+            (mApmObserver != NULL)?
+                NO_ERROR : NO_INIT;
+}
+
+bool Engine::setVolumeProfileForStream(const audio_stream_type_t &streamType,
+                                       Volume::device_category deviceCategory,
+                                       const VolumeCurvePoints &points)
+{
+    Stream *stream = getFromCollection<audio_stream_type_t>(streamType);
+    if (stream == NULL) {
+        ALOGE("%s: stream %d not found", __FUNCTION__, streamType);
+        return false;
+    }
+    return stream->setVolumeProfile(deviceCategory, points) == NO_ERROR;
+}
+
+template <typename Key>
+Element<Key> *Engine::getFromCollection(const Key &key) const
+{
+    const Collection<Key> collection = getCollection<Key>();
+    return collection.get(key);
+}
+
+template <typename Key>
+status_t Engine::add(const std::string &name, const Key &key)
+{
+    Collection<Key> &collection = getCollection<Key>();
+    return collection.add(name, key);
+}
+
+template <>
+routing_strategy Engine::getPropertyForKey<routing_strategy, audio_usage_t>(audio_usage_t usage) const
+{
+    const AudioOutputCollection &outputs = mApmObserver->getOutputs();
+
+    if (usage == AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY &&
+            (outputs.isStreamActive(AUDIO_STREAM_RING) ||
+             outputs.isStreamActive(AUDIO_STREAM_ALARM))) {
+        return STRATEGY_SONIFICATION;
+    }
+    return getPropertyForKey<routing_strategy, audio_usage_t>(usage);
+}
+
+template <typename Property, typename Key>
+Property Engine::getPropertyForKey(Key key) const
+{
+    Element<Key> *element = getFromCollection<Key>(key);
+    if (element == NULL) {
+        ALOGE("%s: Element not found within collection", __FUNCTION__);
+        return static_cast<Property>(0);
+    }
+    return element->template get<Property>();
+}
+
+template <>
+audio_devices_t Engine::getPropertyForKey<audio_devices_t, routing_strategy>(routing_strategy strategy) const
+{
+    const AudioOutputCollection &outputs = mApmObserver->getOutputs();
+
+    /** 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
+     */
+    if (strategy == STRATEGY_SONIFICATION_RESPECTFUL &&
+            !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)) {
+        return getPropertyForKey<audio_devices_t, routing_strategy>(STRATEGY_MEDIA);
+    }
+    return getPropertyForKey<audio_devices_t, routing_strategy>(strategy);
+}
+
+routing_strategy Engine::ManagerInterfaceImpl::getStrategyForUsage(audio_usage_t usage)
+{
+    return mPolicyEngine->getPropertyForKey<routing_strategy, audio_usage_t>(usage);
+}
+
+audio_devices_t Engine::ManagerInterfaceImpl::getDeviceForStrategy(routing_strategy stategy) const
+{
+    return mPolicyEngine->getPropertyForKey<audio_devices_t, routing_strategy>(stategy);
+}
+
+template <typename Property, typename Key>
+bool Engine::setPropertyForKey(const Property &property, const Key &key)
+{
+    Element<Key> *element = getFromCollection<Key>(key);
+    if (element == NULL) {
+        ALOGE("%s: Element not found within collection", __FUNCTION__);
+        return BAD_VALUE;
+    }
+    return element->template set<Property>(property) == NO_ERROR;
+}
+
+float Engine::volIndexToAmpl(Volume::device_category category,
+                             audio_stream_type_t streamType,
+                             int indexInUi)
+{
+    Stream *stream = getFromCollection<audio_stream_type_t>(streamType);
+    if (stream == NULL) {
+        ALOGE("%s: Element indexed by key=%d not found", __FUNCTION__, streamType);
+        return 1.0f;
+    }
+    return stream->volIndexToAmpl(category, indexInUi);
+}
+
+status_t Engine::initStreamVolume(audio_stream_type_t streamType,
+                                           int indexMin, int indexMax)
+{
+    Stream *stream = getFromCollection<audio_stream_type_t>(streamType);
+    if (stream == NULL) {
+        ALOGE("%s: Stream Type %d not found", __FUNCTION__, streamType);
+        return BAD_TYPE;
+    }
+    return stream->initVolume(indexMin, indexMax);
+}
+
+status_t Engine::setPhoneState(audio_mode_t mode)
+{
+    return mPolicyParameterMgr->setPhoneState(mode);
+}
+
+audio_mode_t Engine::getPhoneState() const
+{
+    return mPolicyParameterMgr->getPhoneState();
+}
+
+status_t Engine::setForceUse(audio_policy_force_use_t usage,
+                                      audio_policy_forced_cfg_t config)
+{
+    return mPolicyParameterMgr->setForceUse(usage, config);
+}
+
+audio_policy_forced_cfg_t Engine::getForceUse(audio_policy_force_use_t usage) const
+{
+    return mPolicyParameterMgr->getForceUse(usage);
+}
+
+status_t Engine::setDeviceConnectionState(audio_devices_t devices, audio_policy_dev_state_t state,
+                                          const char *deviceAddress)
+{
+    return mPolicyParameterMgr->setDeviceConnectionState(devices, state, deviceAddress);
+}
+
+template <>
+AudioPolicyManagerInterface *Engine::queryInterface()
+{
+    return &mManagerInterface;
+}
+
+template <>
+AudioPolicyPluginInterface *Engine::queryInterface()
+{
+    return &mPluginInterface;
+}
+
+} // namespace audio_policy
+} // namespace android
+
+