/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "APM::AudioPolicyEngine" //#define LOG_NDEBUG 0 //#define VERY_VERBOSE_LOGGING #ifdef VERY_VERBOSE_LOGGING #define ALOGVV ALOGV #else #define ALOGVV(a...) do { } while(0) #endif #include "Engine.h" #include "Strategy.h" #include "Stream.h" #include "InputSource.h" #include "Usage.h" #include <policy.h> #include <ParameterManagerWrapper.h> using std::string; using std::map; namespace android { namespace audio_policy { template <> StrategyCollection &Engine::getCollection<routing_strategy>() { return mStrategyCollection; } template <> StreamCollection &Engine::getCollection<audio_stream_type_t>() { return mStreamCollection; } template <> UsageCollection &Engine::getCollection<audio_usage_t>() { return mUsageCollection; } template <> InputSourceCollection &Engine::getCollection<audio_source_t>() { return mInputSourceCollection; } template <> const StrategyCollection &Engine::getCollection<routing_strategy>() const { return mStrategyCollection; } template <> const StreamCollection &Engine::getCollection<audio_stream_type_t>() const { return mStreamCollection; } template <> const UsageCollection &Engine::getCollection<audio_usage_t>() const { return mUsageCollection; } template <> const InputSourceCollection &Engine::getCollection<audio_source_t>() const { return mInputSourceCollection; } Engine::Engine() : mManagerInterface(this), mPluginInterface(this), mPolicyParameterMgr(new ParameterManagerWrapper()), mApmObserver(NULL) { } Engine::~Engine() { mStrategyCollection.clear(); mStreamCollection.clear(); mInputSourceCollection.clear(); mUsageCollection.clear(); } void Engine::setObserver(AudioPolicyManagerObserver *observer) { ALOG_ASSERT(observer != NULL, "Invalid Audio Policy Manager observer"); mApmObserver = observer; } status_t Engine::initCheck() { if (mPolicyParameterMgr == NULL || mPolicyParameterMgr->start() != NO_ERROR) { ALOGE("%s: could not start Policy PFW", __FUNCTION__); return NO_INIT; } return (mApmObserver != NULL)? NO_ERROR : NO_INIT; } template <typename Key> Element<Key> *Engine::getFromCollection(const Key &key) const { const Collection<Key> collection = getCollection<Key>(); return collection.get(key); } template <typename Key> status_t Engine::add(const std::string &name, const Key &key) { Collection<Key> &collection = getCollection<Key>(); return collection.add(name, key); } template <typename Property, typename Key> Property Engine::getPropertyForKey(Key key) const { Element<Key> *element = getFromCollection<Key>(key); if (element == NULL) { ALOGE("%s: Element not found within collection", __FUNCTION__); return static_cast<Property>(0); } return element->template get<Property>(); } routing_strategy Engine::ManagerInterfaceImpl::getStrategyForUsage(audio_usage_t usage) { return mPolicyEngine->getPropertyForKey<routing_strategy, audio_usage_t>(usage); } audio_devices_t Engine::ManagerInterfaceImpl::getDeviceForStrategy(routing_strategy strategy) const { const SwAudioOutputCollection &outputs = mPolicyEngine->mApmObserver->getOutputs(); /** This is the only case handled programmatically because the PFW is unable to know the * activity of streams. * * -While media is playing on a remote device, use the the sonification behavior. * Note that we test this usecase before testing if media is playing because * the isStreamActive() method only informs about the activity of a stream, not * if it's for local playback. Note also that we use the same delay between both tests * * -When media is not playing anymore, fall back on the sonification behavior */ if (strategy == STRATEGY_SONIFICATION_RESPECTFUL && !is_state_in_call(getPhoneState()) && !outputs.isStreamActiveRemotely(AUDIO_STREAM_MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY) && outputs.isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) { return mPolicyEngine->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 mPolicyEngine->getPropertyForKey<audio_devices_t, routing_strategy>(strategy); } bool Engine::PluginInterfaceImpl::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); return true; } return false; } template <typename Property, typename Key> bool Engine::setPropertyForKey(const Property &property, const Key &key) { Element<Key> *element = getFromCollection<Key>(key); if (element == NULL) { ALOGE("%s: Element not found within collection", __FUNCTION__); return BAD_VALUE; } return element->template set<Property>(property) == NO_ERROR; } status_t Engine::setPhoneState(audio_mode_t mode) { return mPolicyParameterMgr->setPhoneState(mode); } audio_mode_t Engine::getPhoneState() const { return mPolicyParameterMgr->getPhoneState(); } status_t Engine::setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config) { return mPolicyParameterMgr->setForceUse(usage, config); } audio_policy_forced_cfg_t Engine::getForceUse(audio_policy_force_use_t usage) const { return mPolicyParameterMgr->getForceUse(usage); } status_t Engine::setDeviceConnectionState(const sp<DeviceDescriptor> devDesc, audio_policy_dev_state_t /*state*/) { if (audio_is_output_device(devDesc->type())) { return mPolicyParameterMgr->setAvailableOutputDevices( mApmObserver->getAvailableOutputDevices().types()); } else if (audio_is_input_device(devDesc->type())) { return mPolicyParameterMgr->setAvailableInputDevices( mApmObserver->getAvailableInputDevices().types()); } return BAD_TYPE; } template <> AudioPolicyManagerInterface *Engine::queryInterface() { return &mManagerInterface; } template <> AudioPolicyPluginInterface *Engine::queryInterface() { return &mPluginInterface; } } // namespace audio_policy } // namespace android