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/Android.mk b/services/audiopolicy/Android.mk
index ebb4f3b..243020d 100644
--- a/services/audiopolicy/Android.mk
+++ b/services/audiopolicy/Android.mk
@@ -11,9 +11,11 @@
LOCAL_C_INCLUDES := \
frameworks/av/services/audioflinger \
$(call include-path-for, audio-utils) \
- frameworks/av/services/audiopolicy/common/include \
frameworks/av/services/audiopolicy/engine/interface \
+LOCAL_HEADER_LIBRARIES := \
+ libaudiopolicycommon
+
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
@@ -76,10 +78,12 @@
endif # ifeq ($(USE_CONFIGURABLE_AUDIO_POLICY), 1)
LOCAL_C_INCLUDES += \
- frameworks/av/services/audiopolicy/common/include \
frameworks/av/services/audiopolicy/engine/interface \
$(call include-path-for, audio-utils) \
+LOCAL_HEADER_LIBRARIES := \
+ libaudiopolicycommon
+
LOCAL_STATIC_LIBRARIES := \
libaudiopolicycomponents
@@ -114,10 +118,12 @@
libaudiopolicycomponents
LOCAL_C_INCLUDES += \
- frameworks/av/services/audiopolicy/common/include \
frameworks/av/services/audiopolicy/engine/interface \
$(call include-path-for, audio-utils) \
+LOCAL_HEADER_LIBRARIES := \
+ libaudiopolicycommon
+
LOCAL_CFLAGS := -Wall -Werror
LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
diff --git a/services/audiopolicy/common/include/RoutingStrategy.h b/services/audiopolicy/common/include/RoutingStrategy.h
index f8a1cd6..bddb340 100644
--- a/services/audiopolicy/common/include/RoutingStrategy.h
+++ b/services/audiopolicy/common/include/RoutingStrategy.h
@@ -18,10 +18,6 @@
namespace android {
-// Time in milliseconds after media stopped playing during which we consider that the
-// sonification should be as unobtrusive as during the time media was playing.
-#define SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY 5000
-
enum routing_strategy {
STRATEGY_NONE = -1,
STRATEGY_MEDIA,
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index 837ca47..04f1eb2 100644
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -17,9 +17,21 @@
#pragma once
#include <system/audio.h>
+#include <vector>
+
+namespace android {
+
+using StreamTypeVector = std::vector<audio_stream_type_t>;
+
+
+static const audio_attributes_t defaultAttr = AUDIO_ATTRIBUTES_INITIALIZER;
+
+} // namespace android
static const audio_format_t gDynamicFormat = AUDIO_FORMAT_DEFAULT;
+static const uint32_t SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY = 5000;
+
// For mixed output and inputs, the policy will use max mixer sampling rates.
// Do not limit sampling rate otherwise
#define SAMPLE_RATE_HZ_MAX 192000
@@ -151,3 +163,9 @@
}
return format1 == format2;
}
+
+constexpr bool operator==(const audio_attributes_t &lhs, const audio_attributes_t &rhs)
+{
+ return lhs.usage == rhs.usage && lhs.content_type == rhs.content_type &&
+ lhs.flags == rhs.flags && (std::strcmp(lhs.tags, rhs.tags) == 0);
+}
diff --git a/services/audiopolicy/engine/Android.mk b/services/audiopolicy/engine/Android.mk
new file mode 100644
index 0000000..dcce8e3
--- /dev/null
+++ b/services/audiopolicy/engine/Android.mk
@@ -0,0 +1,9 @@
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+#######################################################################
+# Recursive call sub-folder Android.mk
+#
+include $(call all-makefiles-under,$(LOCAL_PATH))
+
diff --git a/services/audiopolicy/engine/common/Android.bp b/services/audiopolicy/engine/common/Android.bp
new file mode 100644
index 0000000..e6ede07
--- /dev/null
+++ b/services/audiopolicy/engine/common/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2018 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.
+
+cc_library_headers {
+ name: "libaudiopolicyengine_common_headers",
+ host_supported: true,
+ export_include_dirs: ["include"],
+}
diff --git a/services/audiopolicy/engine/common/include/EngineBase.h b/services/audiopolicy/engine/common/include/EngineBase.h
new file mode 100644
index 0000000..32898b1
--- /dev/null
+++ b/services/audiopolicy/engine/common/include/EngineBase.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include <EngineConfig.h>
+#include <AudioPolicyManagerInterface.h>
+#include <ProductStrategy.h>
+
+namespace android {
+namespace audio_policy {
+
+class EngineBase : public AudioPolicyManagerInterface
+{
+public:
+ ///
+ /// from AudioPolicyManagerInterface
+ ///
+ android::status_t initCheck() override;
+
+ void setObserver(AudioPolicyManagerObserver *observer) override;
+
+ status_t setPhoneState(audio_mode_t mode) override;
+
+ audio_mode_t getPhoneState() const override { return mPhoneState; }
+
+ status_t setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config) override
+ {
+ mForceUse[usage] = config;
+ return NO_ERROR;
+ }
+
+ audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage) const override
+ {
+ return mForceUse[usage];
+ }
+ android::status_t setDeviceConnectionState(const sp<DeviceDescriptor> /*devDesc*/,
+ audio_policy_dev_state_t /*state*/) override
+ {
+ return NO_ERROR;
+ }
+ product_strategy_t getProductStrategyForAttributes(
+ const audio_attributes_t &attr) const override;
+
+ audio_stream_type_t getStreamTypeForAttributes(const audio_attributes_t &attr) const override;
+
+ audio_attributes_t getAttributesForStreamType(audio_stream_type_t stream) const override;
+
+ StreamTypeVector getStreamTypesForProductStrategy(product_strategy_t ps) const override;
+
+ AttributesVector getAllAttributesForProductStrategy(product_strategy_t ps) const override;
+
+ StrategyVector getOrderedProductStrategies() const override;
+
+ void dump(String8 *dst) const override;
+
+
+ engineConfig::ParsingResult loadAudioPolicyEngineConfig();
+
+ const ProductStrategyMap &getProductStrategies() const { return mProductStrategies; }
+
+ ProductStrategyMap &getProductStrategies() { return mProductStrategies; }
+
+ product_strategy_t getProductStrategyForStream(audio_stream_type_t stream) const;
+
+ product_strategy_t getProductStrategyByName(const std::string &name) const;
+
+ AudioPolicyManagerObserver *getApmObserver() const { return mApmObserver; }
+
+ inline bool isInCall() const
+ {
+ return is_state_in_call(getPhoneState());
+ }
+
+private:
+ AudioPolicyManagerObserver *mApmObserver = nullptr;
+
+ ProductStrategyMap mProductStrategies;
+ audio_mode_t mPhoneState = AUDIO_MODE_NORMAL; /**< current phone state. */
+
+ /** current forced use configuration. */
+ audio_policy_forced_cfg_t mForceUse[AUDIO_POLICY_FORCE_USE_CNT] = {};
+};
+
+} // namespace audio_policy
+} // namespace android
diff --git a/services/audiopolicy/engine/common/include/ProductStrategy.h b/services/audiopolicy/engine/common/include/ProductStrategy.h
new file mode 100644
index 0000000..66ae86e
--- /dev/null
+++ b/services/audiopolicy/engine/common/include/ProductStrategy.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include <system/audio.h>
+#include <AudioPolicyManagerInterface.h>
+#include <utils/RefBase.h>
+#include <HandleGenerator.h>
+#include <string>
+#include <vector>
+#include <map>
+#include <utils/Errors.h>
+#include <utils/String8.h>
+
+namespace android {
+
+/**
+ * @brief The ProductStrategy class describes for each product_strategy_t identifier the
+ * associated audio attributes, the device types to use, the device address to use.
+ * The identifier is voluntarily not strongly typed in order to be extensible by OEM.
+ */
+class ProductStrategy : public virtual RefBase, private HandleGenerator<uint32_t>
+{
+private:
+ struct AudioAttributes {
+ audio_stream_type_t mStream = AUDIO_STREAM_DEFAULT;
+ uint32_t mGroupId = 0;
+ audio_attributes_t mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
+ };
+
+ using AudioAttributesVector = std::vector<AudioAttributes>;
+
+public:
+ ProductStrategy(const std::string &name);
+
+ void addAttributes(const AudioAttributes &audioAttributes);
+
+ std::string getName() const { return mName; }
+ AttributesVector getAudioAttributes() const;
+ product_strategy_t getId() const { return mId; }
+ StreamTypeVector getSupportedStreams() const;
+
+ /**
+ * @brief matches checks if the given audio attributes shall follow the strategy.
+ * Order of the attributes within a strategy matters.
+ * If only the usage is available, the check is performed on the usages of the given
+ * attributes, otherwise all fields must match.
+ * @param attributes to consider
+ * @return true if attributes matches with the strategy, false otherwise.
+ */
+ bool matches(const audio_attributes_t attributes) const;
+
+ bool supportStreamType(const audio_stream_type_t &streamType) const;
+
+ void setDeviceAddress(const std::string &address)
+ {
+ mDeviceAddress = address;
+ }
+
+ std::string getDeviceAddress() const { return mDeviceAddress; }
+
+ void setDeviceTypes(audio_devices_t devices)
+ {
+ mApplicableDevices = devices;
+ }
+
+ audio_devices_t getDeviceTypes() const { return mApplicableDevices; }
+
+ audio_attributes_t getAttributesForStreamType(audio_stream_type_t stream) const;
+ audio_stream_type_t getStreamTypeForAttributes(const audio_attributes_t &attr) const;
+
+ bool isDefault() const;
+
+ void dump(String8 *dst, int spaces = 0) const;
+
+ /**
+ * @brief attributesMatches: checks if client attributes matches with a reference attributes
+ * "matching" means the usage shall match if reference attributes has a defined usage, AND
+ * content type shall match if reference attributes has a defined content type AND
+ * flags shall match if reference attributes has defined flags AND
+ * tags shall match if reference attributes has defined tags.
+ * Reference attributes "default" shall not be considered as a "true" case. This convention
+ * is used to identify the default strategy.
+ * @param refAttributes to be considered
+ * @param clientAttritubes to be considered
+ * @return true if matching, false otherwise
+ */
+ static bool attributesMatches(const audio_attributes_t refAttributes,
+ const audio_attributes_t clientAttritubes);
+private:
+ std::string mName;
+
+ AudioAttributesVector mAttributesVector;
+
+ product_strategy_t mId;
+
+ std::string mDeviceAddress; /**< Device address applicable for this strategy, maybe empty */
+
+ /**
+ * Applicable device(s) type mask for this strategy.
+ */
+ audio_devices_t mApplicableDevices = AUDIO_DEVICE_NONE;
+};
+
+class ProductStrategyMap : public std::map<product_strategy_t, sp<ProductStrategy> >
+{
+public:
+ /**
+ * @brief getProductStrategyForAttribute. The order of the vector is dimensionning.
+ * @param attr
+ * @return applicable product strategy for the given attribute, default if none applicable.
+ */
+ product_strategy_t getProductStrategyForAttributes(const audio_attributes_t &attr) const;
+
+ product_strategy_t getProductStrategyForStream(audio_stream_type_t stream) const;
+
+ audio_attributes_t getAttributesForStreamType(audio_stream_type_t stream) const;
+
+ audio_stream_type_t getStreamTypeForAttributes(const audio_attributes_t &attr) const;
+
+ /**
+ * @brief getAttributesForProductStrategy can be called from
+ * AudioManager: in this case, the product strategy IS the former routing strategy
+ * CarAudioManager: in this case, the product strategy IS the car usage
+ * [getAudioAttributesForCarUsage]
+ * OemExtension: in this case, the product strategy IS the Oem usage
+ *
+ * @param strategy
+ * @return audio attributes (or at least one of the attributes) following the given strategy.
+ */
+ audio_attributes_t getAttributesForProductStrategy(product_strategy_t strategy) const;
+
+ audio_devices_t getDeviceTypesForProductStrategy(product_strategy_t strategy) const;
+
+ std::string getDeviceAddressForProductStrategy(product_strategy_t strategy) const;
+
+ product_strategy_t getDefault() const;
+
+ void dump(String8 *dst, int spaces = 0) const;
+};
+
+} // namespace android
diff --git a/services/audiopolicy/engine/common/src/EngineBase.cpp b/services/audiopolicy/engine/common/src/EngineBase.cpp
new file mode 100644
index 0000000..0f4d5a5
--- /dev/null
+++ b/services/audiopolicy/engine/common/src/EngineBase.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2018 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/Base"
+#define LOG_NDEBUG 0
+
+#include "EngineBase.h"
+#include "EngineDefaultConfig.h"
+#include <TypeConverter.h>
+
+namespace android {
+namespace audio_policy {
+
+void EngineBase::setObserver(AudioPolicyManagerObserver *observer)
+{
+ ALOG_ASSERT(observer != NULL, "Invalid Audio Policy Manager observer");
+ mApmObserver = observer;
+}
+
+status_t EngineBase::initCheck()
+{
+ return (mApmObserver != nullptr)? NO_ERROR : NO_INIT;
+}
+
+status_t EngineBase::setPhoneState(audio_mode_t state)
+{
+ ALOGV("setPhoneState() state %d", state);
+
+ if (state < 0 || state >= AUDIO_MODE_CNT) {
+ ALOGW("setPhoneState() invalid state %d", state);
+ return BAD_VALUE;
+ }
+
+ if (state == mPhoneState ) {
+ ALOGW("setPhoneState() setting same state %d", state);
+ return BAD_VALUE;
+ }
+
+ // store previous phone state for management of sonification strategy below
+ int oldState = mPhoneState;
+ mPhoneState = state;
+
+ if (!is_state_in_call(oldState) && is_state_in_call(state)) {
+ ALOGV(" Entering call in setPhoneState()");
+ } else if (is_state_in_call(oldState) && !is_state_in_call(state)) {
+ ALOGV(" Exiting call in setPhoneState()");
+ }
+ return NO_ERROR;
+}
+
+product_strategy_t EngineBase::getProductStrategyForAttributes(const audio_attributes_t &attr) const
+{
+ return mProductStrategies.getProductStrategyForAttributes(attr);
+}
+
+audio_stream_type_t EngineBase::getStreamTypeForAttributes(const audio_attributes_t &attr) const
+{
+ return mProductStrategies.getStreamTypeForAttributes(attr);
+}
+
+audio_attributes_t EngineBase::getAttributesForStreamType(audio_stream_type_t stream) const
+{
+ return mProductStrategies.getAttributesForStreamType(stream);
+}
+
+product_strategy_t EngineBase::getProductStrategyForStream(audio_stream_type_t stream) const
+{
+ return mProductStrategies.getProductStrategyForStream(stream);
+}
+
+product_strategy_t EngineBase::getProductStrategyByName(const std::string &name) const
+{
+ for (const auto &iter : mProductStrategies) {
+ if (iter.second->getName() == name) {
+ return iter.second->getId();
+ }
+ }
+ return PRODUCT_STRATEGY_NONE;
+}
+
+engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig()
+{
+ auto loadProductStrategies =
+ [](auto& strategyConfigs, auto& productStrategies) {
+ uint32_t groupid = 0;
+ for (auto& strategyConfig : strategyConfigs) {
+ sp<ProductStrategy> strategy = new ProductStrategy(strategyConfig.name);
+ for (const auto &group : strategyConfig.attributesGroups) {
+ for (const auto &attr : group.attributesVect) {
+ strategy->addAttributes({group.stream, groupid, attr});
+ }
+ groupid += 1;
+ }
+ product_strategy_t strategyId = strategy->getId();
+ productStrategies[strategyId] = strategy;
+ }
+ };
+
+ auto result = engineConfig::parse();
+ if (result.parsedConfig == nullptr) {
+ ALOGW("%s: No configuration found, using default matching phone experience.", __FUNCTION__);
+ result = {std::make_unique<engineConfig::Config>(gDefaultEngineConfig), 0};
+ }
+ ALOGE_IF(result.nbSkippedElement != 0, "skipped %zu elements", result.nbSkippedElement);
+ loadProductStrategies(result.parsedConfig->productStrategies, mProductStrategies);
+ return result;
+}
+
+StrategyVector EngineBase::getOrderedProductStrategies() const
+{
+ auto findByFlag = [](const auto &productStrategies, auto flag) {
+ return std::find_if(begin(productStrategies), end(productStrategies),
+ [&](const auto &strategy) {
+ for (const auto &attributes : strategy.second->getAudioAttributes()) {
+ if ((attributes.flags & flag) == flag) {
+ return true;
+ }
+ }
+ return false;
+ });
+ };
+ auto strategies = mProductStrategies;
+ auto enforcedAudibleStrategyIter = findByFlag(strategies, AUDIO_FLAG_AUDIBILITY_ENFORCED);
+
+ if (getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED &&
+ enforcedAudibleStrategyIter != strategies.end()) {
+ auto enforcedAudibleStrategy = *enforcedAudibleStrategyIter;
+ strategies.erase(enforcedAudibleStrategyIter);
+ strategies.insert(begin(strategies), enforcedAudibleStrategy);
+ }
+ StrategyVector orderedStrategies;
+ for (const auto &iter : strategies) {
+ orderedStrategies.push_back(iter.second->getId());
+ }
+ return orderedStrategies;
+}
+
+StreamTypeVector EngineBase::getStreamTypesForProductStrategy(product_strategy_t ps) const
+{
+ // @TODO default music stream to control volume if no group?
+ return (mProductStrategies.find(ps) != end(mProductStrategies)) ?
+ mProductStrategies.at(ps)->getSupportedStreams() :
+ StreamTypeVector(AUDIO_STREAM_MUSIC);
+}
+
+AttributesVector EngineBase::getAllAttributesForProductStrategy(product_strategy_t ps) const
+{
+ return (mProductStrategies.find(ps) != end(mProductStrategies)) ?
+ mProductStrategies.at(ps)->getAudioAttributes() : AttributesVector();
+}
+
+void EngineBase::dump(String8 *dst) const
+{
+ mProductStrategies.dump(dst, 2);
+}
+
+} // namespace audio_policy
+} // namespace android
diff --git a/services/audiopolicy/engine/common/src/EngineDefaultConfig.h b/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
new file mode 100644
index 0000000..5f546b3
--- /dev/null
+++ b/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include <system/audio.h>
+
+namespace android {
+/**
+ * @brief AudioProductStrategies hard coded array of strategies to fill new engine API contract.
+ */
+const engineConfig::ProductStrategies gOrderedStrategies = {
+ {"STRATEGY_PHONE",
+ {
+ {"phone", AUDIO_STREAM_VOICE_CALL,
+ {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_VOICE_COMMUNICATION, AUDIO_SOURCE_DEFAULT, 0,
+ ""}},
+ },
+ {"sco", AUDIO_STREAM_BLUETOOTH_SCO,
+ {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_SCO,
+ ""}},
+ }
+ },
+ },
+ {"STRATEGY_SONIFICATION",
+ {
+ {"ring", AUDIO_STREAM_RING,
+ {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE,
+ AUDIO_SOURCE_DEFAULT, 0, ""}}
+ },
+ {"alarm", AUDIO_STREAM_ALARM,
+ {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_ALARM, AUDIO_SOURCE_DEFAULT, 0, ""}},
+ }
+ },
+ },
+ {"STRATEGY_ENFORCED_AUDIBLE",
+ {
+ {"", AUDIO_STREAM_ENFORCED_AUDIBLE,
+ {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT,
+ AUDIO_FLAG_AUDIBILITY_ENFORCED, ""}}
+ }
+ },
+ },
+ {"STRATEGY_ACCESSIBILITY",
+ {
+ {"", AUDIO_STREAM_ACCESSIBILITY,
+ {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY,
+ AUDIO_SOURCE_DEFAULT, 0, ""}}
+ }
+ },
+ },
+ {"STRATEGY_SONIFICATION_RESPECTFUL",
+ {
+ {"", AUDIO_STREAM_NOTIFICATION,
+ {
+ {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_NOTIFICATION, AUDIO_SOURCE_DEFAULT, 0, ""},
+ {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
+ AUDIO_SOURCE_DEFAULT, 0, ""},
+ {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
+ AUDIO_SOURCE_DEFAULT, 0, ""},
+ {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
+ AUDIO_SOURCE_DEFAULT, 0, ""},
+ {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_NOTIFICATION_EVENT,
+ AUDIO_SOURCE_DEFAULT, 0, ""}
+ }
+ }
+ },
+ },
+ {"STRATEGY_MEDIA",
+ {
+ {"music", AUDIO_STREAM_MUSIC,
+ {
+ {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_MEDIA, AUDIO_SOURCE_DEFAULT, 0, ""},
+ {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_GAME, AUDIO_SOURCE_DEFAULT, 0, ""},
+ {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_ASSISTANT, AUDIO_SOURCE_DEFAULT, 0, ""},
+ {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+ AUDIO_SOURCE_DEFAULT, 0, ""},
+ {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT, 0, ""}
+ },
+ },
+ {"system", AUDIO_STREAM_SYSTEM,
+ {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_ASSISTANCE_SONIFICATION,
+ AUDIO_SOURCE_DEFAULT, 0, ""}}
+ }
+ },
+ },
+ {"STRATEGY_DTMF",
+ {
+ {"", AUDIO_STREAM_DTMF,
+ {
+ {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING,
+ AUDIO_SOURCE_DEFAULT, 0, ""}
+ }
+ }
+ },
+ },
+ {"STRATEGY_TRANSMITTED_THROUGH_SPEAKER",
+ {
+ {"", AUDIO_STREAM_TTS,
+ {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT,
+ AUDIO_FLAG_BEACON, ""}}
+ }
+ },
+ },
+ {"STRATEGY_REROUTING",
+ {
+ {"", AUDIO_STREAM_REROUTING,
+ {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT, 0, ""}}
+ }
+ },
+ },
+ {"STRATEGY_PATCH",
+ {
+ {"", AUDIO_STREAM_PATCH,
+ {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT, 0, ""}}
+ }
+ },
+ }
+};
+
+const engineConfig::Config gDefaultEngineConfig = {
+ 1.0,
+ gOrderedStrategies
+};
+} // namespace android
diff --git a/services/audiopolicy/engine/common/src/ProductStrategy.cpp b/services/audiopolicy/engine/common/src/ProductStrategy.cpp
new file mode 100644
index 0000000..a3edb39
--- /dev/null
+++ b/services/audiopolicy/engine/common/src/ProductStrategy.cpp
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2018 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/ProductStrategy"
+//#define LOG_NDEBUG 0
+
+#include "ProductStrategy.h"
+
+#include <media/TypeConverter.h>
+#include <utils/String8.h>
+#include <cstdint>
+#include <string>
+
+#include <log/log.h>
+
+
+namespace android {
+
+ProductStrategy::ProductStrategy(const std::string &name) :
+ mName(name),
+ mId(static_cast<product_strategy_t>(HandleGenerator<uint32_t>::getNextHandle()))
+{
+}
+
+void ProductStrategy::addAttributes(const AudioAttributes &audioAttributes)
+{
+ mAttributesVector.push_back(audioAttributes);
+}
+
+AttributesVector ProductStrategy::getAudioAttributes() const
+{
+ AttributesVector attrVector;
+ for (const auto &attrGroup : mAttributesVector) {
+ attrVector.push_back(attrGroup.mAttributes);
+ }
+ if (not attrVector.empty()) {
+ return attrVector;
+ }
+ return { AUDIO_ATTRIBUTES_INITIALIZER };
+}
+
+// @todo: all flags required to match?
+// all tags required to match?
+/* static */
+bool ProductStrategy::attributesMatches(const audio_attributes_t refAttributes,
+ const audio_attributes_t clientAttritubes)
+{
+ if (refAttributes == defaultAttr) {
+ // The default product strategy is the strategy that holds default attributes by convention.
+ // All attributes that fail to match will follow the default strategy for routing.
+ // Choosing the default must be done as a fallback, the attributes match shall not
+ // selects the default.
+ return false;
+ }
+ return ((refAttributes.usage == AUDIO_USAGE_UNKNOWN) ||
+ (clientAttritubes.usage == refAttributes.usage)) &&
+ ((refAttributes.content_type == AUDIO_CONTENT_TYPE_UNKNOWN) ||
+ (clientAttritubes.content_type == refAttributes.content_type)) &&
+ ((refAttributes.flags == AUDIO_OUTPUT_FLAG_NONE) ||
+ (clientAttritubes.flags != AUDIO_OUTPUT_FLAG_NONE &&
+ (clientAttritubes.flags & refAttributes.flags) == clientAttritubes.flags)) &&
+ ((strlen(refAttributes.tags) == 0) ||
+ (std::strcmp(clientAttritubes.tags, refAttributes.tags) == 0));
+}
+
+bool ProductStrategy::matches(const audio_attributes_t attr) const
+{
+ return std::find_if(begin(mAttributesVector), end(mAttributesVector),
+ [&attr](const auto &supportedAttr) {
+ return attributesMatches(supportedAttr.mAttributes, attr); }) != end(mAttributesVector);
+}
+
+audio_stream_type_t ProductStrategy::getStreamTypeForAttributes(const audio_attributes_t &attr) const
+{
+ const auto iter = std::find_if(begin(mAttributesVector), end(mAttributesVector),
+ [&attr](const auto &supportedAttr) {
+ return attributesMatches(supportedAttr.mAttributes, attr); });
+ return iter != end(mAttributesVector) ? iter->mStream : AUDIO_STREAM_DEFAULT;
+}
+
+audio_attributes_t ProductStrategy::getAttributesForStreamType(audio_stream_type_t streamType) const
+{
+ const auto iter = std::find_if(begin(mAttributesVector), end(mAttributesVector),
+ [&streamType](const auto &supportedAttr) {
+ return supportedAttr.mStream == streamType; });
+ return iter != end(mAttributesVector) ? iter->mAttributes : AUDIO_ATTRIBUTES_INITIALIZER;
+}
+
+bool ProductStrategy::isDefault() const
+{
+ return std::find_if(begin(mAttributesVector), end(mAttributesVector), [](const auto &attr) {
+ return attr.mAttributes == defaultAttr; }) != end(mAttributesVector);
+}
+
+StreamTypeVector ProductStrategy::getSupportedStreams() const
+{
+ StreamTypeVector streams;
+ for (const auto &supportedAttr : mAttributesVector) {
+ if (std::find(begin(streams), end(streams), supportedAttr.mStream) == end(streams) &&
+ supportedAttr.mStream != AUDIO_STREAM_DEFAULT) {
+ streams.push_back(supportedAttr.mStream);
+ }
+ }
+ return streams;
+}
+
+bool ProductStrategy::supportStreamType(const audio_stream_type_t &streamType) const
+{
+ return std::find_if(begin(mAttributesVector), end(mAttributesVector),
+ [&streamType](const auto &supportedAttr) {
+ return supportedAttr.mStream == streamType; }) != end(mAttributesVector);
+}
+
+void ProductStrategy::dump(String8 *dst, int spaces) const
+{
+ dst->appendFormat("\n%*s-%s (id: %d)\n", spaces, "", mName.c_str(), mId);
+ std::string deviceLiteral;
+ if (!OutputDeviceConverter::toString(mApplicableDevices, deviceLiteral)) {
+ ALOGE("%s: failed to convert device %d", __FUNCTION__, mApplicableDevices);
+ }
+ dst->appendFormat("%*sSelected Device: {type:%s, @:%s}\n", spaces + 2, "",
+ deviceLiteral.c_str(), mDeviceAddress.c_str());
+
+ for (const auto &attr : mAttributesVector) {
+ dst->appendFormat("%*sGroup: %d stream: %s\n", spaces + 3, "", attr.mGroupId,
+ android::toString(attr.mStream).c_str());
+ dst->appendFormat("%*s Attributes: ", spaces + 3, "");
+ std::string attStr =
+ attr.mAttributes == defaultAttr ? "{ Any }" : android::toString(attr.mAttributes);
+ dst->appendFormat("%s\n", attStr.c_str());
+ }
+}
+
+product_strategy_t ProductStrategyMap::getProductStrategyForAttributes(
+ const audio_attributes_t &attr) const
+{
+ for (const auto &iter : *this) {
+ if (iter.second->matches(attr)) {
+ return iter.second->getId();
+ }
+ }
+ ALOGV("%s: No matching product strategy for attributes %s, return default", __FUNCTION__,
+ toString(attr).c_str());
+ return getDefault();
+}
+
+audio_attributes_t ProductStrategyMap::getAttributesForStreamType(audio_stream_type_t stream) const
+{
+ for (const auto &iter : *this) {
+ const auto strategy = iter.second;
+ if (strategy->supportStreamType(stream)) {
+ return strategy->getAttributesForStreamType(stream);
+ }
+ }
+ ALOGV("%s: No product strategy for stream %s, using default", __FUNCTION__,
+ toString(stream).c_str());
+ return {};
+}
+
+audio_stream_type_t ProductStrategyMap::getStreamTypeForAttributes(
+ const audio_attributes_t &attr) const
+{
+ for (const auto &iter : *this) {
+ audio_stream_type_t stream = iter.second->getStreamTypeForAttributes(attr);
+ if (stream != AUDIO_STREAM_DEFAULT) {
+ return stream;
+ }
+ }
+ ALOGV("%s: No product strategy for attributes %s, using default (aka MUSIC)", __FUNCTION__,
+ toString(attr).c_str());
+ return AUDIO_STREAM_MUSIC;
+}
+
+product_strategy_t ProductStrategyMap::getDefault() const
+{
+ for (const auto &iter : *this) {
+ if (iter.second->isDefault()) {
+ ALOGV("%s: using default %s", __FUNCTION__, iter.second->getName().c_str());
+ return iter.second->getId();
+ }
+ }
+ ALOGE("%s: No default product strategy defined", __FUNCTION__);
+ return PRODUCT_STRATEGY_NONE;
+}
+
+audio_attributes_t ProductStrategyMap::getAttributesForProductStrategy(
+ product_strategy_t strategy) const
+{
+ if (find(strategy) == end()) {
+ ALOGE("Invalid %d strategy requested", strategy);
+ return AUDIO_ATTRIBUTES_INITIALIZER;
+ }
+ return at(strategy)->getAudioAttributes()[0];
+}
+
+product_strategy_t ProductStrategyMap::getProductStrategyForStream(audio_stream_type_t stream) const
+{
+ for (const auto &iter : *this) {
+ if (iter.second->supportStreamType(stream)) {
+ return iter.second->getId();
+ }
+ }
+ ALOGV("%s: No product strategy for stream %d, using default", __FUNCTION__, stream);
+ return getDefault();
+}
+
+
+audio_devices_t ProductStrategyMap::getDeviceTypesForProductStrategy(
+ product_strategy_t strategy) const
+{
+ if (find(strategy) == end()) {
+ ALOGE("Invalid %d strategy requested, returning device for default strategy", strategy);
+ product_strategy_t defaultStrategy = getDefault();
+ if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
+ return AUDIO_DEVICE_NONE;
+ }
+ return at(getDefault())->getDeviceTypes();
+ }
+ return at(strategy)->getDeviceTypes();
+}
+
+std::string ProductStrategyMap::getDeviceAddressForProductStrategy(product_strategy_t psId) const
+{
+ if (find(psId) == end()) {
+ ALOGE("Invalid %d strategy requested, returning device for default strategy", psId);
+ product_strategy_t defaultStrategy = getDefault();
+ if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
+ return {};
+ }
+ return at(getDefault())->getDeviceAddress();
+ }
+ return at(psId)->getDeviceAddress();
+}
+
+void ProductStrategyMap::dump(String8 *dst, int spaces) const
+{
+ dst->appendFormat("%*sProduct Strategies dump:", spaces, "");
+ for (const auto &iter : *this) {
+ iter.second->dump(dst, spaces + 2);
+ }
+}
+
+}
+
diff --git a/services/audiopolicy/engine/config/Android.mk b/services/audiopolicy/engine/config/Android.mk
new file mode 100644
index 0000000..dbcd1bf
--- /dev/null
+++ b/services/audiopolicy/engine/config/Android.mk
@@ -0,0 +1,41 @@
+LOCAL_PATH := $(call my-dir)
+
+##################################################################
+# Component build
+##################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_EXPORT_C_INCLUDE_DIRS) \
+ external/libxml2/include \
+ external/icu/icu4c/source/common
+
+LOCAL_SRC_FILES := \
+ src/EngineConfig.cpp
+
+LOCAL_CFLAGS += -Wall -Werror -Wextra
+
+LOCAL_SHARED_LIBRARIES := \
+ libparameter \
+ libmedia_helper \
+ libandroidicu \
+ libxml2 \
+ libutils \
+ liblog
+
+LOCAL_STATIC_LIBRARIES := \
+ libaudiopolicycomponents
+
+LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
+
+LOCAL_MODULE := libaudiopolicyengineconfig
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_HEADER_LIBRARIES := \
+ libaudio_system_headers \
+ libaudiopolicycommon
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/services/audiopolicy/engine/config/include/EngineConfig.h b/services/audiopolicy/engine/config/include/EngineConfig.h
new file mode 100644
index 0000000..64b9526
--- /dev/null
+++ b/services/audiopolicy/engine/config/include/EngineConfig.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include <system/audio.h>
+
+#include <string>
+#include <vector>
+#include <utils/Errors.h>
+
+struct _xmlNode;
+struct _xmlDoc;
+
+namespace android {
+namespace engineConfig {
+
+/** Default path of audio policy usages configuration file. */
+constexpr char DEFAULT_PATH[] = "/vendor/etc/audio_policy_engine_configuration.xml";
+
+/** Directories where the effect libraries will be search for. */
+constexpr const char* POLICY_USAGE_LIBRARY_PATH[] = {"/odm/etc/", "/vendor/etc/", "/system/etc/"};
+
+using AttributesVector = std::vector<audio_attributes_t>;
+using StreamVector = std::vector<audio_stream_type_t>;
+
+struct AttributesGroup {
+ std::string name;
+ audio_stream_type_t stream;
+ AttributesVector attributesVect;
+};
+
+using AttributesGroups = std::vector<AttributesGroup>;
+
+struct ProductStrategy {
+ std::string name;
+ AttributesGroups attributesGroups;
+};
+
+using ProductStrategies = std::vector<ProductStrategy>;
+
+struct Config {
+ float version;
+ ProductStrategies productStrategies;
+};
+
+/** Result of `parse(const char*)` */
+struct ParsingResult {
+ /** Parsed config, nullptr if the xml lib could not load the file */
+ std::unique_ptr<Config> parsedConfig;
+ size_t nbSkippedElement; //< Number of skipped invalid product strategies
+};
+
+/** Parses the provided audio policy usage configuration.
+ * @return audio policy usage @see Config
+ */
+ParsingResult parse(const char* path = DEFAULT_PATH);
+
+} // namespace engineConfig
+} // namespace android
diff --git a/services/audiopolicy/engine/config/src/EngineConfig.cpp b/services/audiopolicy/engine/config/src/EngineConfig.cpp
new file mode 100644
index 0000000..26dde66
--- /dev/null
+++ b/services/audiopolicy/engine/config/src/EngineConfig.cpp
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2018 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/Config"
+//#define LOG_NDEBUG 0
+
+#include "EngineConfig.h"
+#include <policy.h>
+#include <media/TypeConverter.h>
+#include <media/convert.h>
+#include <utils/Log.h>
+#include <libxml/parser.h>
+#include <libxml/xinclude.h>
+#include <string>
+#include <vector>
+#include <sstream>
+#include <istream>
+
+#include <cstdint>
+#include <string>
+
+
+namespace android {
+
+using utilities::convertTo;
+
+namespace engineConfig {
+
+static constexpr const char *gVersionAttribute = "version";
+static const char *const gReferenceElementName = "reference";
+static const char *const gReferenceAttributeName = "name";
+
+template<typename E, typename C>
+struct BaseSerializerTraits {
+ typedef E Element;
+ typedef C Collection;
+ typedef void* PtrSerializingCtx;
+};
+
+struct AttributesGroupTraits : public BaseSerializerTraits<AttributesGroup, AttributesGroups> {
+ static constexpr const char *tag = "AttributesGroup";
+ static constexpr const char *collectionTag = "AttributesGroups";
+
+ struct Attributes {
+ static constexpr const char *name = "name";
+ static constexpr const char *streamType = "streamType";
+ };
+ static android::status_t deserialize(_xmlDoc *doc, const _xmlNode *root, Collection &ps);
+};
+
+struct ProductStrategyTraits : public BaseSerializerTraits<ProductStrategy, ProductStrategies> {
+ static constexpr const char *tag = "ProductStrategy";
+ static constexpr const char *collectionTag = "ProductStrategies";
+
+ struct Attributes {
+ static constexpr const char *name = "name";
+ };
+ static android::status_t deserialize(_xmlDoc *doc, const _xmlNode *root, Collection &ps);
+};
+
+using xmlCharUnique = std::unique_ptr<xmlChar, decltype(xmlFree)>;
+
+std::string getXmlAttribute(const xmlNode *cur, const char *attribute)
+{
+ xmlCharUnique charPtr(xmlGetProp(cur, reinterpret_cast<const xmlChar *>(attribute)), xmlFree);
+ if (charPtr == NULL) {
+ return "";
+ }
+ std::string value(reinterpret_cast<const char*>(charPtr.get()));
+ return value;
+}
+
+static void getReference(const _xmlNode *root, const _xmlNode *&refNode, const std::string &refName,
+ const char *collectionTag)
+{
+ for (root = root->xmlChildrenNode; root != NULL; root = root->next) {
+ if (!xmlStrcmp(root->name, (const xmlChar *)collectionTag)) {
+ for (xmlNode *cur = root->xmlChildrenNode; cur != NULL; cur = cur->next) {
+ if ((!xmlStrcmp(cur->name, (const xmlChar *)gReferenceElementName))) {
+ std::string name = getXmlAttribute(cur, gReferenceAttributeName);
+ if (refName == name) {
+ refNode = cur;
+ return;
+ }
+ }
+ }
+ }
+ }
+ return;
+}
+
+template <class Trait>
+static status_t deserializeCollection(_xmlDoc *doc, const _xmlNode *cur,
+ typename Trait::Collection &collection,
+ size_t &nbSkippedElement)
+{
+ for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
+ if (xmlStrcmp(cur->name, (const xmlChar *)Trait::collectionTag) &&
+ xmlStrcmp(cur->name, (const xmlChar *)Trait::tag)) {
+ continue;
+ }
+ const xmlNode *child = cur;
+ if (!xmlStrcmp(child->name, (const xmlChar *)Trait::collectionTag)) {
+ child = child->xmlChildrenNode;
+ }
+ for (; child != NULL; child = child->next) {
+ if (!xmlStrcmp(child->name, (const xmlChar *)Trait::tag)) {
+ status_t status = Trait::deserialize(doc, child, collection);
+ if (status != NO_ERROR) {
+ nbSkippedElement += 1;
+ }
+ }
+ }
+ if (!xmlStrcmp(cur->name, (const xmlChar *)Trait::tag)) {
+ return NO_ERROR;
+ }
+ }
+ return NO_ERROR;
+}
+
+static constexpr const char *attributesAttributeRef = "attributesRef"; /**< for factorization. */
+
+static status_t parseAttributes(const _xmlNode *cur, audio_attributes_t &attributes)
+{
+ for (; cur != NULL; cur = cur->next) {
+ if (!xmlStrcmp(cur->name, (const xmlChar *)("ContentType"))) {
+ std::string contentTypeXml = getXmlAttribute(cur, "value");
+ audio_content_type_t contentType;
+ if (not AudioContentTypeConverter::fromString(contentTypeXml.c_str(), contentType)) {
+ ALOGE("Invalid content type %s", contentTypeXml.c_str());
+ return BAD_VALUE;
+ }
+ attributes.content_type = contentType;
+ ALOGV("%s content type %s", __FUNCTION__, contentTypeXml.c_str());
+ }
+ if (!xmlStrcmp(cur->name, (const xmlChar *)("Usage"))) {
+ std::string usageXml = getXmlAttribute(cur, "value");
+ audio_usage_t usage;
+ if (not UsageTypeConverter::fromString(usageXml.c_str(), usage)) {
+ ALOGE("Invalid usage %s", usageXml.c_str());
+ return BAD_VALUE;
+ }
+ attributes.usage = usage;
+ ALOGV("%s usage %s", __FUNCTION__, usageXml.c_str());
+ }
+ if (!xmlStrcmp(cur->name, (const xmlChar *)("Flags"))) {
+ std::string flags = getXmlAttribute(cur, "value");
+
+ ALOGV("%s flags %s", __FUNCTION__, flags.c_str());
+ attributes.flags = AudioFlagConverter::maskFromString(flags, " ");
+ }
+ if (!xmlStrcmp(cur->name, (const xmlChar *)("Bundle"))) {
+ std::string bundleKey = getXmlAttribute(cur, "key");
+ std::string bundleValue = getXmlAttribute(cur, "value");
+
+ ALOGV("%s Bundle %s %s", __FUNCTION__, bundleKey.c_str(), bundleValue.c_str());
+
+ std::string tags(bundleKey + "=" + bundleValue);
+ std::strncpy(attributes.tags, tags.c_str(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
+ }
+ }
+ return NO_ERROR;
+}
+
+static status_t deserializeAttributes(_xmlDoc *doc, const _xmlNode *cur,
+ audio_attributes_t &attributes) {
+ // Retrieve content type, usage, flags, and bundle from xml
+ for (; cur != NULL; cur = cur->next) {
+ if (not xmlStrcmp(cur->name, (const xmlChar *)("Attributes"))) {
+ const xmlNode *attrNode = cur;
+ std::string attrRef = getXmlAttribute(cur, attributesAttributeRef);
+ if (!attrRef.empty()) {
+ getReference(xmlDocGetRootElement(doc), attrNode, attrRef, attributesAttributeRef);
+ if (attrNode == NULL) {
+ ALOGE("%s: No reference found for %s", __FUNCTION__, attrRef.c_str());
+ return BAD_VALUE;
+ }
+ return deserializeAttributes(doc, attrNode->xmlChildrenNode, attributes);
+ }
+ return parseAttributes(attrNode->xmlChildrenNode, attributes);
+ }
+ if (not xmlStrcmp(cur->name, (const xmlChar *)("ContentType")) ||
+ not xmlStrcmp(cur->name, (const xmlChar *)("Usage")) ||
+ not xmlStrcmp(cur->name, (const xmlChar *)("Flags")) ||
+ not xmlStrcmp(cur->name, (const xmlChar *)("Bundle"))) {
+ return parseAttributes(cur, attributes);
+ }
+ }
+ return BAD_VALUE;
+}
+
+static status_t deserializeAttributesCollection(_xmlDoc *doc, const _xmlNode *cur,
+ AttributesVector &collection)
+{
+ status_t ret = BAD_VALUE;
+ // Either we do provide only one attributes or a collection of supported attributes
+ for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
+ if (not xmlStrcmp(cur->name, (const xmlChar *)("Attributes")) ||
+ not xmlStrcmp(cur->name, (const xmlChar *)("ContentType")) ||
+ not xmlStrcmp(cur->name, (const xmlChar *)("Usage")) ||
+ not xmlStrcmp(cur->name, (const xmlChar *)("Flags")) ||
+ not xmlStrcmp(cur->name, (const xmlChar *)("Bundle"))) {
+ audio_attributes_t attributes = AUDIO_ATTRIBUTES_INITIALIZER;
+ ret = deserializeAttributes(doc, cur, attributes);
+ if (ret == NO_ERROR) {
+ collection.push_back(attributes);
+ // We are done if the "Attributes" balise is omitted, only one Attributes is allowed
+ if (xmlStrcmp(cur->name, (const xmlChar *)("Attributes"))) {
+ return ret;
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+status_t AttributesGroupTraits::deserialize(_xmlDoc *doc, const _xmlNode *child,
+ Collection &attributesGroup)
+{
+ std::string name = getXmlAttribute(child, Attributes::name);
+ if (name.empty()) {
+ ALOGV("AttributesGroupTraits No attribute %s found", Attributes::name);
+ }
+ ALOGV("%s: %s = %s", __FUNCTION__, Attributes::name, name.c_str());
+
+ audio_stream_type_t streamType = AUDIO_STREAM_DEFAULT;
+ std::string streamTypeXml = getXmlAttribute(child, Attributes::streamType);
+ if (streamTypeXml.empty()) {
+ ALOGV("%s: No attribute %s found", __FUNCTION__, Attributes::streamType);
+ } else {
+ ALOGV("%s: %s = %s", __FUNCTION__, Attributes::streamType, streamTypeXml.c_str());
+ if (not StreamTypeConverter::fromString(streamTypeXml.c_str(), streamType)) {
+ ALOGE("Invalid stream type %s", streamTypeXml.c_str());
+ return BAD_VALUE;
+ }
+ }
+ AttributesVector attributesVect;
+ deserializeAttributesCollection(doc, child, attributesVect);
+
+ attributesGroup.push_back({name, streamType, attributesVect});
+ return NO_ERROR;
+}
+
+status_t ProductStrategyTraits::deserialize(_xmlDoc *doc, const _xmlNode *child,
+ Collection &strategies)
+{
+ std::string name = getXmlAttribute(child, Attributes::name);
+ if (name.empty()) {
+ ALOGE("ProductStrategyTraits No attribute %s found", Attributes::name);
+ return BAD_VALUE;
+ }
+ ALOGV("%s: %s = %s", __FUNCTION__, Attributes::name, name.c_str());
+
+ size_t skipped = 0;
+ AttributesGroups attrGroups;
+ deserializeCollection<AttributesGroupTraits>(doc, child, attrGroups, skipped);
+
+ strategies.push_back({name, attrGroups});
+ return NO_ERROR;
+}
+
+ParsingResult parse(const char* path) {
+ xmlDocPtr doc;
+ doc = xmlParseFile(path);
+ if (doc == NULL) {
+ ALOGE("%s: Could not parse document %s", __FUNCTION__, path);
+ return {nullptr, 0};
+ }
+ xmlNodePtr cur = xmlDocGetRootElement(doc);
+ if (cur == NULL) {
+ ALOGE("%s: Could not parse: empty document %s", __FUNCTION__, path);
+ xmlFreeDoc(doc);
+ return {nullptr, 0};
+ }
+ if (xmlXIncludeProcess(doc) < 0) {
+ ALOGE("%s: libxml failed to resolve XIncludes on document %s", __FUNCTION__, path);
+ return {nullptr, 0};
+ }
+ std::string version = getXmlAttribute(cur, gVersionAttribute);
+ if (version.empty()) {
+ ALOGE("%s: No version found", __func__);
+ return {nullptr, 0};
+ }
+ size_t nbSkippedElements = 0;
+ auto config = std::make_unique<Config>();
+ config->version = std::stof(version);
+ deserializeCollection<ProductStrategyTraits>(
+ doc, cur, config->productStrategies, nbSkippedElements);
+
+ return {std::move(config), nbSkippedElements};
+}
+
+} // namespace engineConfig
+} // namespace android
diff --git a/services/audiopolicy/engine/interface/Android.bp b/services/audiopolicy/engine/interface/Android.bp
new file mode 100644
index 0000000..2ea42b6
--- /dev/null
+++ b/services/audiopolicy/engine/interface/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2018 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.
+
+cc_library_headers {
+ name: "libaudiopolicyengine_interface_headers",
+ host_supported: true,
+ export_include_dirs: ["."],
+}
diff --git a/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h b/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h
index 04594f5..9f5fb0c2 100644
--- a/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h
+++ b/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h
@@ -18,6 +18,8 @@
#include <AudioPolicyManagerObserver.h>
#include <RoutingStrategy.h>
+#include <media/AudioCommonTypes.h>
+#include <policy.h>
#include <Volume.h>
#include <HwModule.h>
#include <DeviceDescriptor.h>
@@ -28,6 +30,10 @@
namespace android {
+using DeviceStrategyMap = std::map<product_strategy_t, DeviceVector>;
+using StrategyVector = std::vector<product_strategy_t>;
+
+
/**
* This interface is dedicated to the policy manager that a Policy Engine shall implement.
*/
@@ -55,6 +61,8 @@
* @param[in] inputSource to get the selected input device associated to
*
* @return selected input device for the given input source, may be none if error.
+ *
+ * @deprecated use getInputDeviceForAttributes
*/
virtual audio_devices_t getDeviceForInputSource(audio_source_t inputSource) const = 0;
@@ -64,6 +72,8 @@
* @param[in] stream type for which the selected ouput device is requested.
*
* @return selected ouput device for the given strategy, may be none if error.
+ *
+ * @deprecated use getOutputDeviceForAttributes
*/
virtual audio_devices_t getDeviceForStrategy(routing_strategy stategy) const = 0;
@@ -73,6 +83,9 @@
* @param[in] stream: for which the selected strategy followed by is requested.
*
* @return strategy to be followed.
+ *
+ * @deprecated use getOrderedStreams() / getLinkedStreams() to apply operation on stream
+ * following same former routing_strategy
*/
virtual routing_strategy getStrategyForStream(audio_stream_type_t stream) = 0;
@@ -82,6 +95,8 @@
* @param[in] usage to get the selected strategy followed by.
*
* @return strategy to be followed.
+ *
+ * @deprecated use getProductStrategyForAttributes
*/
virtual routing_strategy getStrategyForUsage(audio_usage_t usage) = 0;
@@ -133,6 +148,130 @@
virtual status_t setDeviceConnectionState(const android::sp<android::DeviceDescriptor> devDesc,
audio_policy_dev_state_t state) = 0;
+ /**
+ * Get the strategy selected for a given audio attributes.
+ *
+ * @param[in] audio attributes to get the selected @product_strategy_t followed by.
+ *
+ * @return @product_strategy_t to be followed.
+ */
+ virtual product_strategy_t getProductStrategyForAttributes(
+ const audio_attributes_t &attr) const = 0;
+
+ /**
+ * @brief getOutputDevicesForAttributes retrieves the devices to be used for given
+ * audio attributes.
+ * @param attributes of the output requesting Device(s) selection
+ * @param preferedDevice valid reference if a prefered device is requested, nullptr otherwise.
+ * @param fromCache if true, the device is returned from internal cache,
+ * otherwise it is determined by current state (device connected,phone state,
+ * force use, a2dp output...)
+ * @return vector of selected device descriptors.
+ * Appropriate device for streams handled by the specified audio attributes according
+ * to current phone state, forced states, connected devices...
+ * if fromCache is true, the device is returned from internal cache,
+ * otherwise it is determined by current state (device connected,phone state, force use,
+ * a2dp output...)
+ * This allows to:
+ * 1 speed up process when the state is stable (when starting or stopping an output)
+ * 2 access to either current device selection (fromCache == true) or
+ * "future" device selection (fromCache == false) when called from a context
+ * where conditions are changing (setDeviceConnectionState(), setPhoneState()...) AND
+ * before manager updates its outputs.
+ */
+ virtual DeviceVector getOutputDevicesForAttributes(
+ const audio_attributes_t &attributes,
+ const sp<DeviceDescriptor> &preferedDevice = nullptr,
+ bool fromCache = false) const = 0;
+
+ /**
+ * @brief getOutputDevicesForStream Legacy function retrieving devices from a stream type.
+ * @param stream type of the output requesting Device(s) selection
+ * @param fromCache if true, the device is returned from internal cache,
+ * otherwise it is determined by current state (device connected,phone state,
+ * force use, a2dp output...)
+ * @return appropriate device for streams handled by the specified audio attributes according
+ * to current phone state, forced states, connected devices...
+ * if fromCache is true, the device is returned from internal cache,
+ * otherwise it is determined by current state (device connected,phone state, force use,
+ * a2dp output...)
+ * This allows to:
+ * 1 speed up process when the state is stable (when starting or stopping an output)
+ * 2 access to either current device selection (fromCache == true) or
+ * "future" device selection (fromCache == false) when called from a context
+ * where conditions are changing (setDeviceConnectionState(), setPhoneState()...) AND
+ * before manager updates its outputs.
+ */
+ virtual DeviceVector getOutputDevicesForStream(audio_stream_type_t stream,
+ bool fromCache = false) const = 0;
+
+ /**
+ * Get the input device selected for given audio attributes.
+ *
+ * @param[in] attr audio attributes to consider
+ * @param[out] mix to be used if a mix has been installed for the given audio attributes.
+ * @return selected input device for the audio attributes, may be null if error.
+ */
+ virtual sp<DeviceDescriptor> getInputDeviceForAttributes(
+ const audio_attributes_t &attr, AudioMix **mix = nullptr) const = 0;
+
+ /**
+ * Get the legacy stream type for a given audio attributes.
+ *
+ * @param[in] audio attributes to get the associated audio_stream_type_t.
+ *
+ * @return audio_stream_type_t associated to the attributes.
+ */
+ virtual audio_stream_type_t getStreamTypeForAttributes(
+ const audio_attributes_t &attr) const = 0;
+
+ /**
+ * @brief getAttributesForStream get the audio attributes from legacy stream type
+ * @param stream to consider
+ * @return audio attributes matching the legacy stream type
+ */
+ virtual audio_attributes_t getAttributesForStreamType(audio_stream_type_t stream) const = 0;
+
+ /**
+ * @brief getStreamTypesForProductStrategy retrieves the list of legacy stream type following
+ * the given product strategy
+ * @param ps product strategy to consider
+ * @return associated legacy Stream Types vector of the given product strategy
+ */
+ virtual StreamTypeVector getStreamTypesForProductStrategy(product_strategy_t ps) const = 0;
+
+ /**
+ * @brief getAllAttributesForProductStrategy retrieves all the attributes following the given
+ * product strategy. Any attributes that "matches" with this one will follow the product
+ * strategy.
+ * "matching" means the usage shall match if reference attributes has a defined usage, AND
+ * content type shall match if reference attributes has a defined content type AND
+ * flags shall match if reference attributes has defined flags AND
+ * tags shall match if reference attributes has defined tags.
+ * @param ps product strategy to consider
+ * @return vector of product strategy ids, empty if unknown strategy.
+ */
+ virtual AttributesVector getAllAttributesForProductStrategy(product_strategy_t ps) const = 0;
+
+ /**
+ * @brief getOrderedAudioProductStrategies
+ * @return priority ordered product strategies to help the AudioPolicyManager evaluating the
+ * device selection per output according to the prioritized strategies.
+ */
+ virtual StrategyVector getOrderedProductStrategies() const = 0;
+
+ /**
+ * @brief updateDeviceSelectionCache. Device selection for AudioAttribute / Streams is cached
+ * in the engine in order to speed up process when the audio system is stable.
+ * When a device is connected, the android mode is changed, engine is notified and can update
+ * the cache.
+ * When starting / stopping an output with a stream that can affect notification, the engine
+ * needs to update the cache upon this function call.
+ */
+ virtual void updateDeviceSelectionCache() = 0;
+
+ virtual void dump(String8 *dst) const = 0;
+
protected:
virtual ~AudioPolicyManagerInterface() {}
};
diff --git a/services/audiopolicy/engineconfigurable/Android.mk b/services/audiopolicy/engineconfigurable/Android.mk
index c2105e9..df813cb 100644
--- a/services/audiopolicy/engineconfigurable/Android.mk
+++ b/services/audiopolicy/engineconfigurable/Android.mk
@@ -14,11 +14,12 @@
src/Strategy.cpp \
src/Usage.cpp \
src/InputSource.cpp \
+ ../engine/common/src/ProductStrategy.cpp \
+ ../engine/common/src/EngineBase.cpp
audio_policy_engine_includes_common := \
frameworks/av/services/audiopolicy/engineconfigurable/include \
- frameworks/av/services/audiopolicy/engineconfigurable/interface \
- frameworks/av/services/audiopolicy/engine/interface
+ frameworks/av/services/audiopolicy/engineconfigurable/interface
LOCAL_CFLAGS += \
-Wall \
@@ -32,8 +33,12 @@
$(audio_policy_engine_includes_common) \
$(TARGET_OUT_HEADERS)/hw \
$(call include-path-for, frameworks-av) \
- $(call include-path-for, audio-utils) \
- frameworks/av/services/audiopolicy/common/include
+ $(call include-path-for, audio-utils)
+
+LOCAL_HEADER_LIBRARIES := \
+ libaudiopolicycommon \
+ libaudiopolicyengine_common_headers \
+ libaudiopolicyengine_interface_headers
LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
@@ -45,8 +50,8 @@
libaudiopolicycomponents
LOCAL_SHARED_LIBRARIES := \
+ libaudiopolicyengineconfig \
liblog \
- libcutils \
libutils \
liblog \
libaudioutils \
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk
index db1f038..a37db1e 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk
@@ -21,7 +21,6 @@
-fvisibility=hidden
LOCAL_C_INCLUDES := \
- frameworks/av/services/audiopolicy/common/include \
frameworks/av/services/audiopolicy/engineconfigurable/include \
frameworks/av/services/audiopolicy/engineconfigurable/interface \
@@ -31,6 +30,9 @@
libmedia_helper \
liblog \
+LOCAL_HEADER_LIBRARIES := \
+ libaudiopolicycommon
+
LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
LOCAL_STATIC_LIBRARIES := libpfw_utility
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
diff --git a/services/audiopolicy/engineconfigurable/tools/provision_criterion_types_from_android_headers.mk b/services/audiopolicy/engineconfigurable/tools/provision_criterion_types_from_android_headers.mk
index 4814376..eebdfd6 100644
--- a/services/audiopolicy/engineconfigurable/tools/provision_criterion_types_from_android_headers.mk
+++ b/services/audiopolicy/engineconfigurable/tools/provision_criterion_types_from_android_headers.mk
@@ -8,7 +8,6 @@
$(LOCAL_BUILT_MODULE): MY_AUDIO_POLICY_CONFIGURATION_FILE := $(AUDIO_POLICY_CONFIGURATION_FILE)
$(LOCAL_BUILT_MODULE): MY_CRITERION_TOOL := $(HOST_OUT)/bin/buildPolicyCriterionTypes.py
$(LOCAL_BUILT_MODULE): $(LOCAL_REQUIRED_MODULES) $(LOCAL_ADDITIONAL_DEPENDENCIES) \
- buildPolicyCriterionTypes.py \
$(CRITERION_TYPES_FILE) \
$(ANDROID_AUDIO_BASE_HEADER_FILE)
diff --git a/services/audiopolicy/engineconfigurable/wrapper/Android.mk b/services/audiopolicy/engineconfigurable/wrapper/Android.mk
index d19a364..b71a53c 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/Android.mk
+++ b/services/audiopolicy/engineconfigurable/wrapper/Android.mk
@@ -14,6 +14,7 @@
frameworks/av/services/audiopolicy/engineconfigurable/include \
frameworks/av/services/audiopolicy/engineconfigurable/interface \
frameworks/av/services/audiopolicy/common/include \
+ frameworks/av/services/audiopolicy/utilities/convert \
external/libxml2/include \
external/icu/icu4c/source/common
@@ -27,6 +28,9 @@
libicuuc \
libxml2
+LOCAL_HEADER_LIBRARIES := \
+ libaudiopolicycommon
+
LOCAL_STATIC_LIBRARIES := \
libaudiopolicycomponents
diff --git a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
index 09faa4c..a3f341f 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
+++ b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
@@ -289,7 +289,7 @@
std::string criterionName = audio_is_output_device(devDesc->type()) ?
gOutputDeviceAddressCriterionName : gInputDeviceAddressCriterionName;
- ALOGV("%s: device with address %s %s", __FUNCTION__, devDesc->mAddress.string(),
+ ALOGV("%s: device with address %s %s", __FUNCTION__, devDesc->address().string(),
state != AUDIO_POLICY_DEVICE_STATE_AVAILABLE? "disconnected" : "connected");
ISelectionCriterionInterface *criterion =
getElement<ISelectionCriterionInterface>(criterionName, mPolicyCriteria);
diff --git a/services/audiopolicy/enginedefault/Android.mk b/services/audiopolicy/enginedefault/Android.mk
index 837d5bb..f9212f9 100644
--- a/services/audiopolicy/enginedefault/Android.mk
+++ b/services/audiopolicy/enginedefault/Android.mk
@@ -8,10 +8,11 @@
LOCAL_SRC_FILES := \
src/Engine.cpp \
src/EngineInstance.cpp \
+ ../engine/common/src/ProductStrategy.cpp \
+ ../engine/common/src/EngineBase.cpp
audio_policy_engine_includes_common := \
- $(LOCAL_PATH)/include \
- frameworks/av/services/audiopolicy/engine/interface
+ $(LOCAL_PATH)/include
LOCAL_CFLAGS += \
-Wall \
@@ -26,8 +27,7 @@
$(TARGET_OUT_HEADERS)/hw \
$(call include-path-for, frameworks-av) \
$(call include-path-for, audio-utils) \
- $(call include-path-for, bionic) \
- frameworks/av/services/audiopolicy/common/include
+ $(call include-path-for, bionic)
LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
@@ -37,12 +37,18 @@
LOCAL_HEADER_LIBRARIES := libbase_headers
LOCAL_STATIC_LIBRARIES := \
- libaudiopolicycomponents \
+ libaudiopolicycomponents
-LOCAL_SHARED_LIBRARIES += \
+LOCAL_SHARED_LIBRARIES := \
liblog \
libcutils \
libutils \
- libmedia_helper
+ libmedia_helper \
+ libaudiopolicyengineconfig
+
+LOCAL_HEADER_LIBRARIES := \
+ libaudiopolicycommon \
+ libaudiopolicyengine_common_headers \
+ libaudiopolicyengine_interface_headers
include $(BUILD_SHARED_LIBRARY)
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index cc5a025..69f0698 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -38,31 +38,33 @@
namespace audio_policy
{
+struct legacy_strategy_map { const char *name; legacy_strategy id; };
+static const std::vector<legacy_strategy_map> gLegacyStrategy = {
+ { "STRATEGY_NONE", STRATEGY_NONE },
+ { "STRATEGY_MEDIA", STRATEGY_MEDIA },
+ { "STRATEGY_PHONE", STRATEGY_PHONE },
+ { "STRATEGY_SONIFICATION", STRATEGY_SONIFICATION },
+ { "STRATEGY_SONIFICATION_RESPECTFUL", STRATEGY_SONIFICATION_RESPECTFUL },
+ { "STRATEGY_DTMF", STRATEGY_DTMF },
+ { "STRATEGY_ENFORCED_AUDIBLE", STRATEGY_ENFORCED_AUDIBLE },
+ { "STRATEGY_TRANSMITTED_THROUGH_SPEAKER", STRATEGY_TRANSMITTED_THROUGH_SPEAKER },
+ { "STRATEGY_ACCESSIBILITY", STRATEGY_ACCESSIBILITY },
+ { "STRATEGY_REROUTING", STRATEGY_REROUTING },
+ { "STRATEGY_PATCH", STRATEGY_REROUTING }, // boiler to manage stream patch volume
+};
+
Engine::Engine()
- : mManagerInterface(this),
- mPhoneState(AUDIO_MODE_NORMAL),
- mApmObserver(NULL)
{
- for (int i = 0; i < AUDIO_POLICY_FORCE_USE_CNT; i++) {
- mForceUse[i] = AUDIO_POLICY_FORCE_NONE;
+ auto result = EngineBase::loadAudioPolicyEngineConfig();
+ ALOGE_IF(result.nbSkippedElement != 0,
+ "Policy Engine configuration is partially invalid, skipped %zu elements",
+ result.nbSkippedElement);
+
+ for (const auto &strategy : gLegacyStrategy) {
+ mLegacyStrategyMap[getProductStrategyByName(strategy.name)] = strategy.id;
}
}
-Engine::~Engine()
-{
-}
-
-void Engine::setObserver(AudioPolicyManagerObserver *observer)
-{
- ALOG_ASSERT(observer != NULL, "Invalid Audio Policy Manager observer");
- mApmObserver = observer;
-}
-
-status_t Engine::initCheck()
-{
- return (mApmObserver != NULL) ? NO_ERROR : NO_INIT;
-}
-
status_t Engine::setPhoneState(audio_mode_t state)
{
ALOGV("setPhoneState() state %d", state);
@@ -72,22 +74,22 @@
return BAD_VALUE;
}
- if (state == mPhoneState ) {
+ if (state == getPhoneState()) {
ALOGW("setPhoneState() setting same state %d", state);
return BAD_VALUE;
}
// store previous phone state for management of sonification strategy below
- int oldState = mPhoneState;
- mPhoneState = state;
+ int oldState = getPhoneState();
+ EngineBase::setPhoneState(state);
if (!is_state_in_call(oldState) && is_state_in_call(state)) {
ALOGV(" Entering call in setPhoneState()");
- mApmObserver->getVolumeCurves().switchVolumeCurve(AUDIO_STREAM_VOICE_CALL,
+ getApmObserver()->getVolumeCurves().switchVolumeCurve(AUDIO_STREAM_VOICE_CALL,
AUDIO_STREAM_DTMF);
} else if (is_state_in_call(oldState) && !is_state_in_call(state)) {
ALOGV(" Exiting call in setPhoneState()");
- mApmObserver->getVolumeCurves().restoreOriginVolumeCurve(AUDIO_STREAM_DTMF);
+ getApmObserver()->getVolumeCurves().restoreOriginVolumeCurve(AUDIO_STREAM_DTMF);
}
return NO_ERROR;
}
@@ -101,7 +103,6 @@
ALOGW("setForceUse() invalid config %d for FOR_COMMUNICATION", config);
return BAD_VALUE;
}
- mForceUse[usage] = config;
break;
case AUDIO_POLICY_FORCE_FOR_MEDIA:
if (config != AUDIO_POLICY_FORCE_HEADPHONES && config != AUDIO_POLICY_FORCE_BT_A2DP &&
@@ -112,7 +113,6 @@
ALOGW("setForceUse() invalid config %d for FOR_MEDIA", config);
return BAD_VALUE;
}
- mForceUse[usage] = config;
break;
case AUDIO_POLICY_FORCE_FOR_RECORD:
if (config != AUDIO_POLICY_FORCE_BT_SCO && config != AUDIO_POLICY_FORCE_WIRED_ACCESSORY &&
@@ -120,7 +120,6 @@
ALOGW("setForceUse() invalid config %d for FOR_RECORD", config);
return BAD_VALUE;
}
- mForceUse[usage] = config;
break;
case AUDIO_POLICY_FORCE_FOR_DOCK:
if (config != AUDIO_POLICY_FORCE_NONE && config != AUDIO_POLICY_FORCE_BT_CAR_DOCK &&
@@ -130,21 +129,18 @@
config != AUDIO_POLICY_FORCE_DIGITAL_DOCK) {
ALOGW("setForceUse() invalid config %d for FOR_DOCK", config);
}
- mForceUse[usage] = config;
break;
case AUDIO_POLICY_FORCE_FOR_SYSTEM:
if (config != AUDIO_POLICY_FORCE_NONE &&
config != AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) {
ALOGW("setForceUse() invalid config %d for FOR_SYSTEM", config);
}
- mForceUse[usage] = config;
break;
case AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO:
if (config != AUDIO_POLICY_FORCE_NONE &&
config != AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED) {
ALOGW("setForceUse() invalid config %d for HDMI_SYSTEM_AUDIO", config);
}
- mForceUse[usage] = config;
break;
case AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND:
if (config != AUDIO_POLICY_FORCE_NONE &&
@@ -154,20 +150,18 @@
ALOGW("setForceUse() invalid config %d for ENCODED_SURROUND", config);
return BAD_VALUE;
}
- mForceUse[usage] = config;
break;
case AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING:
if (config != AUDIO_POLICY_FORCE_BT_SCO && config != AUDIO_POLICY_FORCE_NONE) {
ALOGW("setForceUse() invalid config %d for FOR_VIBRATE_RINGING", config);
return BAD_VALUE;
}
- mForceUse[usage] = config;
break;
default:
ALOGW("setForceUse() invalid usage %d", usage);
break; // TODO return BAD_VALUE?
}
- return NO_ERROR;
+ return EngineBase::setForceUse(usage, config);
}
routing_strategy Engine::getStrategyForStream(audio_stream_type_t stream)
@@ -176,14 +170,14 @@
switch (stream) {
case AUDIO_STREAM_VOICE_CALL:
case AUDIO_STREAM_BLUETOOTH_SCO:
- return STRATEGY_PHONE;
+ return android::STRATEGY_PHONE;
case AUDIO_STREAM_RING:
case AUDIO_STREAM_ALARM:
- return STRATEGY_SONIFICATION;
+ return android::STRATEGY_SONIFICATION;
case AUDIO_STREAM_NOTIFICATION:
- return STRATEGY_SONIFICATION_RESPECTFUL;
+ return android::STRATEGY_SONIFICATION_RESPECTFUL;
case AUDIO_STREAM_DTMF:
- return STRATEGY_DTMF;
+ return android::STRATEGY_DTMF;
default:
ALOGE("unknown stream type %d", stream);
FALLTHROUGH_INTENDED;
@@ -191,15 +185,15 @@
// NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs
// while key clicks are played produces a poor result
case AUDIO_STREAM_MUSIC:
- return STRATEGY_MEDIA;
+ return android::STRATEGY_MEDIA;
case AUDIO_STREAM_ENFORCED_AUDIBLE:
- return STRATEGY_ENFORCED_AUDIBLE;
+ return android::STRATEGY_ENFORCED_AUDIBLE;
case AUDIO_STREAM_TTS:
- return STRATEGY_TRANSMITTED_THROUGH_SPEAKER;
+ return android::STRATEGY_TRANSMITTED_THROUGH_SPEAKER;
case AUDIO_STREAM_ACCESSIBILITY:
- return STRATEGY_ACCESSIBILITY;
+ return android::STRATEGY_ACCESSIBILITY;
case AUDIO_STREAM_REROUTING:
- return STRATEGY_REROUTING;
+ return android::STRATEGY_REROUTING;
}
}
@@ -208,55 +202,54 @@
// usage to strategy mapping
switch (usage) {
case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
- return STRATEGY_ACCESSIBILITY;
+ return android::STRATEGY_ACCESSIBILITY;
case AUDIO_USAGE_MEDIA:
case AUDIO_USAGE_GAME:
case AUDIO_USAGE_ASSISTANT:
case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
case AUDIO_USAGE_ASSISTANCE_SONIFICATION:
- return STRATEGY_MEDIA;
+ return android::STRATEGY_MEDIA;
case AUDIO_USAGE_VOICE_COMMUNICATION:
- return STRATEGY_PHONE;
+ return android::STRATEGY_PHONE;
case AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING:
- return STRATEGY_DTMF;
+ return android::STRATEGY_DTMF;
case AUDIO_USAGE_ALARM:
case AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE:
- return STRATEGY_SONIFICATION;
+ return android::STRATEGY_SONIFICATION;
case AUDIO_USAGE_NOTIFICATION:
case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
case AUDIO_USAGE_NOTIFICATION_EVENT:
- return STRATEGY_SONIFICATION_RESPECTFUL;
+ return android::STRATEGY_SONIFICATION_RESPECTFUL;
case AUDIO_USAGE_UNKNOWN:
default:
- return STRATEGY_MEDIA;
+ return android::STRATEGY_MEDIA;
}
}
audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const
{
- DeviceVector availableOutputDevices = mApmObserver->getAvailableOutputDevices();
- DeviceVector availableInputDevices = mApmObserver->getAvailableInputDevices();
+ DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
+ DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices();
- const SwAudioOutputCollection &outputs = mApmObserver->getOutputs();
+ const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
- return getDeviceForStrategyInt(strategy, availableOutputDevices,
+ return getDeviceForStrategyInt(static_cast<legacy_strategy>(strategy), availableOutputDevices,
availableInputDevices, outputs, (uint32_t)AUDIO_DEVICE_NONE);
}
-
-audio_devices_t Engine::getDeviceForStrategyInt(routing_strategy strategy,
- DeviceVector availableOutputDevices,
- DeviceVector availableInputDevices,
- const SwAudioOutputCollection &outputs,
- uint32_t outputDeviceTypesToIgnore) const
+audio_devices_t Engine::getDeviceForStrategyInt(legacy_strategy strategy,
+ DeviceVector availableOutputDevices,
+ DeviceVector availableInputDevices,
+ const SwAudioOutputCollection &outputs,
+ uint32_t outputDeviceTypesToIgnore) const
{
uint32_t device = AUDIO_DEVICE_NONE;
uint32_t availableOutputDevicesType =
@@ -334,7 +327,7 @@
}
// for phone strategy, we first consider the forced use and then the available devices by
// order of priority
- switch (mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION]) {
+ switch (getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION)) {
case AUDIO_POLICY_FORCE_BT_SCO:
if (!isInCall() || strategy != STRATEGY_DTMF) {
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
@@ -352,7 +345,7 @@
if (device) break;
// when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
if (!isInCall() &&
- (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
+ (getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
outputs.isA2dpSupported()) {
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
if (device) break;
@@ -386,7 +379,7 @@
// when not in a phone call, phone strategy should route STREAM_VOICE_CALL to
// A2DP speaker when forcing to speaker output
if (!isInCall() &&
- (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
+ (getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
outputs.isA2dpSupported()) {
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
if (device) break;
@@ -426,7 +419,7 @@
// - in countries where not enforced in which case it follows STRATEGY_MEDIA
if ((strategy == STRATEGY_SONIFICATION) ||
- (mForceUse[AUDIO_POLICY_FORCE_FOR_SYSTEM] == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)) {
+ (getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)) {
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
}
@@ -442,9 +435,9 @@
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
}
// Use ONLY Bluetooth SCO output when ringing in vibration mode
- if (!((mForceUse[AUDIO_POLICY_FORCE_FOR_SYSTEM] == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)
+ if (!((getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)
&& (strategy == STRATEGY_ENFORCED_AUDIBLE))) {
- if (mForceUse[AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING]
+ if (getForceUse(AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING)
== AUDIO_POLICY_FORCE_BT_SCO) {
if (device2 != AUDIO_DEVICE_NONE) {
device = device2;
@@ -453,7 +446,7 @@
}
}
// Use both Bluetooth SCO and phone default output when ringing in normal mode
- if (mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION] == AUDIO_POLICY_FORCE_BT_SCO) {
+ if (getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION) == AUDIO_POLICY_FORCE_BT_SCO) {
if ((strategy == STRATEGY_SONIFICATION) &&
(device & AUDIO_DEVICE_OUT_SPEAKER) &&
(availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
@@ -520,7 +513,7 @@
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_HEARING_AID;
}
if ((device2 == AUDIO_DEVICE_NONE) &&
- (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
+ (getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
outputs.isA2dpSupported()) {
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
if (device2 == AUDIO_DEVICE_NONE) {
@@ -531,7 +524,7 @@
}
}
if ((device2 == AUDIO_DEVICE_NONE) &&
- (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] == AUDIO_POLICY_FORCE_SPEAKER)) {
+ (getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) == AUDIO_POLICY_FORCE_SPEAKER)) {
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
}
if (device2 == AUDIO_DEVICE_NONE) {
@@ -560,7 +553,7 @@
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_DIGITAL;
}
if ((device2 == AUDIO_DEVICE_NONE) &&
- (mForceUse[AUDIO_POLICY_FORCE_FOR_DOCK] == AUDIO_POLICY_FORCE_ANALOG_DOCK)) {
+ (getForceUse(AUDIO_POLICY_FORCE_FOR_DOCK) == AUDIO_POLICY_FORCE_ANALOG_DOCK)) {
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
}
if (device2 == AUDIO_DEVICE_NONE) {
@@ -581,7 +574,7 @@
// If hdmi system audio mode is on, remove speaker out of output list.
if ((strategy == STRATEGY_MEDIA) &&
- (mForceUse[AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO] ==
+ (getForceUse(AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO) ==
AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED)) {
device &= ~AUDIO_DEVICE_OUT_SPEAKER;
}
@@ -603,7 +596,7 @@
if (device == AUDIO_DEVICE_NONE) {
ALOGV("getDeviceForStrategy() no device found for strategy %d", strategy);
- device = mApmObserver->getDefaultOutputDevice()->type();
+ device = getApmObserver()->getDefaultOutputDevice()->type();
ALOGE_IF(device == AUDIO_DEVICE_NONE,
"getDeviceForStrategy() no default device defined");
}
@@ -614,9 +607,9 @@
audio_devices_t Engine::getDeviceForInputSource(audio_source_t inputSource) const
{
- const DeviceVector &availableOutputDevices = mApmObserver->getAvailableOutputDevices();
- const DeviceVector &availableInputDevices = mApmObserver->getAvailableInputDevices();
- const SwAudioOutputCollection &outputs = mApmObserver->getOutputs();
+ const DeviceVector &availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
+ const DeviceVector &availableInputDevices = getApmObserver()->getAvailableInputDevices();
+ const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
audio_devices_t availableDeviceTypes = availableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN;
uint32_t device = AUDIO_DEVICE_NONE;
@@ -651,7 +644,7 @@
case AUDIO_SOURCE_MIC:
if (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {
device = AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
- } else if ((mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD] == AUDIO_POLICY_FORCE_BT_SCO) &&
+ } else if ((getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) == AUDIO_POLICY_FORCE_BT_SCO) &&
(availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET)) {
device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
@@ -675,7 +668,7 @@
primaryOutput->getModuleHandle()) & ~AUDIO_DEVICE_BIT_IN;
}
- switch (mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION]) {
+ switch (getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION)) {
case AUDIO_POLICY_FORCE_BT_SCO:
// if SCO device is requested but no SCO device is available, fall back to default case
if (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
@@ -709,7 +702,7 @@
case AUDIO_SOURCE_VOICE_RECOGNITION:
case AUDIO_SOURCE_UNPROCESSED:
case AUDIO_SOURCE_HOTWORD:
- if (mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD] == AUDIO_POLICY_FORCE_BT_SCO &&
+ if (getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) == AUDIO_POLICY_FORCE_BT_SCO &&
availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
@@ -780,10 +773,86 @@
return device;
}
+void Engine::updateDeviceSelectionCache()
+{
+ for (const auto &iter : getProductStrategies()) {
+ const auto &strategy = iter.second;
+ auto devices = getDevicesForProductStrategy(strategy->getId());
+ mDevicesForStrategies[strategy->getId()] = devices;
+ strategy->setDeviceTypes(devices.types());
+ strategy->setDeviceAddress(devices.getFirstValidAddress().c_str());
+ }
+}
+
+DeviceVector Engine::getDevicesForProductStrategy(product_strategy_t strategy) const
+{
+ DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
+ DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices();
+ const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
+
+ auto legacyStrategy = mLegacyStrategyMap.find(strategy) != end(mLegacyStrategyMap) ?
+ mLegacyStrategyMap.at(strategy) : STRATEGY_NONE;
+ audio_devices_t devices = getDeviceForStrategyInt(legacyStrategy,
+ availableOutputDevices,
+ availableInputDevices, outputs,
+ (uint32_t)AUDIO_DEVICE_NONE);
+ 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);
+ }
+ //
+ // @TODO: what is the priority of explicit routing? Shall it be considered first as it used to
+ // be by APM?
+ //
+ product_strategy_t strategy = 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 = getAttributesForStreamType(stream);
+ return getOutputDevicesForAttributes(attributes, nullptr, fromCache);
+}
+
+sp<DeviceDescriptor> Engine::getInputDeviceForAttributes(const audio_attributes_t &attr,
+ AudioMix **/*mix*/) const
+{
+ const auto &availableInputDevices = getApmObserver()->getAvailableInputDevices();
+ std::string address;
+ //
+ // @TODO: manage explicit routing and dynamic mix
+ //
+ audio_devices_t deviceType = getDeviceForInputSource(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 availableInputDevices.getDevice(deviceType,
+ String8(address.c_str()),
+ AUDIO_FORMAT_DEFAULT);
+}
+
template <>
AudioPolicyManagerInterface *Engine::queryInterface()
{
- return &mManagerInterface;
+ return this;
}
} // namespace audio_policy
diff --git a/services/audiopolicy/enginedefault/src/Engine.h b/services/audiopolicy/enginedefault/src/Engine.h
index 06186c1..80e92de 100644
--- a/services/audiopolicy/enginedefault/src/Engine.h
+++ b/services/audiopolicy/enginedefault/src/Engine.h
@@ -16,7 +16,7 @@
#pragma once
-
+#include "EngineBase.h"
#include "AudioPolicyManagerInterface.h"
#include <AudioGain.h>
#include <policy.h>
@@ -29,114 +29,76 @@
namespace audio_policy
{
-class Engine
+enum legacy_strategy {
+ STRATEGY_NONE = -1,
+ STRATEGY_MEDIA,
+ STRATEGY_PHONE,
+ STRATEGY_SONIFICATION,
+ STRATEGY_SONIFICATION_RESPECTFUL,
+ STRATEGY_DTMF,
+ STRATEGY_ENFORCED_AUDIBLE,
+ STRATEGY_TRANSMITTED_THROUGH_SPEAKER,
+ STRATEGY_ACCESSIBILITY,
+ STRATEGY_REROUTING,
+};
+
+class Engine : public EngineBase
{
public:
Engine();
- virtual ~Engine();
+ virtual ~Engine() = default;
template <class RequestedInterface>
RequestedInterface *queryInterface();
private:
- /// Interface members
- class ManagerInterfaceImpl : public AudioPolicyManagerInterface
- {
- public:
- explicit ManagerInterfaceImpl(Engine *policyEngine)
- : mPolicyEngine(policyEngine) {}
+ ///
+ /// from EngineBase, so from AudioPolicyManagerInterface
+ ///
+ audio_devices_t getDeviceForInputSource(audio_source_t inputSource) const override;
- virtual void setObserver(AudioPolicyManagerObserver *observer)
- {
- mPolicyEngine->setObserver(observer);
- }
- virtual status_t initCheck()
- {
- return mPolicyEngine->initCheck();
- }
- virtual audio_devices_t getDeviceForInputSource(audio_source_t inputSource) const
- {
- return mPolicyEngine->getDeviceForInputSource(inputSource);
- }
- virtual audio_devices_t getDeviceForStrategy(routing_strategy strategy) const
- {
- return mPolicyEngine->getDeviceForStrategy(strategy);
- }
- virtual routing_strategy getStrategyForStream(audio_stream_type_t stream)
- {
- return mPolicyEngine->getStrategyForStream(stream);
- }
- virtual routing_strategy getStrategyForUsage(audio_usage_t usage)
- {
- return mPolicyEngine->getStrategyForUsage(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 status_t setDeviceConnectionState(const sp<DeviceDescriptor> /*devDesc*/,
- audio_policy_dev_state_t /*state*/)
- {
- return NO_ERROR;
- }
- private:
- Engine *mPolicyEngine;
- } mManagerInterface;
+ audio_devices_t getDeviceForStrategy(routing_strategy strategy) const override;
+
+ routing_strategy getStrategyForStream(audio_stream_type_t stream) override;
+
+ routing_strategy getStrategyForUsage(audio_usage_t usage) override;
+
+ status_t setPhoneState(audio_mode_t mode) override;
+
+ status_t setForceUse(audio_policy_force_use_t usage,
+ audio_policy_forced_cfg_t config) 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;
+
private:
/* Copy facilities are put private to disable copy. */
Engine(const Engine &object);
Engine &operator=(const Engine &object);
- void setObserver(AudioPolicyManagerObserver *observer);
-
- status_t initCheck();
-
- inline bool isInCall() const
- {
- return is_state_in_call(mPhoneState);
- }
-
- status_t setPhoneState(audio_mode_t mode);
- audio_mode_t getPhoneState() const
- {
- return mPhoneState;
- }
- 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
- {
- return mForceUse[usage];
- }
status_t setDefaultDevice(audio_devices_t device);
- routing_strategy getStrategyForStream(audio_stream_type_t stream);
- routing_strategy getStrategyForUsage(audio_usage_t usage);
- audio_devices_t getDeviceForStrategy(routing_strategy strategy) const;
- audio_devices_t getDeviceForStrategyInt(routing_strategy strategy,
- DeviceVector availableOutputDevices,
- DeviceVector availableInputDevices,
- const SwAudioOutputCollection &outputs,
- uint32_t outputDeviceTypesToIgnore) const;
- audio_devices_t getDeviceForInputSource(audio_source_t inputSource) const;
- audio_mode_t mPhoneState; /**< current phone state. */
+ audio_devices_t getDeviceForStrategyInt(legacy_strategy strategy,
+ DeviceVector availableOutputDevices,
+ DeviceVector availableInputDevices,
+ const SwAudioOutputCollection &outputs,
+ uint32_t outputDeviceTypesToIgnore) const;
- /** current forced use configuration. */
- audio_policy_forced_cfg_t mForceUse[AUDIO_POLICY_FORCE_USE_CNT];
+ DeviceVector getDevicesForProductStrategy(product_strategy_t strategy) const;
- AudioPolicyManagerObserver *mApmObserver;
+ DeviceStrategyMap mDevicesForStrategies;
+
+ std::map<product_strategy_t, legacy_strategy> mLegacyStrategyMap;
};
} // namespace audio_policy
} // namespace android
diff --git a/services/audiopolicy/tests/Android.mk b/services/audiopolicy/tests/Android.mk
index e4fba0f..5f0974e 100644
--- a/services/audiopolicy/tests/Android.mk
+++ b/services/audiopolicy/tests/Android.mk
@@ -4,7 +4,6 @@
LOCAL_C_INCLUDES := \
frameworks/av/services/audiopolicy \
- frameworks/av/services/audiopolicy/common/include \
frameworks/av/services/audiopolicy/engine/interface \
$(call include-path-for, audio-utils) \
@@ -18,6 +17,9 @@
LOCAL_STATIC_LIBRARIES := \
libaudiopolicycomponents \
+LOCAL_HEADER_LIBRARIES := \
+ libaudiopolicycommon
+
LOCAL_SRC_FILES := \
audiopolicymanager_tests.cpp \