audiopolicy: apm: switch to new Engine APIs

Test: make
Change-Id: Iedc2268852ee0bce32b67cfd324395c48cb33424
Signed-off-by: François Gaffie <francois.gaffie@renault.com>
gugelfrei
François Gaffie 6 years ago committed by Eric Laurent
parent d0ba9ed06c
commit c005e569c7

@ -414,7 +414,7 @@ public:
data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
data.writeInt32(static_cast <uint32_t>(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 <audio_stream_type_t>(data.readInt32());
reply->writeInt32(getStrategyForStream(stream));
reply->writeUint32(getStrategyForStream(stream));
return NO_ERROR;
} break;

@ -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

@ -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

@ -23,7 +23,6 @@ namespace android {
using StreamTypeVector = std::vector<audio_stream_type_t>;
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);
}

@ -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 <class IoDescriptor, class Filter>
sp<DeviceDescriptor> 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 <class IoCollection, class Filter>
sp<DeviceDescriptor> findPreferredDevice(
IoCollection& ioCollection, Filter filter, const DeviceVector& devices)
{
sp<DeviceDescriptor> device;
for (size_t i = 0; i < ioCollection.size(); i++) {
auto desc = ioCollection.valueAt(i);
bool active;
sp<DeviceDescriptor> curDevice = findPreferredDevice(desc, filter, active, devices);
if (active && curDevice == nullptr) {
return nullptr;
} else if (curDevice != nullptr) {
device = curDevice;
}
}
return device;
}
} // namespace android

@ -16,18 +16,20 @@
#pragma once
#define __STDC_LIMIT_MACROS
#include <inttypes.h>
#include <sys/types.h>
#include <utils/Errors.h>
#include <utils/Timers.h>
#include <utils/KeyedVector.h>
#include <system/audio.h>
#include <RoutingStrategy.h>
#include "AudioIODescriptorInterface.h"
#include "AudioPort.h"
#include "ClientDescriptor.h"
#include "DeviceDescriptor.h"
#include <map>
#include <vector>
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<product_strategy_t, RoutingActivity>;
// 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<TrackClientDescriptor>& 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<AudioPort> 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<SwAudioOutputDescriptor>& desc,
uint32_t inPastMs = 0, nsecs_t sysTime = 0) const;
/**
* returns the A2DP output handle if it is open or 0 otherwise
*/

@ -78,7 +78,7 @@ public:
sp<DeviceDescriptor> 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

@ -22,14 +22,14 @@
#include <sys/types.h>
#include <system/audio.h>
#include <system/audio_policy.h>
#include <media/AudioProductStrategy.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
#include <policy.h>
#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<AudioPatch>& patchDesc, const sp<DeviceDescriptor>& srcDevice,
audio_stream_type_t stream, routing_strategy strategy);
audio_stream_type_t stream, product_strategy_t strategy);
~SourceClientDescriptor() override = default;
sp<AudioPatch> patchDesc() const { return mPatchDesc; }

@ -16,7 +16,7 @@
#pragma once
#include <RoutingStrategy.h>
#include <policy.h>
#include <system/audio_effect.h>
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
@ -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<int, sp<EffectDescriptor> >
@ -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<EffectDescriptor> getEffect(int id) const;
status_t setEffectEnabled(int id, bool enabled);

@ -44,9 +44,6 @@ AudioOutputDescriptor::AudioOutputDescriptor(const sp<AudioPort>& 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 sp<TrackClientDescript
// return;
}
mActiveCount[stream] += delta;
mRoutingActivities[client->strategy()].changeActivityCount(delta);
if (delta > 0) {
mActiveClients[client] += delta;
@ -122,6 +120,12 @@ void AudioOutputDescriptor::changeStreamActiveCount(const sp<TrackClientDescript
ALOGV("%s stream %d, count %d", __FUNCTION__, stream, mActiveCount[stream]);
}
void AudioOutputDescriptor::setStopTime(const sp<TrackClientDescriptor>& client, nsecs_t sysTime)
{
mStopTime[client->stream()] = sysTime;
mRoutingActivities[client->strategy()].setStopTime(sysTime);
}
void AudioOutputDescriptor::setClientActive(const sp<TrackClientDescriptor>& 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<SwAudioOutputDescriptor>& desc,
uint32_t inPastMs, nsecs_t sysTime) const
{
for (size_t i = 0; i < size(); i++) {
const sp<SwAudioOutputDescriptor> 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++) {

@ -302,7 +302,7 @@ sp<DeviceDescriptor> AudioPolicyMixCollection::getDeviceAndMixForOutput(
}
sp<DeviceDescriptor> 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();

@ -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<AudioPatch>& patchDesc,
const sp<DeviceDescriptor>& 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),

@ -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<EffectDescriptor> effectDesc = new EffectDescriptor();
memcpy (&effectDesc->mDesc, desc, sizeof(effect_descriptor_t));
effectDesc->mId = id;
effectDesc->mIo = io;
effectDesc->mStrategy = static_cast<routing_strategy>(strategy);
effectDesc->mSession = session;
effectDesc->mEnabled = false;
sp<EffectDescriptor> 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<EffectDescriptor> 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);

@ -32,6 +32,7 @@
#include <EngineConfig.h>
#include <policy.h>
#include <AudioIODescriptorInterface.h>
#include <ParameterManagerWrapper.h>
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<DeviceDescriptor> 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<DeviceDescriptor> 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<DeviceDescriptor> 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<audio_devices_t, audio_source_t>(attr.source);
if (audio_is_remote_submix_device(deviceType)) {
@ -361,7 +388,7 @@ sp<DeviceDescriptor> 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()

@ -29,6 +29,7 @@
#include <AudioPolicyManagerObserver.h>
#include <AudioPort.h>
#include <IOProfile.h>
#include <AudioIODescriptorInterface.h>
#include <policy.h>
#include <utils/String8.h>
#include <utils/Log.h>
@ -241,7 +242,8 @@ audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const
const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
return getDeviceForStrategyInt(static_cast<legacy_strategy>(strategy), availableOutputDevices,
return getDeviceForStrategyInt(static_cast<legacy_strategy>(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<DeviceDescriptor> 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<DeviceDescriptor> 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<DeviceDescriptor> 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)) {

File diff suppressed because it is too large Load Diff

@ -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<audio_format_t> *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<AudioInputDescriptor>& 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<AudioOutputDescriptor>& outputDesc, routing_strategy strategy,
uint32_t inPastMs = 0, nsecs_t sysTime = 0) const;
bool isStrategyActiveOnSameModule(const sp<SwAudioOutputDescriptor>& 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<SwAudioOutputDescriptor>& 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<DeviceDescriptor> 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<AudioOutputDescriptor>& 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<AudioOutputDescriptor>& outputDesc,
int delayMs = 0,
@ -430,26 +412,28 @@ protected:
// A2DP suspend status is rechecked.
void checkForDeviceAndOutputChanges(std::function<bool()> 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 <class IoDescriptor, class Filter>
sp<DeviceDescriptor> findPreferredDevice(IoDescriptor& desc, Filter filter,
bool& active, const DeviceVector& devices);
template <class IoCollection, class Filter>
sp<DeviceDescriptor> 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<SwAudioOutputDescriptor>& 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<audio_io_handle_t> 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<AudioOutputDescriptor>& 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<AudioOutputDescriptor>& outputDesc,
const DeviceVector &prevDevices,
uint32_t delayMs);
audio_io_handle_t selectOutput(const SortedVector<audio_io_handle_t>& 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<SourceClientDescriptor>& sourceDesc);
status_t disconnectAudioSource(const sp<SourceClientDescriptor>& sourceDesc);
sp<SourceClientDescriptor> getSourceForStrategyOnOutput(audio_io_handle_t output,
routing_strategy strategy);
sp<SourceClientDescriptor> getSourceForAttributesOnOutput(audio_io_handle_t output,
const audio_attributes_t &attr);
void cleanUpForDevice(const sp<DeviceDescriptor>& 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<DeviceDescriptor> &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<DeviceDescriptor> 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,

@ -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);
}

@ -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 \

Loading…
Cancel
Save