From c005e569c7bae3f8c49660c9388c3076046069f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Gaffie?= Date: Tue, 6 Nov 2018 15:04:49 +0100 Subject: [PATCH] audiopolicy: apm: switch to new Engine APIs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: make Change-Id: Iedc2268852ee0bce32b67cfd324395c48cb33424 Signed-off-by: François Gaffie --- media/libaudioclient/IAudioPolicyService.cpp | 5 +- .../include/media/AudioCommonTypes.h | 5 +- services/audiopolicy/Android.mk | 12 +- services/audiopolicy/common/include/policy.h | 23 +- .../include/AudioIODescriptorInterface.h | 34 + .../include/AudioOutputDescriptor.h | 115 ++- .../include/AudioPolicyMix.h | 2 +- .../include/ClientDescriptor.h | 12 +- .../include/EffectDescriptor.h | 18 +- .../src/AudioOutputDescriptor.cpp | 28 +- .../managerdefinitions/src/AudioPolicyMix.cpp | 2 +- .../src/ClientDescriptor.cpp | 2 +- .../src/EffectDescriptor.cpp | 21 +- .../engineconfigurable/src/Engine.cpp | 39 +- .../audiopolicy/enginedefault/src/Engine.cpp | 37 +- .../managerdefault/AudioPolicyManager.cpp | 665 +++++++----------- .../managerdefault/AudioPolicyManager.h | 164 +++-- .../service/AudioPolicyInterfaceImpl.cpp | 5 +- services/audiopolicy/tests/Android.mk | 4 +- 19 files changed, 619 insertions(+), 574 deletions(-) diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp index edd8e8011d..0db56e8609 100644 --- a/media/libaudioclient/IAudioPolicyService.cpp +++ b/media/libaudioclient/IAudioPolicyService.cpp @@ -414,7 +414,7 @@ public: data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); data.writeInt32(static_cast (stream)); remote()->transact(GET_STRATEGY_FOR_STREAM, data, &reply); - return reply.readInt32(); + return reply.readUint32(); } virtual audio_devices_t getDevicesForStream(audio_stream_type_t stream) @@ -1126,7 +1126,6 @@ status_t BnAudioPolicyService::onTransact( case START_INPUT: case STOP_INPUT: case RELEASE_INPUT: - case GET_STRATEGY_FOR_STREAM: case GET_OUTPUT_FOR_EFFECT: case REGISTER_EFFECT: case UNREGISTER_EFFECT: @@ -1422,7 +1421,7 @@ status_t BnAudioPolicyService::onTransact( CHECK_INTERFACE(IAudioPolicyService, data, reply); audio_stream_type_t stream = static_cast (data.readInt32()); - reply->writeInt32(getStrategyForStream(stream)); + reply->writeUint32(getStrategyForStream(stream)); return NO_ERROR; } break; diff --git a/media/libaudioclient/include/media/AudioCommonTypes.h b/media/libaudioclient/include/media/AudioCommonTypes.h index 48d15403d0..5188da1fd3 100644 --- a/media/libaudioclient/include/media/AudioCommonTypes.h +++ b/media/libaudioclient/include/media/AudioCommonTypes.h @@ -34,6 +34,9 @@ constexpr bool operator==(const audio_attributes_t &lhs, const audio_attributes_ return lhs.usage == rhs.usage && lhs.content_type == rhs.content_type && lhs.flags == rhs.flags && (std::strcmp(lhs.tags, rhs.tags) == 0); } - +constexpr bool operator!=(const audio_attributes_t &lhs, const audio_attributes_t &rhs) +{ + return !(lhs==rhs); +} } // namespace android diff --git a/services/audiopolicy/Android.mk b/services/audiopolicy/Android.mk index 5476497c7b..f72f44a652 100644 --- a/services/audiopolicy/Android.mk +++ b/services/audiopolicy/Android.mk @@ -11,10 +11,10 @@ LOCAL_SRC_FILES:= \ LOCAL_C_INCLUDES := \ frameworks/av/services/audioflinger \ $(call include-path-for, audio-utils) \ - frameworks/av/services/audiopolicy/engine/interface \ LOCAL_HEADER_LIBRARIES := \ - libaudiopolicycommon + libaudiopolicycommon \ + libaudiopolicyengine_interface_headers \ LOCAL_SHARED_LIBRARIES := \ libcutils \ @@ -78,11 +78,11 @@ LOCAL_SHARED_LIBRARIES += libaudiopolicyenginedefault endif # ifeq ($(USE_CONFIGURABLE_AUDIO_POLICY), 1) LOCAL_C_INCLUDES += \ - frameworks/av/services/audiopolicy/engine/interface \ $(call include-path-for, audio-utils) \ LOCAL_HEADER_LIBRARIES := \ - libaudiopolicycommon + libaudiopolicycommon \ + libaudiopolicyengine_interface_headers LOCAL_STATIC_LIBRARIES := \ libaudiopolicycomponents @@ -118,11 +118,11 @@ LOCAL_STATIC_LIBRARIES := \ libaudiopolicycomponents LOCAL_C_INCLUDES += \ - frameworks/av/services/audiopolicy/engine/interface \ $(call include-path-for, audio-utils) \ LOCAL_HEADER_LIBRARIES := \ - libaudiopolicycommon + libaudiopolicycommon \ + libaudiopolicyengine_interface_headers LOCAL_CFLAGS := -Wall -Werror diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h index b90a08d36c..605fc1cda1 100644 --- a/services/audiopolicy/common/include/policy.h +++ b/services/audiopolicy/common/include/policy.h @@ -23,7 +23,6 @@ namespace android { using StreamTypeVector = std::vector; - static const audio_attributes_t defaultAttr = AUDIO_ATTRIBUTES_INITIALIZER; } // namespace android @@ -163,3 +162,25 @@ static inline bool audio_formats_match(audio_format_t format1, } return format1 == format2; } + +/** + * @brief hasStream checks if a given stream type is found in the list of streams + * @param streams collection of stream types to consider. + * @param streamType to consider + * @return true if voice stream is found in the given streams, false otherwise + */ +static inline bool hasStream(const android::StreamTypeVector &streams, + audio_stream_type_t streamType) +{ + return std::find(begin(streams), end(streams), streamType) != end(streams); +} + +/** + * @brief hasVoiceStream checks if a voice stream is found in the list of streams + * @param streams collection to consider. + * @return true if voice stream is found in the given streams, false otherwise + */ +static inline bool hasVoiceStream(const android::StreamTypeVector &streams) +{ + return hasStream(streams, AUDIO_STREAM_VOICE_CALL); +} diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h b/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h index 555412e0cd..6e2963245c 100644 --- a/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h +++ b/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h @@ -16,6 +16,8 @@ #pragma once +#include "DeviceDescriptor.h" + namespace android { /** @@ -34,4 +36,36 @@ public: virtual void setPatchHandle(audio_patch_handle_t handle) = 0; }; +template +sp findPreferredDevice( + IoDescriptor& desc, Filter filter, bool& active, const DeviceVector& devices) +{ + auto activeClients = desc->clientsList(true /*activeOnly*/); + auto activeClientsWithRoute = + desc->clientsList(true /*activeOnly*/, filter, true /*preferredDevice*/); + active = activeClients.size() > 0; + if (active && activeClients.size() == activeClientsWithRoute.size()) { + return devices.getDeviceFromId(activeClientsWithRoute[0]->preferredDeviceId()); + } + return nullptr; +} + +template +sp findPreferredDevice( + IoCollection& ioCollection, Filter filter, const DeviceVector& devices) +{ + sp device; + for (size_t i = 0; i < ioCollection.size(); i++) { + auto desc = ioCollection.valueAt(i); + bool active; + sp curDevice = findPreferredDevice(desc, filter, active, devices); + if (active && curDevice == nullptr) { + return nullptr; + } else if (curDevice != nullptr) { + device = curDevice; + } + } + return device; +} + } // namespace android diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h index e1ecc61eda..6132bb4782 100644 --- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h +++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h @@ -16,18 +16,20 @@ #pragma once +#define __STDC_LIMIT_MACROS +#include + #include #include #include #include #include -#include #include "AudioIODescriptorInterface.h" #include "AudioPort.h" #include "ClientDescriptor.h" #include "DeviceDescriptor.h" -#include +#include namespace android { @@ -35,6 +37,70 @@ class IOProfile; class AudioMix; class AudioPolicyClientInterface; +class ActivityTracking +{ +public: + virtual ~ActivityTracking() = default; + bool isActive(uint32_t inPastMs = 0, nsecs_t sysTime = 0) const + { + if (mActivityCount > 0) { + return true; + } + if (inPastMs == 0) { + return false; + } + if (sysTime == 0) { + sysTime = systemTime(); + } + if (ns2ms(sysTime - mStopTime) < inPastMs) { + return true; + } + return false; + } + void changeActivityCount(int delta) + { + if ((delta + (int)mActivityCount) < 0) { + LOG_ALWAYS_FATAL("%s: invalid delta %d, refCount %d", __func__, delta, mActivityCount); + } + mActivityCount += delta; + if (!mActivityCount) { + setStopTime(systemTime()); + } + } + uint32_t getActivityCount() const { return mActivityCount; } + nsecs_t getStopTime() const { return mStopTime; } + void setStopTime(nsecs_t stopTime) { mStopTime = stopTime; } + + virtual void dump(String8 *dst, int spaces) const + { + dst->appendFormat("%*s- ActivityCount: %d, StopTime: %" PRId64 " \n", spaces, "", + getActivityCount(), getStopTime()); + } +private: + uint32_t mActivityCount = 0; + nsecs_t mStopTime = 0; +}; + +/** + * @brief The Activity class: it tracks the activity for volume policy (volume index, mute, + * memorize previous stop, and store mute if incompatible device with another strategy. + * Having this class prevents from looping on all attributes (legacy streams) of the strategy + */ +class RoutingActivity : public ActivityTracking +{ +public: + void setMutedByDevice( bool isMuted) { mIsMutedByDevice = isMuted; } + bool isMutedByDevice() const { return mIsMutedByDevice; } + +private: + /** + * strategies muted because of incompatible device selection. + * See AudioPolicyManager::checkDeviceMuteStrategies() + */ + bool mIsMutedByDevice = false; +}; +using RoutingActivities = std::map; + // descriptor for audio outputs. Used to maintain current configuration of each opened audio output // and keep track of the usage of this output by each audio stream type. class AudioOutputDescriptor: public AudioPortConfig, public AudioIODescriptorInterface @@ -70,6 +136,14 @@ public: uint32_t streamActiveCount(audio_stream_type_t stream) const { return mActiveCount[stream]; } + /** + * @brief setStopTime set the stop time due to the client stoppage or a re routing of this + * client + * @param client to be considered + * @param sysTime when the client stopped/was rerouted + */ + void setStopTime(const sp& client, nsecs_t sysTime); + /** * Changes the client->active() state and the output descriptor's global active count, * along with the stream active count and mActiveClients. @@ -82,6 +156,21 @@ public: uint32_t inPastMs = 0, nsecs_t sysTime = 0) const; + bool isStrategyActive(product_strategy_t ps, uint32_t inPastMs = 0, nsecs_t sysTime = 0) const + { + return mRoutingActivities.find(ps) != std::end(mRoutingActivities)? + mRoutingActivities.at(ps).isActive(inPastMs, sysTime) : false; + } + bool isStrategyMutedByDevice(product_strategy_t ps) const + { + return mRoutingActivities.find(ps) != std::end(mRoutingActivities)? + mRoutingActivities.at(ps).isMutedByDevice() : false; + } + void setStrategyMutedByDevice(product_strategy_t ps, bool isMuted) + { + mRoutingActivities[ps].setMutedByDevice(isMuted); + } + virtual void toAudioPortConfig(struct audio_port_config *dstConfig, const struct audio_port_config *srcConfig = NULL) const; virtual sp getAudioPort() const { return mPort; } @@ -95,7 +184,8 @@ public: void setPatchHandle(audio_patch_handle_t handle) override; TrackClientVector clientsList(bool activeOnly = false, - routing_strategy strategy = STRATEGY_NONE, bool preferredDeviceOnly = false) const; + product_strategy_t strategy = PRODUCT_STRATEGY_NONE, + bool preferredDeviceOnly = false) const; // override ClientMapHandler to abort when removing a client when active. void removeClient(audio_port_handle_t portId) override { @@ -121,8 +211,6 @@ public: DeviceVector mDevices; /**< current devices this output is routed to */ nsecs_t mStopTime[AUDIO_STREAM_CNT]; int mMuteCount[AUDIO_STREAM_CNT]; // mute request counter - bool mStrategyMutedByDevice[NUM_STRATEGIES]; // strategies muted because of incompatible - // device selection. See checkDeviceMuteStrategies() AudioMix *mPolicyMix = nullptr; // non NULL when used by a dynamic policy protected: @@ -139,6 +227,8 @@ protected: // Compare with the ClientMap (mClients) which are external AudioTrack clients of the // output descriptor (and do not count internal PatchTracks). ActiveClientMap mActiveClients; + + RoutingActivities mRoutingActivities; /**< track routing activity on this ouput.*/ }; // Audio output driven by a software mixer in audio flinger. @@ -274,6 +364,21 @@ public: */ bool isStreamActiveLocally(audio_stream_type_t stream, uint32_t inPastMs = 0) const; + /** + * @brief isStrategyActiveOnSameModule checks if the given strategy is active (or was active + * in the past) on the given output and all the outputs belonging to the same HW Module + * the same module than the given output + * @param outputDesc to be considered + * @param ps product strategy to be checked upon activity status + * @param inPastMs if 0, check currently, otherwise, check in the past + * @param sysTime shall be set if request is done for the past activity. + * @return true if an output following the strategy is active on the same module than desc, + * false otherwise + */ + bool isStrategyActiveOnSameModule(product_strategy_t ps, + const sp& desc, + uint32_t inPastMs = 0, nsecs_t sysTime = 0) const; + /** * returns the A2DP output handle if it is open or 0 otherwise */ diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h index 2932296cb6..7296c9532c 100644 --- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h +++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h @@ -78,7 +78,7 @@ public: sp getDeviceAndMixForInputSource(audio_source_t inputSource, const DeviceVector &availableDeviceTypes, - AudioMix **policyMix); + AudioMix **policyMix) const; /** * @brief try to find a matching mix for a given output descriptor and returns the associated diff --git a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h index a1870291f2..2fb1277b96 100644 --- a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h +++ b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h @@ -22,14 +22,14 @@ #include #include -#include +#include #include #include #include #include +#include #include "AudioPatch.h" #include "EffectDescriptor.h" -#include "RoutingStrategy.h" namespace android { @@ -81,7 +81,7 @@ public: TrackClientDescriptor(audio_port_handle_t portId, uid_t uid, audio_session_t sessionId, audio_attributes_t attributes, audio_config_base_t config, audio_port_handle_t preferredDeviceId, audio_stream_type_t stream, - routing_strategy strategy, audio_output_flags_t flags) : + product_strategy_t strategy, audio_output_flags_t flags) : ClientDescriptor(portId, uid, sessionId, attributes, config, preferredDeviceId), mStream(stream), mStrategy(strategy), mFlags(flags) {} ~TrackClientDescriptor() override = default; @@ -92,11 +92,11 @@ public: audio_output_flags_t flags() const { return mFlags; } audio_stream_type_t stream() const { return mStream; } - routing_strategy strategy() const { return mStrategy; } + product_strategy_t strategy() const { return mStrategy; } private: const audio_stream_type_t mStream; - const routing_strategy mStrategy; + const product_strategy_t mStrategy; const audio_output_flags_t mFlags; }; @@ -136,7 +136,7 @@ class SourceClientDescriptor: public TrackClientDescriptor public: SourceClientDescriptor(audio_port_handle_t portId, uid_t uid, audio_attributes_t attributes, const sp& patchDesc, const sp& srcDevice, - audio_stream_type_t stream, routing_strategy strategy); + audio_stream_type_t stream, product_strategy_t strategy); ~SourceClientDescriptor() override = default; sp patchDesc() const { return mPatchDesc; } diff --git a/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h index 2dc33ab936..7f01dc522d 100644 --- a/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h +++ b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h @@ -16,7 +16,7 @@ #pragma once -#include +#include #include #include #include @@ -28,14 +28,26 @@ namespace android { class EffectDescriptor : public RefBase { public: + EffectDescriptor(const effect_descriptor_t *desc, bool isMusicEffect, + int id, int io, int session) : + mId(id), mIo(io), mSession(session), mEnabled(false), + mIsMusicEffect(isMusicEffect) + { + memcpy (&mDesc, desc, sizeof(effect_descriptor_t)); + } + void dump(String8 *dst, int spaces = 0) const; int mId; // effect unique ID int mIo; // io the effect is attached to - routing_strategy mStrategy; // routing strategy the effect is associated to int mSession; // audio session the effect is on effect_descriptor_t mDesc; // effect descriptor bool mEnabled; // enabled state: CPU load being used or not + + bool isMusicEffect() const { return mIsMusicEffect; } + +private: + bool mIsMusicEffect; }; class EffectDescriptorCollection : public KeyedVector > @@ -44,7 +56,7 @@ public: EffectDescriptorCollection(); status_t registerEffect(const effect_descriptor_t *desc, audio_io_handle_t io, - uint32_t strategy, int session, int id); + int session, int id, bool isMusicEffect); status_t unregisterEffect(int id); sp getEffect(int id) const; status_t setEffectEnabled(int id, bool enabled); diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp index 78b3f45bd9..d997bf74af 100644 --- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp @@ -44,9 +44,6 @@ AudioOutputDescriptor::AudioOutputDescriptor(const sp& port, mMuteCount[i] = 0; mStopTime[i] = 0; } - for (int i = 0; i < NUM_STRATEGIES; i++) { - mStrategyMutedByDevice[i] = false; - } if (mPort.get() != nullptr) { mPort->pickAudioProfile(mSamplingRate, mChannelMask, mFormat); if (mPort->mGains.size() > 0) { @@ -101,6 +98,7 @@ void AudioOutputDescriptor::changeStreamActiveCount(const spstrategy()].changeActivityCount(delta); if (delta > 0) { mActiveClients[client] += delta; @@ -122,6 +120,12 @@ void AudioOutputDescriptor::changeStreamActiveCount(const sp& client, nsecs_t sysTime) +{ + mStopTime[client->stream()] = sysTime; + mRoutingActivities[client->strategy()].setStopTime(sysTime); +} + void AudioOutputDescriptor::setClientActive(const sp& client, bool active) { LOG_ALWAYS_FATAL_IF(getClient(client->portId()) == nullptr, @@ -247,13 +251,13 @@ void AudioOutputDescriptor::toAudioPort(struct audio_port *port) const port->ext.mix.hw_module = getModuleHandle(); } -TrackClientVector AudioOutputDescriptor::clientsList(bool activeOnly, routing_strategy strategy, +TrackClientVector AudioOutputDescriptor::clientsList(bool activeOnly, product_strategy_t strategy, bool preferredDeviceOnly) const { TrackClientVector clients; for (const auto &client : getClientIterable()) { if ((!activeOnly || client->active()) - && (strategy == STRATEGY_NONE || strategy == client->strategy()) + && (strategy == PRODUCT_STRATEGY_NONE || strategy == client->strategy()) && (!preferredDeviceOnly || client->hasPreferredDevice())) { clients.push_back(client); } @@ -698,6 +702,20 @@ bool SwAudioOutputCollection::isStreamActiveRemotely(audio_stream_type_t stream, return false; } +bool SwAudioOutputCollection::isStrategyActiveOnSameModule(product_strategy_t ps, + const sp& desc, + uint32_t inPastMs, nsecs_t sysTime) const +{ + for (size_t i = 0; i < size(); i++) { + const sp otherDesc = valueAt(i); + if (desc->sharesHwModuleWith(otherDesc) && + otherDesc->isStrategyActive(ps, inPastMs, sysTime)) { + return true; + } + } + return false; +} + audio_io_handle_t SwAudioOutputCollection::getA2dpOutput() const { for (size_t i = 0; i < size(); i++) { diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp index cd10c8240d..2489e76e7a 100644 --- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp @@ -302,7 +302,7 @@ sp AudioPolicyMixCollection::getDeviceAndMixForOutput( } sp AudioPolicyMixCollection::getDeviceAndMixForInputSource( - audio_source_t inputSource, const DeviceVector &availDevices, AudioMix **policyMix) + audio_source_t inputSource, const DeviceVector &availDevices, AudioMix **policyMix) const { for (size_t i = 0; i < size(); i++) { AudioMix *mix = valueAt(i)->getMix(); diff --git a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp index 82d64c9e4d..1525285f55 100644 --- a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp @@ -82,7 +82,7 @@ void RecordClientDescriptor::dump(String8 *dst, int spaces, int index) const SourceClientDescriptor::SourceClientDescriptor(audio_port_handle_t portId, uid_t uid, audio_attributes_t attributes, const sp& patchDesc, const sp& srcDevice, audio_stream_type_t stream, - routing_strategy strategy) : + product_strategy_t strategy) : TrackClientDescriptor::TrackClientDescriptor(portId, uid, AUDIO_SESSION_NONE, attributes, AUDIO_CONFIG_BASE_INITIALIZER, AUDIO_PORT_HANDLE_NONE, stream, strategy, AUDIO_OUTPUT_FLAG_NONE), diff --git a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp index 40c49e7e9c..89f989943d 100644 --- a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp @@ -24,8 +24,9 @@ namespace android { void EffectDescriptor::dump(String8 *dst, int spaces) const { + dst->appendFormat("%*sID: %d\n", spaces, "", mId); dst->appendFormat("%*sI/O: %d\n", spaces, "", mIo); - dst->appendFormat("%*sStrategy: %d\n", spaces, "", mStrategy); + dst->appendFormat("%*sMusic Effect: %s\n", spaces, "", isMusicEffect()? "yes" : "no"); dst->appendFormat("%*sSession: %d\n", spaces, "", mSession); dst->appendFormat("%*sName: %s\n", spaces, "", mDesc.name); dst->appendFormat("%*s%s\n", spaces, "", mEnabled ? "Enabled" : "Disabled"); @@ -41,9 +42,8 @@ EffectDescriptorCollection::EffectDescriptorCollection() : status_t EffectDescriptorCollection::registerEffect(const effect_descriptor_t *desc, audio_io_handle_t io, - uint32_t strategy, int session, - int id) + int id, bool isMusicEffect) { if (getEffect(id) != nullptr) { ALOGW("%s effect %s already registered", __FUNCTION__, desc->name); @@ -59,18 +59,11 @@ status_t EffectDescriptorCollection::registerEffect(const effect_descriptor_t *d if (mTotalEffectsMemory > mTotalEffectsMemoryMaxUsed) { mTotalEffectsMemoryMaxUsed = mTotalEffectsMemory; } - ALOGV("registerEffect() effect %s, io %d, strategy %d session %d id %d", - desc->name, io, strategy, session, id); + ALOGV("registerEffect() effect %s, io %d, session %d id %d", + desc->name, io, session, id); ALOGV("registerEffect() memory %d, total memory %d", desc->memoryUsage, mTotalEffectsMemory); - sp effectDesc = new EffectDescriptor(); - memcpy (&effectDesc->mDesc, desc, sizeof(effect_descriptor_t)); - effectDesc->mId = id; - effectDesc->mIo = io; - effectDesc->mStrategy = static_cast(strategy); - effectDesc->mSession = session; - effectDesc->mEnabled = false; - + sp effectDesc = new EffectDescriptor(desc, isMusicEffect, id, io, session); add(id, effectDesc); return NO_ERROR; @@ -161,7 +154,7 @@ bool EffectDescriptorCollection::isNonOffloadableEffectEnabled() const { for (size_t i = 0; i < size(); i++) { sp effectDesc = valueAt(i); - if (effectDesc->mEnabled && (effectDesc->mStrategy == STRATEGY_MEDIA) && + if (effectDesc->mEnabled && (effectDesc->isMusicEffect()) && ((effectDesc->mDesc.flags & EFFECT_FLAG_OFFLOAD_SUPPORTED) == 0)) { ALOGV("isNonOffloadableEffectEnabled() non offloadable effect %s enabled on session %d", effectDesc->mDesc.name, effectDesc->mSession); diff --git a/services/audiopolicy/engineconfigurable/src/Engine.cpp b/services/audiopolicy/engineconfigurable/src/Engine.cpp index a04254c450..1b09e3dcc6 100644 --- a/services/audiopolicy/engineconfigurable/src/Engine.cpp +++ b/services/audiopolicy/engineconfigurable/src/Engine.cpp @@ -32,6 +32,7 @@ #include #include +#include #include using std::string; @@ -330,10 +331,20 @@ DeviceVector Engine::getOutputDevicesForAttributes(const audio_attributes_t &att ALOGV("%s explicit Routing on device %s", __func__, preferredDevice->toString().c_str()); return DeviceVector(preferredDevice); } - product_strategy_t strategy = EngineBase::getProductStrategyForAttributes(attributes); + product_strategy_t strategy = getProductStrategyForAttributes(attributes); + const DeviceVector &availableOutputDevices = getApmObserver()->getAvailableOutputDevices(); + const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs(); // - // @TODO: manage dynamic mix + // @TODO: what is the priority of explicit routing? Shall it be considered first as it used to + // be by APM? // + // Honor explicit routing requests only if all active clients have a preferred route in which + // case the last active client route is used + sp device = findPreferredDevice(outputs, strategy, availableOutputDevices); + if (device != nullptr) { + return DeviceVector(device); + } + return fromCache? mDevicesForStrategies.at(strategy) : getDevicesForProductStrategy(strategy); } @@ -344,13 +355,29 @@ DeviceVector Engine::getOutputDevicesForStream(audio_stream_type_t stream, bool } sp Engine::getInputDeviceForAttributes(const audio_attributes_t &attr, - AudioMix **/*mix*/) const + AudioMix **mix) const { - const auto &availInputDevices = getApmObserver()->getAvailableInputDevices(); + const auto &policyMixes = getApmObserver()->getAudioPolicyMixCollection(); + const auto &availableInputDevices = getApmObserver()->getAvailableInputDevices(); + const auto &inputs = getApmObserver()->getInputs(); std::string address; // - // @TODO: manage explicit routing and dynamic mix + // Explicit Routing ??? what is the priority of explicit routing? Shall it be considered + // first as it used to be by APM? // + // Honor explicit routing requests only if all active clients have a preferred route in which + // case the last active client route is used + sp device = + findPreferredDevice(inputs, attr.source, availableInputDevices); + if (device != nullptr) { + return device; + } + + device = policyMixes.getDeviceAndMixForInputSource(attr.source, availableInputDevices, mix); + if (device != nullptr) { + return device; + } + audio_devices_t deviceType = getPropertyForKey(attr.source); if (audio_is_remote_submix_device(deviceType)) { @@ -361,7 +388,7 @@ sp Engine::getInputDeviceForAttributes(const audio_attributes_ address = tags.substr(pos + std::strlen("addr=")); } } - return availInputDevices.getDevice(deviceType, String8(address.c_str()), AUDIO_FORMAT_DEFAULT); + return availableInputDevices.getDevice(deviceType, String8(address.c_str()), AUDIO_FORMAT_DEFAULT); } void Engine::updateDeviceSelectionCache() diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp index 69f06982e5..a449df6d6c 100644 --- a/services/audiopolicy/enginedefault/src/Engine.cpp +++ b/services/audiopolicy/enginedefault/src/Engine.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -241,7 +242,8 @@ audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs(); - return getDeviceForStrategyInt(static_cast(strategy), availableOutputDevices, + return getDeviceForStrategyInt(static_cast(strategy), + availableOutputDevices, availableInputDevices, outputs, (uint32_t)AUDIO_DEVICE_NONE); } @@ -808,14 +810,19 @@ DeviceVector Engine::getOutputDevicesForAttributes(const audio_attributes_t &att ALOGV("%s explicit Routing on device %s", __func__, preferredDevice->toString().c_str()); return DeviceVector(preferredDevice); } + product_strategy_t strategy = getProductStrategyForAttributes(attributes); + const DeviceVector &availableOutputDevices = getApmObserver()->getAvailableOutputDevices(); + const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs(); // // @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 - // + // Honor explicit routing requests only if all active clients have a preferred route in which + // case the last active client route is used + sp device = findPreferredDevice(outputs, strategy, availableOutputDevices); + if (device != nullptr) { + return DeviceVector(device); + } return fromCache? mDevicesForStrategies.at(strategy) : getDevicesForProductStrategy(strategy); } @@ -827,13 +834,29 @@ DeviceVector Engine::getOutputDevicesForStream(audio_stream_type_t stream, bool } sp Engine::getInputDeviceForAttributes(const audio_attributes_t &attr, - AudioMix **/*mix*/) const + AudioMix **mix) const { + const auto &policyMixes = getApmObserver()->getAudioPolicyMixCollection(); const auto &availableInputDevices = getApmObserver()->getAvailableInputDevices(); + const auto &inputs = getApmObserver()->getInputs(); std::string address; + // - // @TODO: manage explicit routing and dynamic mix + // Explicit Routing ??? what is the priority of explicit routing? Shall it be considered + // first as it used to be by APM? // + // Honor explicit routing requests only if all active clients have a preferred route in which + // case the last active client route is used + sp device = + findPreferredDevice(inputs, attr.source, availableInputDevices); + if (device != nullptr) { + return device; + } + + device = policyMixes.getDeviceAndMixForInputSource(attr.source, availableInputDevices, mix); + if (device != nullptr) { + return device; + } audio_devices_t deviceType = getDeviceForInputSource(attr.source); if (audio_is_remote_submix_device(deviceType)) { diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index d7c7b4d029..771f62aade 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -495,9 +495,10 @@ uint32_t AudioPolicyManager::updateCallRouting(const DeviceVector &rxDevices, ui ALOG_ASSERT(!rxDevices.isEmpty(), "updateCallRouting() no selected output device"); audio_attributes_t attr = { .source = AUDIO_SOURCE_VOICE_COMMUNICATION }; - auto txSourceDevice = getDeviceAndMixForAttributes(attr); + auto txSourceDevice = mEngine->getInputDeviceForAttributes(attr); ALOG_ASSERT(txSourceDevice != 0, "updateCallRouting() input selected device not available"); - ALOGV("updateCallRouting device rxDevice %s txDevice %s", + + ALOGV("updateCallRouting device rxDevice %s txDevice %s", rxDevices.itemAt(0)->toString().c_str(), txSourceDevice->toString().c_str()); // release existing RX patch if any @@ -677,26 +678,27 @@ void AudioPolicyManager::setPhoneState(audio_mode_t state) int delayMs = 0; if (isStateInCall(state)) { nsecs_t sysTime = systemTime(); + auto musicStrategy = streamToStrategy(AUDIO_STREAM_MUSIC); + auto sonificationStrategy = streamToStrategy(AUDIO_STREAM_ALARM); for (size_t i = 0; i < mOutputs.size(); i++) { sp desc = mOutputs.valueAt(i); // mute media and sonification strategies and delay device switch by the largest // latency of any output where either strategy is active. // This avoid sending the ring tone or music tail into the earpiece or headset. - if ((isStrategyActive(desc, STRATEGY_MEDIA, - SONIFICATION_HEADSET_MUSIC_DELAY, - sysTime) || - isStrategyActive(desc, STRATEGY_SONIFICATION, - SONIFICATION_HEADSET_MUSIC_DELAY, - sysTime)) && + if ((desc->isStrategyActive(musicStrategy, SONIFICATION_HEADSET_MUSIC_DELAY, sysTime) || + desc->isStrategyActive(sonificationStrategy, SONIFICATION_HEADSET_MUSIC_DELAY, + sysTime)) && (delayMs < (int)desc->latency()*2)) { delayMs = desc->latency()*2; } - setStrategyMute(STRATEGY_MEDIA, true, desc); - setStrategyMute(STRATEGY_MEDIA, false, desc, MUTE_TIME_MS, - getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/)); - setStrategyMute(STRATEGY_SONIFICATION, true, desc); - setStrategyMute(STRATEGY_SONIFICATION, false, desc, MUTE_TIME_MS, - getDeviceForStrategy(STRATEGY_SONIFICATION, true /*fromCache*/)); + setStrategyMute(musicStrategy, true, desc); + setStrategyMute(musicStrategy, false, desc, MUTE_TIME_MS, + mEngine->getOutputDevicesForAttributes(attributes_initializer(AUDIO_USAGE_MEDIA), + nullptr, true /*fromCache*/).types()); + setStrategyMute(sonificationStrategy, true, desc); + setStrategyMute(sonificationStrategy, false, desc, MUTE_TIME_MS, + mEngine->getOutputDevicesForAttributes(attributes_initializer(AUDIO_USAGE_ALARM), + nullptr, true /*fromCache*/).types()); } } @@ -743,12 +745,8 @@ void AudioPolicyManager::setPhoneState(audio_mode_t state) } // Flag that ringtone volume must be limited to music volume until we exit MODE_RINGTONE - if (state == AUDIO_MODE_RINGTONE && - isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY)) { - mLimitRingtoneVolume = true; - } else { - mLimitRingtoneVolume = false; - } + mLimitRingtoneVolume = (state == AUDIO_MODE_RINGTONE && + isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY)); } audio_mode_t AudioPolicyManager::getPhoneState() { @@ -871,8 +869,7 @@ sp AudioPolicyManager::getProfileForOutput( audio_io_handle_t AudioPolicyManager::getOutput(audio_stream_type_t stream) { - routing_strategy strategy = getStrategy(stream); - DeviceVector devices = getDevicesForStrategy(strategy, false /*fromCache*/); + DeviceVector devices = mEngine->getOutputDevicesForStream(stream, false /*fromCache*/); // Note that related method getOutputForAttr() uses getOutputForDevice() not selectOutput(). // We use selectOutput() here since we don't have the desired AudioTrack sample rate, @@ -906,7 +903,7 @@ status_t AudioPolicyManager::getAudioAttributes(audio_attributes_t *dstAttr, ALOGE("%s: invalid stream type", __func__); return BAD_VALUE; } - stream_type_to_audio_attributes(srcStream, dstAttr); + *dstAttr = mEngine->getAttributesForStreamType(srcStream); } return NO_ERROR; } @@ -921,57 +918,52 @@ status_t AudioPolicyManager::getOutputForAttrInt(audio_attributes_t *resultAttr, audio_output_flags_t *flags, audio_port_handle_t *selectedDeviceId) { - DeviceVector devices; - routing_strategy strategy; - audio_devices_t deviceType = AUDIO_DEVICE_NONE; + DeviceVector outputDevices; const audio_port_handle_t requestedPortId = *selectedDeviceId; DeviceVector msdDevices = getMsdAudioOutDevices(); + const sp requestedDevice = + mAvailableOutputDevices.getDeviceFromId(requestedPortId); + + status_t status = getAudioAttributes(resultAttr, attr, *stream); if (status != NO_ERROR) { return status; } + *stream = mEngine->getStreamTypeForAttributes(*resultAttr); - ALOGV("%s usage=%d, content=%d, tag=%s flags=%08x" - " session %d selectedDeviceId %d", - __func__, - resultAttr->usage, resultAttr->content_type, resultAttr->tags, resultAttr->flags, - session, requestedPortId); - - *stream = streamTypefromAttributesInt(resultAttr); - - strategy = getStrategyForAttr(resultAttr); - - // First check for explicit routing (eg. setPreferredDevice) - sp requestedDevice = mAvailableOutputDevices.getDeviceFromId(requestedPortId); - if (requestedDevice != nullptr) { - deviceType = requestedDevice->type(); - } else { - // If no explict route, is there a matching dynamic policy that applies? - sp desc; - if (mPolicyMixes.getOutputForAttr(*resultAttr, uid, desc) == NO_ERROR) { - ALOG_ASSERT(desc != 0, "Invalid desc returned by getOutputForAttr"); - if (!audio_has_proportional_frames(config->format)) { - return BAD_VALUE; - } - *stream = streamTypefromAttributesInt(resultAttr); - *output = desc->mIoHandle; - AudioMix *mix = desc->mPolicyMix; - sp deviceDesc = - mAvailableOutputDevices.getDevice( - mix->mDeviceType, mix->mDeviceAddress, AUDIO_FORMAT_DEFAULT); - *selectedDeviceId = deviceDesc != 0 ? deviceDesc->getId() : AUDIO_PORT_HANDLE_NONE; - ALOGV("%s returns output %d", __func__, *output); - return NO_ERROR; - } + ALOGV("%s() attributes=%s stream=%s session %d selectedDeviceId %d", __func__, + toString(*resultAttr).c_str(), toString(*stream).c_str(), session, requestedPortId); - // Virtual sources must always be dynamicaly or explicitly routed - if (resultAttr->usage == AUDIO_USAGE_VIRTUAL_SOURCE) { - ALOGW("%s no policy mix found for usage AUDIO_USAGE_VIRTUAL_SOURCE", __func__); + // 1/ First check for explicit routing (eg. setPreferredDevice): NOTE: now handled by engine + // 2/ If no explict route, is there a matching dynamic policy that applies? + // NOTE: new engine product strategy does not make use of dynamic routing, keep it for + // remote-submix and legacy + sp desc; + if (requestedDevice == nullptr && + mPolicyMixes.getOutputForAttr(*resultAttr, uid, desc) == NO_ERROR) { + ALOG_ASSERT(desc != 0, "Invalid desc returned by getOutputForAttr"); + if (!audio_has_proportional_frames(config->format)) { return BAD_VALUE; } - deviceType = getDeviceForStrategy(strategy, false /*fromCache*/); + *output = desc->mIoHandle; + AudioMix *mix = desc->mPolicyMix; + sp deviceDesc = + mAvailableOutputDevices.getDevice(mix->mDeviceType, + mix->mDeviceAddress, + AUDIO_FORMAT_DEFAULT); + *selectedDeviceId = deviceDesc != 0 ? deviceDesc->getId() : AUDIO_PORT_HANDLE_NONE; + ALOGV("getOutputForAttr() returns output %d", *output); + return NO_ERROR; } + // Virtual sources must always be dynamicaly or explicitly routed + if (resultAttr->usage == AUDIO_USAGE_VIRTUAL_SOURCE) { + ALOGW("getOutputForAttr() no policy mix found for usage AUDIO_USAGE_VIRTUAL_SOURCE"); + return BAD_VALUE; + } + // explicit routing managed by getDeviceForStrategy in APM is now handled by engine + // in order to let the choice of the order to future vendor engine + outputDevices = mEngine->getOutputDevicesForAttributes(*resultAttr, requestedDevice, false); if ((resultAttr->flags & AUDIO_FLAG_HW_AV_SYNC) != 0) { *flags = (audio_output_flags_t)(*flags | AUDIO_OUTPUT_FLAG_HW_AV_SYNC); @@ -982,45 +974,40 @@ status_t AudioPolicyManager::getOutputForAttrInt(audio_attributes_t *resultAttr, // FIXME: provide a more generic approach which is not device specific and move this back // to getOutputForDevice. // TODO: Remove check of AUDIO_STREAM_MUSIC once migration is completed on the app side. - if (deviceType == AUDIO_DEVICE_OUT_TELEPHONY_TX && - (*stream == AUDIO_STREAM_MUSIC || resultAttr->usage == AUDIO_USAGE_VOICE_COMMUNICATION) && + if (outputDevices.types() == AUDIO_DEVICE_OUT_TELEPHONY_TX && + (*stream == AUDIO_STREAM_MUSIC || resultAttr->usage == AUDIO_USAGE_VOICE_COMMUNICATION) && audio_is_linear_pcm(config->format) && isInCall()) { if (requestedPortId != AUDIO_PORT_HANDLE_NONE) { *flags = (audio_output_flags_t)AUDIO_OUTPUT_FLAG_INCALL_MUSIC; - } else { - // Get the devce type directly from the engine to bypass preferred route logic - deviceType = mEngine->getDeviceForStrategy(strategy); + // @todo: provide another solution (separated CL) } } - ALOGV("%s device 0x%x, sampling rate %d, format %#x, channel mask %#x, " - "flags %#x", - __func__, - deviceType, config->sample_rate, config->format, config->channel_mask, *flags); + ALOGV("%s() device %s, sampling rate %d, format %#x, channel mask %#x, flags %#x stream %s", + __func__, outputDevices.toString().c_str(), config->sample_rate, config->format, + config->channel_mask, *flags, toString(*stream).c_str()); *output = AUDIO_IO_HANDLE_NONE; if (!msdDevices.isEmpty()) { *output = getOutputForDevices(msdDevices, session, *stream, config, flags); - sp deviceDesc = - mAvailableOutputDevices.getDevice(deviceType, String8(), AUDIO_FORMAT_DEFAULT); - if (*output != AUDIO_IO_HANDLE_NONE && setMsdPatch(deviceDesc) == NO_ERROR) { - ALOGV("%s() Using MSD devices %s instead of device %s", - __func__, msdDevices.toString().c_str(), deviceDesc->toString().c_str()); - deviceType = msdDevices.types(); + sp device = outputDevices.isEmpty() ? nullptr : outputDevices.itemAt(0); + if (*output != AUDIO_IO_HANDLE_NONE && setMsdPatch(device) == NO_ERROR) { + ALOGV("%s() Using MSD devices %s instead of devices %s", + __func__, msdDevices.toString().c_str(), outputDevices.toString().c_str()); + outputDevices = msdDevices; } else { *output = AUDIO_IO_HANDLE_NONE; } } - devices = mAvailableOutputDevices.getDevicesFromTypeMask(deviceType); if (*output == AUDIO_IO_HANDLE_NONE) { - *output = getOutputForDevices(devices, session, *stream, config, flags); + *output = getOutputForDevices(outputDevices, session, *stream, config, flags); } if (*output == AUDIO_IO_HANDLE_NONE) { return INVALID_OPERATION; } - *selectedDeviceId = getFirstDeviceId(devices); + *selectedDeviceId = getFirstDeviceId(outputDevices); ALOGV("%s returns output %d selectedDeviceId %d", __func__, *output, *selectedDeviceId); @@ -1057,13 +1044,13 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr, sp clientDesc = new TrackClientDescriptor(*portId, uid, session, resultAttr, clientConfig, requestedPortId, *stream, - getStrategyForAttr(&resultAttr), + mEngine->getProductStrategyForAttributes(resultAttr), *flags); sp outputDesc = mOutputs.valueFor(*output); outputDesc->addClient(clientDesc); - ALOGV("%s returns output %d selectedDeviceId %d for port ID %d", - __func__, *output, requestedPortId, *portId); + ALOGV("%s() returns output %d selectedDeviceId %d for port ID %d", __func__, + *output, *selectedDeviceId, *portId); return NO_ERROR; } @@ -1368,7 +1355,8 @@ status_t AudioPolicyManager::setMsdPatch(const sp &outputDevic // Use media strategy for unspecified output device. This should only // occur on checkForDeviceAndOutputChanges(). Device connection events may // therefore invalidate explicit routing requests. - DeviceVector devices = getDevicesForStrategy(STRATEGY_MEDIA, false /*fromCache*/); + DeviceVector devices = mEngine->getOutputDevicesForAttributes( + attributes_initializer(AUDIO_USAGE_MEDIA), nullptr, false /*fromCache*/); LOG_ALWAYS_FATAL_IF(devices.isEmpty(), "no outpudevice to set Msd Patch"); device = devices.itemAt(0); } @@ -1547,6 +1535,8 @@ status_t AudioPolicyManager::startSource(const sp& outp *delayMs = 0; audio_stream_type_t stream = client->stream(); + auto clientStrategy = client->strategy(); + auto clientAttr = client->attributes(); if (stream == AUDIO_STREAM_TTS) { ALOGV("\t found BEACON stream"); if (!mTtsOutputAvailable && mOutputs.isAnyOutputActive(AUDIO_STREAM_TTS /*streamToIgnore*/)) { @@ -1594,11 +1584,11 @@ status_t AudioPolicyManager::startSource(const sp& outp if (client->hasPreferredDevice(true)) { devices = getNewOutputDevices(outputDesc, false /*fromCache*/); if (devices != outputDesc->devices()) { - checkStrategyRoute(getStrategy(stream), outputDesc->mIoHandle); + checkStrategyRoute(clientStrategy, outputDesc->mIoHandle); } } - if (stream == AUDIO_STREAM_MUSIC) { + if (followsSameRouting(clientAttr, attributes_initializer(AUDIO_USAGE_MEDIA))) { selectOutputForMusicEffects(); } @@ -1607,11 +1597,10 @@ status_t AudioPolicyManager::startSource(const sp& outp if (devices.isEmpty()) { devices = getNewOutputDevices(outputDesc, false /*fromCache*/); } - - routing_strategy strategy = getStrategy(stream); - bool shouldWait = (strategy == STRATEGY_SONIFICATION) || - (strategy == STRATEGY_SONIFICATION_RESPECTFUL) || - (beaconMuteLatency > 0); + bool shouldWait = + (followsSameRouting(clientAttr, attributes_initializer(AUDIO_USAGE_ALARM)) || + followsSameRouting(clientAttr, attributes_initializer(AUDIO_USAGE_NOTIFICATION)) || + (beaconMuteLatency > 0)); uint32_t waitMs = beaconMuteLatency; for (size_t i = 0; i < mOutputs.size(); i++) { sp desc = mOutputs.valueAt(i); @@ -1666,7 +1655,7 @@ status_t AudioPolicyManager::startSource(const sp& outp handleNotificationRoutingForStream(stream); // force reevaluating accessibility routing when ringtone or alarm starts - if (strategy == STRATEGY_SONIFICATION) { + if (followsSameRouting(clientAttr, attributes_initializer(AUDIO_USAGE_ALARM))) { mpClientInterface->invalidateStream(AUDIO_STREAM_ACCESSIBILITY); } @@ -1685,7 +1674,7 @@ status_t AudioPolicyManager::startSource(const sp& outp if (stream == AUDIO_STREAM_ENFORCED_AUDIBLE && mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) { - setStrategyMute(STRATEGY_SONIFICATION, true, outputDesc); + setStrategyMute(streamToStrategy(AUDIO_STREAM_ALARM), true, outputDesc); } // Automatically enable the remote submix input when output is started on a re routing mix @@ -1747,7 +1736,7 @@ status_t AudioPolicyManager::stopSource(const sp& outpu } bool forceDeviceUpdate = false; if (client->hasPreferredDevice(true)) { - checkStrategyRoute(getStrategy(stream), AUDIO_IO_HANDLE_NONE); + checkStrategyRoute(client->strategy(), AUDIO_IO_HANDLE_NONE); forceDeviceUpdate = true; } @@ -1756,7 +1745,7 @@ status_t AudioPolicyManager::stopSource(const sp& outpu // store time at which the stream was stopped - see isStreamActive() if (outputDesc->streamActiveCount(stream) == 0 || forceDeviceUpdate) { - outputDesc->mStopTime[stream] = systemTime(); + outputDesc->setStopTime(client, systemTime()); DeviceVector newDevices = getNewOutputDevices(outputDesc, false /*fromCache*/); // delay the device switch by twice the latency because stopOutput() is executed when // the track stop() command is received and at that time the audio track buffer can @@ -1791,10 +1780,10 @@ status_t AudioPolicyManager::stopSource(const sp& outpu if (stream == AUDIO_STREAM_ENFORCED_AUDIBLE && mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) { - setStrategyMute(STRATEGY_SONIFICATION, false, outputDesc); + setStrategyMute(streamToStrategy(AUDIO_STREAM_RING), false, outputDesc); } - if (stream == AUDIO_STREAM_MUSIC) { + if (followsSameRouting(client->attributes(), attributes_initializer(AUDIO_USAGE_MEDIA))) { selectOutputForMusicEffects(); } return NO_ERROR; @@ -1849,9 +1838,9 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, input_type_t *inputType, audio_port_handle_t *portId) { - ALOGV("getInputForAttr() source %d, sampling rate %d, format %#x, channel mask %#x," - "session %d, flags %#x", - attr->source, config->sample_rate, config->format, config->channel_mask, session, flags); + ALOGV("%s() source %d, sampling rate %d, format %#x, channel mask %#x, session %d, " + "flags %#x attributes=%s", __func__, attr->source, config->sample_rate, + config->format, config->channel_mask, session, flags, toString(*attr).c_str()); status_t status = NO_ERROR; audio_source_t halInputSource; @@ -1940,7 +1929,7 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, if (explicitRoutingDevice != nullptr) { device = explicitRoutingDevice; } else { - device = getDeviceAndMixForAttributes(attributes, &policyMix); + device = mEngine->getInputDeviceForAttributes(attributes, &policyMix); } if (device == nullptr) { ALOGW("getInputForAttr() could not find device for source %d", attributes.source); @@ -1954,8 +1943,6 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, // know about it and is therefore considered "legacy" *inputType = API_INPUT_LEGACY; } else if (audio_is_remote_submix_device(device->type())) { - device = mAvailableInputDevices.getDevice(AUDIO_DEVICE_IN_REMOTE_SUBMIX, String8("0"), - AUDIO_FORMAT_DEFAULT); *inputType = API_INPUT_MIX_CAPTURE; } else if (device->type() == AUDIO_DEVICE_IN_TELEPHONY_RX) { *inputType = API_INPUT_TELEPHONY_RX; @@ -1965,9 +1952,7 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, } - *input = getInputForDevice(device, session, attributes.source, - config, flags, - policyMix); + *input = getInputForDevice(device, session, attributes, config, flags, policyMix); if (*input == AUDIO_IO_HANDLE_NONE) { status = INVALID_OPERATION; goto error; @@ -1975,8 +1960,8 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, exit: - *selectedDeviceId = mAvailableInputDevices.contains(device) ? - device->getId() : AUDIO_PORT_HANDLE_NONE; + *selectedDeviceId = mAvailableInputDevices.contains(device) ? + device->getId() : AUDIO_PORT_HANDLE_NONE; isSoundTrigger = attributes.source == AUDIO_SOURCE_HOTWORD && mSoundTriggerSessions.indexOfKey(session) > 0; @@ -2000,16 +1985,16 @@ error: audio_io_handle_t AudioPolicyManager::getInputForDevice(const sp &device, audio_session_t session, - audio_source_t inputSource, + const audio_attributes_t &attributes, const audio_config_base_t *config, audio_input_flags_t flags, AudioMix *policyMix) { audio_io_handle_t input = AUDIO_IO_HANDLE_NONE; - audio_source_t halInputSource = inputSource; + audio_source_t halInputSource = attributes.source; bool isSoundTrigger = false; - if (inputSource == AUDIO_SOURCE_HOTWORD) { + if (attributes.source == AUDIO_SOURCE_HOTWORD) { ssize_t index = mSoundTriggerSessions.indexOfKey(session); if (index >= 0) { input = mSoundTriggerSessions.valueFor(session); @@ -2019,7 +2004,7 @@ audio_io_handle_t AudioPolicyManager::getInputForDevice(const spformat)) { flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_VOIP_TX); } @@ -2374,10 +2359,10 @@ status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream, // update volume on all outputs and streams matching the following: // - The requested stream (or a stream matching for volume control) is active on the output - // - The device (or devices) selected by the strategy corresponding to this stream includes + // - The device (or devices) selected by the engine for this stream includes // the requested device // - For non default requested device, currently selected device on the output is either the - // requested device or one of the devices selected by the strategy + // requested device or one of the devices selected by the engine for this stream // - For default requested device (AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME), apply volume only if // no specific device volume value exists for currently selected device. status_t status = NO_ERROR; @@ -2391,9 +2376,9 @@ status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream, if (!(desc->isStreamActive((audio_stream_type_t)curStream) || isInCall())) { continue; } - routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream); - audio_devices_t curStreamDevice = Volume::getDeviceForVolume(getDeviceForStrategy( - curStrategy, false /*fromCache*/)); + audio_devices_t curStreamDevice = Volume::getDeviceForVolume( + mEngine->getOutputDevicesForStream((audio_stream_type_t)curStream, + false /*fromCache*/).types()); if ((device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) && ((curStreamDevice & device) == 0)) { continue; @@ -2435,10 +2420,10 @@ status_t AudioPolicyManager::getStreamVolumeIndex(audio_stream_type_t stream, if (!audio_is_output_device(device)) { return BAD_VALUE; } - // if device is AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME, return volume for device corresponding to - // the strategy the stream belongs to. + // if device is AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME, return volume for device selected for this + // stream by the engine. if (device == AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) { - device = getDeviceForStrategy(getStrategy(stream), true /*fromCache*/); + device = mEngine->getOutputDevicesForStream(stream, true /*fromCache*/).types(); } device = Volume::getDeviceForVolume(device); @@ -2458,8 +2443,8 @@ audio_io_handle_t AudioPolicyManager::selectOutputForMusicEffects() // 3: The primary output // 4: the first output in the list - routing_strategy strategy = getStrategy(AUDIO_STREAM_MUSIC); - DeviceVector devices = getDevicesForStrategy(strategy, false /*fromCache*/); + DeviceVector devices = mEngine->getOutputDevicesForAttributes( + attributes_initializer(AUDIO_USAGE_MEDIA), nullptr, false /*fromCache*/); SortedVector outputs = getOutputsForDevices(devices, mOutputs); if (outputs.size() == 0) { @@ -2531,7 +2516,9 @@ status_t AudioPolicyManager::registerEffect(const effect_descriptor_t *desc, return INVALID_OPERATION; } } - return mEffects.registerEffect(desc, io, strategy, session, id); + return mEffects.registerEffect(desc, io, session, id, + (strategy == streamToStrategy(AUDIO_STREAM_MUSIC) || + strategy == PRODUCT_STRATEGY_NONE)); } status_t AudioPolicyManager::unregisterEffect(int id) @@ -2870,6 +2857,9 @@ void AudioPolicyManager::dump(String8 *dst) const mAudioPatches.dump(dst); mPolicyMixes.dump(dst); mAudioSources.dump(dst); + + dst->appendFormat("\nPolicy Engine dump:\n"); + mEngine->dump(dst); } status_t AudioPolicyManager::dump(int fd) @@ -3461,27 +3451,27 @@ void AudioPolicyManager::clearAudioPatches(uid_t uid) } } -void AudioPolicyManager::checkStrategyRoute(routing_strategy strategy, - audio_io_handle_t ouptutToSkip) +void AudioPolicyManager::checkStrategyRoute(product_strategy_t ps, audio_io_handle_t ouptutToSkip) { - DeviceVector devices = getDevicesForStrategy(strategy, false /*fromCache*/); + // Take the first attributes following the product strategy as it is used to retrieve the routed + // device. All attributes wihin a strategy follows the same "routing strategy" + auto attributes = mEngine->getAllAttributesForProductStrategy(ps).front(); + DeviceVector devices = mEngine->getOutputDevicesForAttributes(attributes, nullptr, false); SortedVector outputs = getOutputsForDevices(devices, mOutputs); for (size_t j = 0; j < mOutputs.size(); j++) { if (mOutputs.keyAt(j) == ouptutToSkip) { continue; } sp outputDesc = mOutputs.valueAt(j); - if (!isStrategyActive(outputDesc, (routing_strategy)strategy)) { + if (!outputDesc->isStrategyActive(ps)) { continue; } // If the default device for this strategy is on another output mix, // invalidate all tracks in this strategy to force re connection. // Otherwise select new device on the output mix. if (outputs.indexOf(mOutputs.keyAt(j)) < 0) { - for (int stream = 0; stream < AUDIO_STREAM_FOR_POLICY_CNT; stream++) { - if (getStrategy((audio_stream_type_t)stream) == strategy) { - mpClientInterface->invalidateStream((audio_stream_type_t)stream); - } + for (auto stream : mEngine->getStreamTypesForProductStrategy(ps)) { + mpClientInterface->invalidateStream(stream); } } else { setOutputDevices( @@ -3493,13 +3483,18 @@ void AudioPolicyManager::checkStrategyRoute(routing_strategy strategy, void AudioPolicyManager::clearSessionRoutes(uid_t uid) { // remove output routes associated with this uid - SortedVector affectedStrategies; + std::vector affectedStrategies; for (size_t i = 0; i < mOutputs.size(); i++) { sp outputDesc = mOutputs.valueAt(i); for (const auto& client : outputDesc->getClientIterable()) { if (client->hasPreferredDevice() && client->uid() == uid) { client->setPreferredDeviceId(AUDIO_PORT_HANDLE_NONE); - affectedStrategies.add(getStrategy(client->stream())); + auto clientStrategy = client->strategy(); + if (std::find(begin(affectedStrategies), end(affectedStrategies), clientStrategy) != + end(affectedStrategies)) { + continue; + } + affectedStrategies.push_back(client->strategy()); } } } @@ -3549,7 +3544,7 @@ status_t AudioPolicyManager::acquireSoundTriggerSession(audio_session_t *session *session = (audio_session_t)mpClientInterface->newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION); *ioHandle = (audio_io_handle_t)mpClientInterface->newAudioUniqueId(AUDIO_UNIQUE_ID_USE_INPUT); audio_attributes_t attr = { .source = AUDIO_SOURCE_HOTWORD }; - *device = getDeviceAndMixForAttributes(attr)->type(); + *device = mEngine->getInputDeviceForAttributes(attr)->type(); return mSoundTriggerSessions.acquireSession(*session, *ioHandle); } @@ -3591,8 +3586,8 @@ status_t AudioPolicyManager::startAudioSource(const struct audio_port_config *so sp sourceDesc = new SourceClientDescriptor(*portId, uid, *attributes, patchDesc, srcDevice, - streamTypefromAttributesInt(attributes), - getStrategyForAttr(attributes)); + mEngine->getStreamTypeForAttributes(*attributes), + mEngine->getProductStrategyForAttributes(*attributes)); status_t status = connectAudioSource(sourceDesc); if (status == NO_ERROR) { @@ -3609,12 +3604,12 @@ status_t AudioPolicyManager::connectAudioSource(const sp disconnectAudioSource(sourceDesc); audio_attributes_t attributes = sourceDesc->attributes(); - routing_strategy strategy = getStrategyForAttr(&attributes); audio_stream_type_t stream = sourceDesc->stream(); sp srcDevice = sourceDesc->srcDevice(); - DeviceVector sinkDevices = getDevicesForStrategy(strategy, true); - ALOG_ASSERT(!sinkDevices.isEmpty(), "connectAudioSource(): no device found for strategy"); + DeviceVector sinkDevices = + mEngine->getOutputDevicesForAttributes(attributes, nullptr, true); + ALOG_ASSERT(!sinkDevices.isEmpty(), "connectAudioSource(): no device found for attributes"); sp sinkDevice = sinkDevices.itemAt(0); ALOG_ASSERT(mAvailableOutputDevices.contains(sinkDevice), "%s: Device %s not available", __FUNCTION__, sinkDevice->toString().c_str()); @@ -3968,16 +3963,15 @@ status_t AudioPolicyManager::disconnectAudioSource(const sp AudioPolicyManager::getSourceForStrategyOnOutput( - audio_io_handle_t output, routing_strategy strategy) +sp AudioPolicyManager::getSourceForAttributesOnOutput( + audio_io_handle_t output, const audio_attributes_t &attr) { sp source; for (size_t i = 0; i < mAudioSources.size(); i++) { sp sourceDesc = mAudioSources.valueAt(i); - audio_attributes_t attributes = sourceDesc->attributes(); - routing_strategy sourceStrategy = getStrategyForAttr(&attributes); sp outputDesc = sourceDesc->swOutput().promote(); - if (sourceStrategy == strategy && outputDesc != 0 && outputDesc->mIoHandle == output) { + if (followsSameRouting(attr, sourceDesc->attributes()) && + outputDesc != 0 && outputDesc->mIoHandle == output) { source = sourceDesc; break; } @@ -4792,16 +4786,25 @@ void AudioPolicyManager::checkForDeviceAndOutputChanges(std::function on } } -void AudioPolicyManager::checkOutputForStrategy(routing_strategy strategy) +bool AudioPolicyManager::followsSameRouting(const audio_attributes_t &lAttr, + const audio_attributes_t &rAttr) const { - DeviceVector oldDevices = getDevicesForStrategy(strategy, true /*fromCache*/); - DeviceVector newDevices = getDevicesForStrategy(strategy, false /*fromCache*/); + return mEngine->getProductStrategyForAttributes(lAttr) == + mEngine->getProductStrategyForAttributes(rAttr); +} + +void AudioPolicyManager::checkOutputForAttributes(const audio_attributes_t &attr) +{ + auto psId = mEngine->getProductStrategyForAttributes(attr); + + DeviceVector oldDevices = mEngine->getOutputDevicesForAttributes(attr, 0, true /*fromCache*/); + DeviceVector newDevices = mEngine->getOutputDevicesForAttributes(attr, 0, false /*fromCache*/); SortedVector srcOutputs = getOutputsForDevices(oldDevices, mPreviousOutputs); SortedVector dstOutputs = getOutputsForDevices(newDevices, mOutputs); // also take into account external policy-related changes: add all outputs which are // associated with policies in the "before" and "after" output vectors - ALOGVV("checkOutputForStrategy(): policy related outputs"); + ALOGVV("%s(): policy related outputs", __func__); for (size_t i = 0 ; i < mPreviousOutputs.size() ; i++) { const sp desc = mPreviousOutputs.valueAt(i); if (desc != 0 && desc->mPolicyMix != NULL) { @@ -4817,7 +4820,7 @@ void AudioPolicyManager::checkOutputForStrategy(routing_strategy strategy) } } - if (!dstOutputs.isEmpty() && srcOutputs != dstOutputs) { + if (srcOutputs != dstOutputs) { // get maximum latency of all source outputs to determine the minimum mute time guaranteeing // audio from invalidated tracks will be rendered when unmuting uint32_t maxLatency = 0; @@ -4828,50 +4831,40 @@ void AudioPolicyManager::checkOutputForStrategy(routing_strategy strategy) } } ALOGV_IF(!(srcOutputs.isEmpty() || dstOutputs.isEmpty()), - "%s: strategy %d, moving from output %s to output %s", __func__, strategy, + "%s: strategy %d, moving from output %s to output %s", __func__, psId, std::to_string(srcOutputs[0]).c_str(), std::to_string(dstOutputs[0]).c_str()); // mute strategy while moving tracks from one output to another for (audio_io_handle_t srcOut : srcOutputs) { sp desc = mPreviousOutputs.valueFor(srcOut); - if (desc != 0 && isStrategyActive(desc, strategy)) { - setStrategyMute(strategy, true, desc); - setStrategyMute(strategy, false, desc, maxLatency * LATENCY_MUTE_FACTOR, + if (desc != 0 && desc->isStrategyActive(psId)) { + setStrategyMute(psId, true, desc); + setStrategyMute(psId, false, desc, maxLatency * LATENCY_MUTE_FACTOR, newDevices.types()); } - sp source = - getSourceForStrategyOnOutput(srcOut, strategy); + sp source = getSourceForAttributesOnOutput(srcOut, attr); if (source != 0){ connectAudioSource(source); } } - // Move effects associated to this strategy from previous output to new output - if (strategy == STRATEGY_MEDIA) { + // Move effects associated to this stream from previous output to new output + if (followsSameRouting(attr, attributes_initializer(AUDIO_USAGE_MEDIA))) { selectOutputForMusicEffects(); } - // Move tracks associated to this strategy from previous output to new output - for (int i = 0; i < AUDIO_STREAM_FOR_POLICY_CNT; i++) { - if (getStrategy((audio_stream_type_t)i) == strategy) { - mpClientInterface->invalidateStream((audio_stream_type_t)i); - } + // Move tracks associated to this stream (and linked) from previous output to new output + for (auto stream : mEngine->getStreamTypesForProductStrategy(psId)) { + mpClientInterface->invalidateStream(stream); } } } void AudioPolicyManager::checkOutputForAllStrategies() { - if (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) - checkOutputForStrategy(STRATEGY_ENFORCED_AUDIBLE); - checkOutputForStrategy(STRATEGY_PHONE); - if (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) != AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) - checkOutputForStrategy(STRATEGY_ENFORCED_AUDIBLE); - checkOutputForStrategy(STRATEGY_SONIFICATION); - checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL); - checkOutputForStrategy(STRATEGY_ACCESSIBILITY); - checkOutputForStrategy(STRATEGY_MEDIA); - checkOutputForStrategy(STRATEGY_DTMF); - checkOutputForStrategy(STRATEGY_REROUTING); + for (const auto &strategy : mEngine->getOrderedProductStrategies()) { + auto attributes = mEngine->getAllAttributesForProductStrategy(strategy).front(); + checkOutputForAttributes(attributes); + } } void AudioPolicyManager::checkA2dpSuspend() @@ -4924,38 +4917,6 @@ void AudioPolicyManager::checkA2dpSuspend() } } -template -sp AudioPolicyManager::findPreferredDevice( - IoDescriptor& desc, Filter filter, bool& active, const DeviceVector& devices) -{ - auto activeClients = desc->clientsList(true /*activeOnly*/); - auto activeClientsWithRoute = - desc->clientsList(true /*activeOnly*/, filter, true /*preferredDevice*/); - active = activeClients.size() > 0; - if (active && activeClients.size() == activeClientsWithRoute.size()) { - return devices.getDeviceFromId(activeClientsWithRoute[0]->preferredDeviceId()); - } - return nullptr; -} - -template -sp AudioPolicyManager::findPreferredDevice( - IoCollection& ioCollection, Filter filter, const DeviceVector& devices) -{ - sp device; - for (size_t i = 0; i < ioCollection.size(); i++) { - auto desc = ioCollection.valueAt(i); - bool active; - sp curDevice = findPreferredDevice(desc, filter, active, devices); - if (active && curDevice == nullptr) { - return nullptr; - } else if (curDevice != nullptr) { - device = curDevice; - } - } - return device; -} - DeviceVector AudioPolicyManager::getNewOutputDevices(const sp& outputDesc, bool fromCache) { @@ -4975,7 +4936,7 @@ DeviceVector AudioPolicyManager::getNewOutputDevices(const sp device = - findPreferredDevice(outputDesc, STRATEGY_NONE, active, mAvailableOutputDevices); + findPreferredDevice(outputDesc, PRODUCT_STRATEGY_NONE, active, mAvailableOutputDevices); if (device != nullptr) { return DeviceVector(device); } @@ -4987,54 +4948,22 @@ DeviceVector AudioPolicyManager::getNewOutputDevices(const spgetForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) { - devices = getDevicesForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache); - } else if (isInCall() || - isStrategyActiveOnSameModule(outputDesc, STRATEGY_PHONE)) { - devices = getDevicesForStrategy(STRATEGY_PHONE, fromCache); - } else if (isStrategyActiveOnSameModule(outputDesc, STRATEGY_SONIFICATION)) { - devices = getDevicesForStrategy(STRATEGY_SONIFICATION, fromCache); - } else if (isStrategyActive(outputDesc, STRATEGY_ENFORCED_AUDIBLE)) { - devices = getDevicesForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache); - } else if (isStrategyActive(outputDesc, STRATEGY_ACCESSIBILITY)) { - devices = getDevicesForStrategy(STRATEGY_ACCESSIBILITY, fromCache); - } else if (isStrategyActive(outputDesc, STRATEGY_SONIFICATION_RESPECTFUL)) { - devices = getDevicesForStrategy(STRATEGY_SONIFICATION_RESPECTFUL, fromCache); - } else if (isStrategyActive(outputDesc, STRATEGY_MEDIA)) { - devices = getDevicesForStrategy(STRATEGY_MEDIA, fromCache); - } else if (isStrategyActive(outputDesc, STRATEGY_DTMF)) { - devices = getDevicesForStrategy(STRATEGY_DTMF, fromCache); - } else if (isStrategyActive(outputDesc, STRATEGY_TRANSMITTED_THROUGH_SPEAKER)) { - devices = getDevicesForStrategy(STRATEGY_TRANSMITTED_THROUGH_SPEAKER, fromCache); - } else if (isStrategyActive(outputDesc, STRATEGY_REROUTING)) { - devices = getDevicesForStrategy(STRATEGY_REROUTING, fromCache); - } - - ALOGV("getNewOutputDevice() selected devices %s", devices.toString().c_str()); + for (const auto &productStrategy : mEngine->getOrderedProductStrategies()) { + StreamTypeVector streams = mEngine->getStreamTypesForProductStrategy(productStrategy); + auto attr = mEngine->getAllAttributesForProductStrategy(productStrategy).front(); + + if ((hasVoiceStream(streams) && + (isInCall() || mOutputs.isStrategyActiveOnSameModule(productStrategy, outputDesc))) || + (hasStream(streams, AUDIO_STREAM_ALARM) && + mOutputs.isStrategyActiveOnSameModule(productStrategy, outputDesc)) || + outputDesc->isStrategyActive(productStrategy)) { + // Retrieval of devices for voice DL is done on primary output profile, cannot + // check the route (would force modifying configuration file for this profile) + devices = mEngine->getOutputDevicesForAttributes(attr, nullptr, fromCache); + break; + } + } + ALOGV("%s selected devices %s", __func__, devices.toString().c_str()); return devices; } @@ -5068,7 +4997,7 @@ sp AudioPolicyManager::getNewInputDevice( attributes.source = AUDIO_SOURCE_VOICE_COMMUNICATION; } if (attributes.source != AUDIO_SOURCE_DEFAULT) { - device = getDeviceAndMixForAttributes(attributes); + device = mEngine->getInputDeviceForAttributes(attributes); } return device; @@ -5079,26 +5008,22 @@ bool AudioPolicyManager::streamsMatchForvolume(audio_stream_type_t stream1, return (stream1 == stream2); } -uint32_t AudioPolicyManager::getStrategyForStream(audio_stream_type_t stream) { - return (uint32_t)getStrategy(stream); -} - audio_devices_t AudioPolicyManager::getDevicesForStream(audio_stream_type_t stream) { // By checking the range of stream before calling getStrategy, we avoid - // getStrategy's behavior for invalid streams. getStrategy would do a ALOGE - // and then return STRATEGY_MEDIA, but we want to return the empty set. - if (stream < (audio_stream_type_t) 0 || stream >= AUDIO_STREAM_PUBLIC_CNT) { + // getOutputDevicesForStream's behavior for invalid streams. + // engine's getOutputDevicesForStream would fallback on its default behavior (most probably + // device for music stream), but we want to return the empty set. + if (stream < AUDIO_STREAM_MIN || stream >= AUDIO_STREAM_PUBLIC_CNT) { return AUDIO_DEVICE_NONE; } DeviceVector activeDevices; DeviceVector devices; - for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) { - if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) { + for (audio_stream_type_t curStream = AUDIO_STREAM_MIN; curStream < AUDIO_STREAM_PUBLIC_CNT; + curStream = (audio_stream_type_t) (curStream + 1)) { + if (!streamsMatchForvolume(stream, curStream)) { continue; } - routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream); - DeviceVector curDevices = - getDevicesForStrategy((routing_strategy)curStrategy, false /*fromCache*/); + DeviceVector curDevices = mEngine->getOutputDevicesForStream(curStream, false/*fromCache*/); devices.merge(curDevices); for (audio_io_handle_t output : getOutputsForDevices(curDevices, mOutputs)) { sp outputDesc = mOutputs.valueFor(output); @@ -5123,28 +5048,10 @@ audio_devices_t AudioPolicyManager::getDevicesForStream(audio_stream_type_t stre return devices.types(); } -routing_strategy AudioPolicyManager::getStrategy(audio_stream_type_t stream) const -{ - ALOG_ASSERT(stream != AUDIO_STREAM_PATCH,"getStrategy() called for AUDIO_STREAM_PATCH"); - return mEngine->getStrategyForStream(stream); -} - -routing_strategy AudioPolicyManager::getStrategyForAttr(const audio_attributes_t *attr) { - // flags to strategy mapping - if ((attr->flags & AUDIO_FLAG_BEACON) == AUDIO_FLAG_BEACON) { - return STRATEGY_TRANSMITTED_THROUGH_SPEAKER; - } - if ((attr->flags & AUDIO_FLAG_AUDIBILITY_ENFORCED) == AUDIO_FLAG_AUDIBILITY_ENFORCED) { - return STRATEGY_ENFORCED_AUDIBLE; - } - // usage to strategy mapping - return mEngine->getStrategyForUsage(attr->usage); -} - void AudioPolicyManager::handleNotificationRoutingForStream(audio_stream_type_t stream) { switch(stream) { case AUDIO_STREAM_MUSIC: - checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL); + checkOutputForAttributes(attributes_initializer(AUDIO_USAGE_NOTIFICATION)); updateDevicesAndOutputs(); break; default: @@ -5211,33 +5118,14 @@ uint32_t AudioPolicyManager::setBeaconMute(bool mute) { return 0; } -DeviceVector AudioPolicyManager::getDevicesForStrategy(routing_strategy strategy, bool fromCache) -{ - // Honor explicit routing requests only if all active clients have a preferred route in which - // case the last active client route is used - sp device = findPreferredDevice(mOutputs, strategy, mAvailableOutputDevices); - if (device != nullptr) { - return DeviceVector(device); - } - - if (fromCache) { - ALOGVV("%s from cache strategy %d, device %s", __func__, strategy, - mDevicesForStrategy[strategy].toString().c_str()); - return mDevicesForStrategy[strategy]; - } - return mAvailableOutputDevices.getDevicesFromTypeMask(mEngine->getDeviceForStrategy(strategy)); -} - void AudioPolicyManager::updateDevicesAndOutputs() { - for (int i = 0; i < NUM_STRATEGIES; i++) { - mDevicesForStrategy[i] = getDevicesForStrategy((routing_strategy)i, false /*fromCache*/); - } + mEngine->updateDeviceSelectionCache(); mPreviousOutputs = mOutputs; } uint32_t AudioPolicyManager::checkDeviceMuteStrategies(const sp& outputDesc, - audio_devices_t prevDeviceType, + const DeviceVector &prevDevices, uint32_t delayMs) { // mute/unmute strategies using an incompatible device combination @@ -5248,22 +5136,24 @@ uint32_t AudioPolicyManager::checkDeviceMuteStrategies(const spdevices().types(); - bool shouldMute = outputDesc->isActive() && (popcount(deviceType) >= 2); - - for (size_t i = 0; i < NUM_STRATEGIES; i++) { - audio_devices_t curDeviceType = - getDeviceForStrategy((routing_strategy)i, false /*fromCache*/); - curDeviceType = curDeviceType & outputDesc->supportedDevices().types(); - bool mute = shouldMute && (curDeviceType & deviceType) && (curDeviceType != deviceType); + DeviceVector devices = outputDesc->devices(); + bool shouldMute = outputDesc->isActive() && (devices.size() >= 2); + + auto productStrategies = mEngine->getOrderedProductStrategies(); + for (const auto &productStrategy : productStrategies) { + auto attributes = mEngine->getAllAttributesForProductStrategy(productStrategy).front(); + DeviceVector curDevices = + mEngine->getOutputDevicesForAttributes(attributes, nullptr, false/*fromCache*/); + curDevices = curDevices.filter(outputDesc->supportedDevices()); + bool mute = shouldMute && curDevices.containsAtLeastOne(devices) && curDevices != devices; bool doMute = false; - if (mute && !outputDesc->mStrategyMutedByDevice[i]) { + if (mute && !outputDesc->isStrategyMutedByDevice(productStrategy)) { doMute = true; - outputDesc->mStrategyMutedByDevice[i] = true; - } else if (!mute && outputDesc->mStrategyMutedByDevice[i]){ + outputDesc->setStrategyMutedByDevice(productStrategy, true); + } else if (!mute && outputDesc->isStrategyMutedByDevice(productStrategy)) { doMute = true; - outputDesc->mStrategyMutedByDevice[i] = false; + outputDesc->setStrategyMutedByDevice(productStrategy, false); } if (doMute) { for (size_t j = 0; j < mOutputs.size(); j++) { @@ -5272,10 +5162,10 @@ uint32_t AudioPolicyManager::checkDeviceMuteStrategies(const spsupportedDevices().containsAtLeastOne(outputDesc->supportedDevices())) { continue; } - ALOGVV("checkDeviceMuteStrategies() %s strategy %zu (curDevice %04x)", - mute ? "muting" : "unmuting", i, curDeviceType); - setStrategyMute((routing_strategy)i, mute, desc, mute ? 0 : delayMs); - if (isStrategyActive(desc, (routing_strategy)i)) { + ALOGVV("%s() %s (curDevice %s)", __func__, + mute ? "muting" : "unmuting", curDevices.toString().c_str()); + setStrategyMute(productStrategy, mute, desc, mute ? 0 : delayMs); + if (desc->isStrategyActive(productStrategy)) { if (mute) { // FIXME: should not need to double latency if volume could be applied // immediately by the audioflinger mixer. We must account for the delay @@ -5293,7 +5183,7 @@ uint32_t AudioPolicyManager::checkDeviceMuteStrategies(const spisActive() && (deviceType != prevDeviceType)) { + if (outputDesc->isActive() && (devices != prevDevices)) { uint32_t tempMuteWaitMs = outputDesc->latency() * 2; // temporary mute duration is conservatively set to 4 times the reported latency uint32_t tempMuteDurationMs = outputDesc->latency() * 4; @@ -5301,13 +5191,13 @@ uint32_t AudioPolicyManager::checkDeviceMuteStrategies(const spisStrategyActive(productStrategy)) { // make sure that we do not start the temporary mute period too early in case of // delayed device change - setStrategyMute((routing_strategy)i, true, outputDesc, delayMs); - setStrategyMute((routing_strategy)i, false, outputDesc, - delayMs + tempMuteDurationMs, deviceType); + setStrategyMute(productStrategy, true, outputDesc, delayMs); + setStrategyMute(productStrategy, false, outputDesc, delayMs + tempMuteDurationMs, + devices.types()); } } } @@ -5359,7 +5249,7 @@ uint32_t AudioPolicyManager::setOutputDevices(const sp& // if the outputs are not materially active, there is no need to mute. if (requiresMuteCheck) { - muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevices.types(), delayMs); + muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevices, delayMs); } else { ALOGV("%s: suppressing checkDeviceMuteStrategies", __func__); muteWaitMs = 0; @@ -5531,36 +5421,6 @@ sp AudioPolicyManager::getInputProfile(const sp &de return NULL; } -sp AudioPolicyManager::getDeviceAndMixForAttributes( - const audio_attributes_t &attributes, AudioMix **policyMix) -{ - // Honor explicit routing requests only if all active clients have a preferred route in which - // case the last active client route is used - sp device = - findPreferredDevice(mInputs, attributes.source, mAvailableInputDevices); - if (device != nullptr) { - return device; - } - - sp selectedDeviceFromMix = - mPolicyMixes.getDeviceAndMixForInputSource(attributes.source, mAvailableInputDevices, - policyMix); - return (selectedDeviceFromMix != nullptr) ? - selectedDeviceFromMix : getDeviceForAttributes(attributes); -} - -sp AudioPolicyManager::getDeviceForAttributes(const audio_attributes_t &attributes) -{ - audio_devices_t device = mEngine->getDeviceForInputSource(attributes.source); - if (attributes.source == AUDIO_SOURCE_REMOTE_SUBMIX && - strncmp(attributes.tags, "addr=", strlen("addr=")) == 0) { - return mAvailableInputDevices.getDevice(AUDIO_DEVICE_IN_REMOTE_SUBMIX, - String8(attributes.tags + strlen("addr=")), - AUDIO_FORMAT_DEFAULT); - } - return mAvailableInputDevices.getDevice(device, String8(), AUDIO_FORMAT_DEFAULT); -} - float AudioPolicyManager::computeVolume(audio_stream_type_t stream, int index, audio_devices_t device) @@ -5613,18 +5473,18 @@ float AudioPolicyManager::computeVolume(audio_stream_type_t stream, // speaker is part of the select devices // - if music is playing, always limit the volume to current music volume, // with a minimum threshold at -36dB so that notification is always perceived. - const routing_strategy stream_strategy = getStrategy(stream); if ((device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE | AUDIO_DEVICE_OUT_USB_HEADSET | AUDIO_DEVICE_OUT_HEARING_AID)) && - ((stream_strategy == STRATEGY_SONIFICATION) - || (stream_strategy == STRATEGY_SONIFICATION_RESPECTFUL) + ((stream == AUDIO_STREAM_ALARM || stream == AUDIO_STREAM_RING) + || (stream == AUDIO_STREAM_NOTIFICATION) || (stream == AUDIO_STREAM_SYSTEM) - || ((stream_strategy == STRATEGY_ENFORCED_AUDIBLE) && - (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_NONE))) && + || ((stream == AUDIO_STREAM_ENFORCED_AUDIBLE) && + (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == + AUDIO_POLICY_FORCE_NONE))) && mVolumeCurves->canBeMuted(stream)) { // when the phone is ringing we must consider that music could have been paused just before // by the music application and behave as if music was active if the last music track was @@ -5632,7 +5492,9 @@ float AudioPolicyManager::computeVolume(audio_stream_type_t stream, if (isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY) || mLimitRingtoneVolume) { volumeDB += SONIFICATION_HEADSET_VOLUME_FACTOR_DB; - audio_devices_t musicDevice = getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/); + audio_devices_t musicDevice = + mEngine->getOutputDevicesForAttributes(attributes_initializer(AUDIO_USAGE_MEDIA), + nullptr, true /*fromCache*/).types(); float musicVolDB = computeVolume(AUDIO_STREAM_MUSIC, mVolumeCurves->getVolumeIndex(AUDIO_STREAM_MUSIC, musicDevice), @@ -5656,7 +5518,7 @@ float AudioPolicyManager::computeVolume(audio_stream_type_t stream, } } } else if ((Volume::getDeviceForVolume(device) != AUDIO_DEVICE_OUT_SPEAKER) || - stream_strategy != STRATEGY_SONIFICATION) { + (stream != AUDIO_STREAM_ALARM && stream != AUDIO_STREAM_RING)) { volumeDB += SONIFICATION_HEADSET_VOLUME_FACTOR_DB; } } @@ -5761,18 +5623,16 @@ void AudioPolicyManager::applyStreamVolumes(const sp& out } } -void AudioPolicyManager::setStrategyMute(routing_strategy strategy, - bool on, - const sp& outputDesc, - int delayMs, - audio_devices_t device) +void AudioPolicyManager::setStrategyMute(product_strategy_t strategy, + bool on, + const sp& outputDesc, + int delayMs, + audio_devices_t device) { - ALOGVV("setStrategyMute() strategy %d, mute %d, output ID %d", - strategy, on, outputDesc->getId()); - for (int stream = 0; stream < AUDIO_STREAM_FOR_POLICY_CNT; stream++) { - if (getStrategy((audio_stream_type_t)stream) == strategy) { - setStreamMute((audio_stream_type_t)stream, on, outputDesc, delayMs, device); - } + for (auto stream: mEngine->getStreamTypesForProductStrategy(strategy)) { + ALOGVV("%s() stream %d, mute %d, output ID %d", __FUNCTION__, stream, on, + outputDesc->getId()); + setStreamMute(stream, on, outputDesc, delayMs, device); } } @@ -5814,25 +5674,9 @@ void AudioPolicyManager::setStreamMute(audio_stream_type_t stream, } } -audio_stream_type_t AudioPolicyManager::streamTypefromAttributesInt(const audio_attributes_t *attr) -{ - // flags to stream type mapping - if ((attr->flags & AUDIO_FLAG_AUDIBILITY_ENFORCED) == AUDIO_FLAG_AUDIBILITY_ENFORCED) { - return AUDIO_STREAM_ENFORCED_AUDIBLE; - } - if ((attr->flags & AUDIO_FLAG_SCO) == AUDIO_FLAG_SCO) { - return AUDIO_STREAM_BLUETOOTH_SCO; - } - if ((attr->flags & AUDIO_FLAG_BEACON) == AUDIO_FLAG_BEACON) { - return AUDIO_STREAM_TTS; - } - - return audio_usage_to_stream_type(attr->usage); -} - bool AudioPolicyManager::isValidAttributes(const audio_attributes_t *paa) { - // has flags that map to a strategy? + // has flags that map to a stream type? if ((paa->flags & (AUDIO_FLAG_AUDIBILITY_ENFORCED | AUDIO_FLAG_SCO | AUDIO_FLAG_BEACON)) != 0) { return true; } @@ -5863,37 +5707,6 @@ bool AudioPolicyManager::isValidAttributes(const audio_attributes_t *paa) return true; } -bool AudioPolicyManager::isStrategyActive(const sp& outputDesc, - routing_strategy strategy, uint32_t inPastMs, - nsecs_t sysTime) const -{ - if ((sysTime == 0) && (inPastMs != 0)) { - sysTime = systemTime(); - } - for (int i = 0; i < (int)AUDIO_STREAM_FOR_POLICY_CNT; i++) { - if (((getStrategy((audio_stream_type_t)i) == strategy) || - (STRATEGY_NONE == strategy)) && - outputDesc->isStreamActive((audio_stream_type_t)i, inPastMs, sysTime)) { - return true; - } - } - return false; -} - -bool AudioPolicyManager::isStrategyActiveOnSameModule(const sp& outputDesc, - routing_strategy strategy, uint32_t inPastMs, - nsecs_t sysTime) const -{ - for (size_t i = 0; i < mOutputs.size(); i++) { - sp desc = mOutputs.valueAt(i); - if (outputDesc->sharesHwModuleWith(desc) - && isStrategyActive(desc, strategy, inPastMs, sysTime)) { - return true; - } - } - return false; -} - audio_policy_forced_cfg_t AudioPolicyManager::getForceUse(audio_policy_force_use_t usage) { return mEngine->getForceUse(usage); diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h index e715fd4ac2..0bf40f4ab4 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.h +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h @@ -153,9 +153,15 @@ public: audio_devices_t device); // return the strategy corresponding to a given stream type - virtual uint32_t getStrategyForStream(audio_stream_type_t stream); - // return the strategy corresponding to the given audio attributes - virtual routing_strategy getStrategyForAttr(const audio_attributes_t *attr); + virtual uint32_t getStrategyForStream(audio_stream_type_t stream) + { + return streamToStrategy(stream); + } + product_strategy_t streamToStrategy(audio_stream_type_t stream) const + { + auto attributes = mEngine->getAttributesForStreamType(stream); + return mEngine->getProductStrategyForAttributes(attributes); + } // return the enabled output devices for the given stream type virtual audio_devices_t getDevicesForStream(audio_stream_type_t stream); @@ -244,9 +250,6 @@ public: virtual status_t getHwOffloadEncodingFormatsSupportedForA2DP( std::vector *formats); - // return the strategy corresponding to a given stream type - routing_strategy getStrategy(audio_stream_type_t stream) const; - virtual void setAppState(uid_t uid, app_state_t state); virtual bool isHapticPlaybackSupported(); @@ -316,32 +319,6 @@ protected: void removeOutput(audio_io_handle_t output); void addInput(audio_io_handle_t input, const sp& inputDesc); - // return appropriate device for streams handled by the specified strategy according to current - // phone state, connected devices... - // if fromCache is true, the device is returned from mDeviceForStrategy[], - // otherwise it is determine 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 updateDevicesAndOutputs() is called. - virtual audio_devices_t getDeviceForStrategy(routing_strategy strategy, - bool fromCache) - { - return getDevicesForStrategy(strategy, fromCache).types(); - } - - DeviceVector getDevicesForStrategy(routing_strategy strategy, bool fromCache); - - bool isStrategyActive(const sp& outputDesc, routing_strategy strategy, - uint32_t inPastMs = 0, nsecs_t sysTime = 0) const; - - bool isStrategyActiveOnSameModule(const sp& outputDesc, - routing_strategy strategy, uint32_t inPastMs = 0, - nsecs_t sysTime = 0) const; - // change the route of the specified output. Returns the number of ms we have slept to // allow new routing to take effect in certain cases. uint32_t setOutputDevices(const sp& outputDesc, @@ -360,9 +337,6 @@ protected: status_t resetInputDevice(audio_io_handle_t input, audio_patch_handle_t *patchHandle = NULL); - // select input device corresponding to requested audio source - sp getDeviceForAttributes(const audio_attributes_t &attributes); - // compute the actual volume for a given stream according to the requested index and a particular // device virtual float computeVolume(audio_stream_type_t stream, @@ -383,8 +357,16 @@ protected: void applyStreamVolumes(const sp& outputDesc, audio_devices_t device, int delayMs = 0, bool force = false); - // Mute or unmute all streams handled by the specified strategy on the specified output - void setStrategyMute(routing_strategy strategy, + /** + * @brief setStrategyMute Mute or unmute all active clients on the considered output + * following the given strategy. + * @param strategy to be considered + * @param on true for mute, false for unmute + * @param outputDesc to be considered + * @param delayMs + * @param device + */ + void setStrategyMute(product_strategy_t strategy, bool on, const sp& outputDesc, int delayMs = 0, @@ -430,26 +412,28 @@ protected: // A2DP suspend status is rechecked. void checkForDeviceAndOutputChanges(std::function onOutputsChecked = nullptr); - // checks and if necessary changes outputs used for all strategies. - // must be called every time a condition that affects the output choice for a given strategy - // changes: connected device, phone state, force use... - // Must be called before updateDevicesAndOutputs() - void checkOutputForStrategy(routing_strategy strategy); + /** + * @brief checkOutputForAttributes checks and if necessary changes outputs used for the + * given audio attributes. + * must be called every time a condition that affects the output choice for a given + * attributes changes: connected device, phone state, force use... + * Must be called before updateDevicesAndOutputs() + * @param attr to be considered + */ + void checkOutputForAttributes(const audio_attributes_t &attr); + + bool followsSameRouting(const audio_attributes_t &lAttr, + const audio_attributes_t &rAttr) const; - // Same as checkOutputForStrategy() but for a all strategies in order of priority + /** + * @brief checkOutputForAllStrategies Same as @see checkOutputForAttributes() + * but for a all product strategies in order of priority + */ void checkOutputForAllStrategies(); // manages A2DP output suspend/restore according to phone state and BT SCO usage void checkA2dpSuspend(); - template - sp findPreferredDevice(IoDescriptor& desc, Filter filter, - bool& active, const DeviceVector& devices); - - template - sp findPreferredDevice(IoCollection& ioCollection, Filter filter, - const DeviceVector& devices); - // selects the most appropriate device on output for current state // must be called every time a condition that affects the device choice for a given output is // changed: connected device, phone state, force use, output start, output stop.. @@ -457,11 +441,14 @@ protected: DeviceVector getNewOutputDevices(const sp& outputDesc, bool fromCache); - // updates cache of device used by all strategies (mDeviceForStrategy[]) - // must be called every time a condition that affects the device choice for a given strategy is - // changed: connected device, phone state, force use... - // cached values are used by getDeviceForStrategy() if parameter fromCache is true. - // Must be called after checkOutputForAllStrategies() + /** + * @brief updateDevicesAndOutputs: updates cache of devices of the engine + * must be called every time a condition that affects the device choice is changed: + * connected device, phone state, force use... + * cached values are used by getOutputDevicesForStream()/getDevicesForAttributes if + * parameter fromCache is true. + * Must be called after checkOutputForAllStrategies() + */ void updateDevicesAndOutputs(); // selects the most appropriate device on input for current state @@ -480,13 +467,19 @@ protected: SortedVector getOutputsForDevices( const DeviceVector &devices, const SwAudioOutputCollection& openOutputs); - // mute/unmute strategies using an incompatible device combination - // if muting, wait for the audio in pcm buffer to be drained before proceeding - // if unmuting, unmute only after the specified delay - // Returns the number of ms waited - virtual uint32_t checkDeviceMuteStrategies(const sp& outputDesc, - audio_devices_t prevDeviceType, - uint32_t delayMs); + /** + * @brief checkDeviceMuteStrategies mute/unmute strategies + * using an incompatible device combination. + * if muting, wait for the audio in pcm buffer to be drained before proceeding + * if unmuting, unmute only after the specified delay + * @param outputDesc + * @param prevDevice + * @param delayMs + * @return the number of ms waited + */ + virtual uint32_t checkDeviceMuteStrategies(const sp& outputDesc, + const DeviceVector &prevDevices, + uint32_t delayMs); audio_io_handle_t selectOutput(const SortedVector& outputs, audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE, @@ -580,15 +573,22 @@ protected: void clearAudioPatches(uid_t uid); void clearSessionRoutes(uid_t uid); - void checkStrategyRoute(routing_strategy strategy, audio_io_handle_t ouptutToSkip); + + /** + * @brief checkStrategyRoute: when an output is beeing rerouted, reconsider each output + * that may host a strategy playing on the considered output. + * @param ps product strategy that initiated the rerouting + * @param ouptutToSkip output that initiated the rerouting + */ + void checkStrategyRoute(product_strategy_t ps, audio_io_handle_t ouptutToSkip); status_t hasPrimaryOutput() const { return mPrimaryOutput != 0; } status_t connectAudioSource(const sp& sourceDesc); status_t disconnectAudioSource(const sp& sourceDesc); - sp getSourceForStrategyOnOutput(audio_io_handle_t output, - routing_strategy strategy); + sp getSourceForAttributesOnOutput(audio_io_handle_t output, + const audio_attributes_t &attr); void cleanUpForDevice(const sp& deviceDesc); @@ -616,15 +616,6 @@ protected: bool mLimitRingtoneVolume; // limit ringtone volume to music volume if headset connected - /** - * @brief mDevicesForStrategy vector of devices that are assigned for a given strategy. - * Note: in case of removal of device (@see setDeviceConnectionState), the device descriptor - * will be removed from the @see mAvailableOutputDevices or @see mAvailableInputDevices - * but the devices for strategies will be reevaluated within the - * @see setDeviceConnectionState function. - */ - DeviceVector mDevicesForStrategy[NUM_STRATEGIES]; - float mLastVoiceVolume; // last voice volume value sent to audio HAL bool mA2dpSuspended; // true if A2DP output is suspended @@ -727,16 +718,26 @@ private: audio_stream_type_t stream, const audio_config_t *config, audio_output_flags_t *flags); - // internal method to return the input handle for the given device and format + + /** + * @brief getInputForDevice selects an input handle for a given input device and + * requester context + * @param device to be used by requester, selected by policy mix rules or engine + * @param session requester session id + * @param uid requester uid + * @param attributes requester audio attributes (e.g. input source and tags matter) + * @param config requester audio configuration (e.g. sample rate, format, channel mask). + * @param flags requester input flags + * @param policyMix may be null, policy rules to be followed by the requester + * @return input io handle aka unique input identifier selected for this device. + */ audio_io_handle_t getInputForDevice(const sp &device, audio_session_t session, - audio_source_t inputSource, + const audio_attributes_t &attributes, const audio_config_base_t *config, audio_input_flags_t flags, AudioMix *policyMix); - // internal function to derive a stream type value from audio attributes - audio_stream_type_t streamTypefromAttributesInt(const audio_attributes_t *attr); // event is one of STARTING_OUTPUT, STARTING_BEACON, STOPPING_OUTPUT, STOPPING_BEACON // returns 0 if no mute/unmute event happened, the largest latency of the device where // the mute/unmute happened @@ -744,11 +745,6 @@ private: uint32_t setBeaconMute(bool mute); bool isValidAttributes(const audio_attributes_t *paa); - // select input device corresponding to requested audio source and return associated policy - // mix if any. Calls getDeviceForInputSource(). - sp getDeviceAndMixForAttributes(const audio_attributes_t &attributes, - AudioMix **policyMix = NULL); - // Called by setDeviceConnectionState(). status_t setDeviceConnectionStateInt(audio_devices_t deviceType, audio_policy_dev_state_t state, diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp index d9fbdaafb1..63cb18757e 100644 --- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp +++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp @@ -703,11 +703,12 @@ status_t AudioPolicyService::getStreamVolumeIndex(audio_stream_type_t stream, uint32_t AudioPolicyService::getStrategyForStream(audio_stream_type_t stream) { if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) { - return 0; + return PRODUCT_STRATEGY_NONE; } if (mAudioPolicyManager == NULL) { - return 0; + return PRODUCT_STRATEGY_NONE; } + // DO NOT LOCK, may be called from AudioFlinger with lock held, reaching deadlock AutoCallerClear acc; return mAudioPolicyManager->getStrategyForStream(stream); } diff --git a/services/audiopolicy/tests/Android.mk b/services/audiopolicy/tests/Android.mk index 5f0974ea04..97be44cea2 100644 --- a/services/audiopolicy/tests/Android.mk +++ b/services/audiopolicy/tests/Android.mk @@ -4,7 +4,6 @@ include $(CLEAR_VARS) LOCAL_C_INCLUDES := \ frameworks/av/services/audiopolicy \ - frameworks/av/services/audiopolicy/engine/interface \ $(call include-path-for, audio-utils) \ LOCAL_SHARED_LIBRARIES := \ @@ -18,7 +17,8 @@ LOCAL_STATIC_LIBRARIES := \ libaudiopolicycomponents \ LOCAL_HEADER_LIBRARIES := \ - libaudiopolicycommon + libaudiopolicycommon \ + libaudiopolicyengine_interface_headers LOCAL_SRC_FILES := \ audiopolicymanager_tests.cpp \