Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c209fe49 authored by Eric Laurent's avatar Eric Laurent
Browse files

audio policy: output selection upon dynamic policy registration

Force reevalution of output selection for AudioTrack clients when a
dynamic audio policy (DAP) of type RENDER is registered or unregistered.
For LOOPBACK policies, this is not needed because the remote submix
device is connected or disconnected triggering output reevaluation.

Also refactor checkOutputForAttributes to take actual output selection
for each client associated to a DAP instead of blindly forcing stream
invalidation as soon as an output associated with a DAP is found.
This covers direct outputs as the output is not opened when the DAP
is registered.

Bug: 130296239
Test: AudioHostTest
Test: AudioServiceHostTest
Test: audiopolicy_tests
Test: regression with auto projected mode and live caption
Change-Id: I07977e7902eb31c59621462a8fe2d7d1a4b1ba36
parent ea5f4133
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@

namespace android {

class AudioPolicyMix;
class DeviceDescriptor;
class HwAudioOutputDescriptor;
class SwAudioOutputDescriptor;
@@ -90,11 +91,12 @@ public:
                          product_strategy_t strategy, VolumeSource volumeSource,
                          audio_output_flags_t flags,
                          bool isPreferredDeviceForExclusiveUse,
                          std::vector<wp<SwAudioOutputDescriptor>> secondaryOutputs) :
                          std::vector<wp<SwAudioOutputDescriptor>> secondaryOutputs,
                          wp<AudioPolicyMix> primaryMix) :
        ClientDescriptor(portId, uid, sessionId, attributes, config, preferredDeviceId,
                         isPreferredDeviceForExclusiveUse),
        mStream(stream), mStrategy(strategy), mVolumeSource(volumeSource), mFlags(flags),
        mSecondaryOutputs(std::move(secondaryOutputs)) {}
        mSecondaryOutputs(std::move(secondaryOutputs)), mPrimaryMix(primaryMix) {}
    ~TrackClientDescriptor() override = default;

    using ClientDescriptor::dump;
@@ -108,6 +110,9 @@ public:
        return mSecondaryOutputs;
    };
    VolumeSource volumeSource() const { return mVolumeSource; }
    const sp<AudioPolicyMix> getPrimaryMix() const {
        return mPrimaryMix.promote();
    };

    void setActive(bool active) override
    {
@@ -136,7 +141,7 @@ private:
    const VolumeSource mVolumeSource;
    const audio_output_flags_t mFlags;
    const std::vector<wp<SwAudioOutputDescriptor>> mSecondaryOutputs;

    const wp<AudioPolicyMix> mPrimaryMix;
    /**
     * required for duplicating thread, prevent from removing active client from an output
     * involved in a duplication.
+4 −1
Original line number Diff line number Diff line
@@ -28,7 +28,7 @@ namespace android {

void AudioPolicyMix::dump(String8 *dst, int spaces, int index) const
{
    dst->appendFormat("%*sAudio Policy Mix %d:\n", spaces, "", index + 1);
    dst->appendFormat("%*sAudio Policy Mix %d (%p):\n", spaces, "", index + 1, this);
    std::string mixTypeLiteral;
    if (!MixTypeConverter::toString(mMixType, mixTypeLiteral)) {
        ALOGE("%s: failed to convert mix type %d", __FUNCTION__, mMixType);
@@ -44,6 +44,9 @@ void AudioPolicyMix::dump(String8 *dst, int spaces, int index) const

    dst->appendFormat("%*s- device address: %s\n", spaces, "", mDeviceAddress.string());

    dst->appendFormat("%*s- output: %d\n", spaces, "",
            mOutput == nullptr ? 0 : mOutput->mIoHandle);

    int indexCriterion = 0;
    for (const auto &criterion : mCriteria) {
        dst->appendFormat("%*s- Criterion %d: ", spaces + 2, "", indexCriterion++);
+8 −1
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <TypeConverter.h>
#include "AudioOutputDescriptor.h"
#include "AudioPatch.h"
#include "AudioPolicyMix.h"
#include "ClientDescriptor.h"
#include "DeviceDescriptor.h"
#include "HwModule.h"
@@ -55,6 +56,12 @@ void TrackClientDescriptor::dump(String8 *dst, int spaces, int index) const
    ClientDescriptor::dump(dst, spaces, index);
    dst->appendFormat("%*s- Stream: %d flags: %08x\n", spaces, "", mStream, mFlags);
    dst->appendFormat("%*s- Refcount: %d\n", spaces, "", mActivityCount);
    dst->appendFormat("%*s- DAP Primary Mix: %p\n", spaces, "", mPrimaryMix.promote().get());
    dst->appendFormat("%*s- DAP Secondary Outputs:\n", spaces, "");
    for (auto desc : mSecondaryOutputs) {
        dst->appendFormat("%*s  - %d\n", spaces, "",
                desc.promote() == nullptr ? 0 : desc.promote()->mIoHandle);
    }
}

std::string TrackClientDescriptor::toShortString() const
@@ -88,7 +95,7 @@ SourceClientDescriptor::SourceClientDescriptor(audio_port_handle_t portId, uid_t
    TrackClientDescriptor::TrackClientDescriptor(portId, uid, AUDIO_SESSION_NONE, attributes,
        {config.sample_rate, config.channel_mask, config.format}, AUDIO_PORT_HANDLE_NONE,
        stream, strategy, volumeSource, AUDIO_OUTPUT_FLAG_NONE, false,
        {} /* Sources do not support secondary outputs*/), mSrcDevice(srcDevice)
        {} /* Sources do not support secondary outputs*/, nullptr), mSrcDevice(srcDevice)
{
}

+42 −23
Original line number Diff line number Diff line
@@ -1102,14 +1102,15 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
    };
    *portId = PolicyAudioPort::getNextUniqueId();

    sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(*output);
    sp<TrackClientDescriptor> clientDesc =
        new TrackClientDescriptor(*portId, uid, session, resultAttr, clientConfig,
                                  sanitizedRequestedPortId, *stream,
                                  mEngine->getProductStrategyForAttributes(resultAttr),
                                  toVolumeSource(resultAttr),
                                  *flags, isRequestedDeviceForExclusiveUse,
                                  std::move(weakSecondaryOutputDescs));
    sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(*output);
                                  std::move(weakSecondaryOutputDescs),
                                  outputDesc->mPolicyMix);
    outputDesc->addClient(clientDesc);

    ALOGV("%s() returns output %d requestedPortId %d selectedDeviceId %d for port ID %d", __func__,
@@ -2877,7 +2878,7 @@ status_t AudioPolicyManager::registerPolicyMixes(const Vector<AudioMix>& mixes)
{
    ALOGV("registerPolicyMixes() %zu mix(es)", mixes.size());
    status_t res = NO_ERROR;

    bool checkOutputs = false;
    sp<HwModule> rSubmixModule;
    // examine each mix's route type
    for (size_t i = 0; i < mixes.size(); i++) {
@@ -2996,11 +2997,16 @@ status_t AudioPolicyManager::registerPolicyMixes(const Vector<AudioMix>& mixes)
                        i, type, address.string());
                res = INVALID_OPERATION;
                break;
            } else {
                checkOutputs = true;
            }
        }
    }
    if (res != NO_ERROR) {
        unregisterPolicyMixes(mixes);
    } else if (checkOutputs) {
        checkForDeviceAndOutputChanges();
        updateCallAndOutputRouting();
    }
    return res;
}
@@ -3009,6 +3015,7 @@ status_t AudioPolicyManager::unregisterPolicyMixes(Vector<AudioMix> mixes)
{
    ALOGV("unregisterPolicyMixes() num mixes %zu", mixes.size());
    status_t res = NO_ERROR;
    bool checkOutputs = false;
    sp<HwModule> rSubmixModule;
    // examine each mix's route type
    for (const auto& mix : mixes) {
@@ -3049,9 +3056,15 @@ status_t AudioPolicyManager::unregisterPolicyMixes(Vector<AudioMix> mixes)
            if (mPolicyMixes.unregisterMix(mix) != NO_ERROR) {
                res = INVALID_OPERATION;
                continue;
            } else {
                checkOutputs = true;
            }
        }
    }
    if (res == NO_ERROR && checkOutputs) {
        checkForDeviceAndOutputChanges();
        updateCallAndOutputRouting();
    }
    return res;
}

@@ -5226,32 +5239,38 @@ void AudioPolicyManager::checkOutputForAttributes(const audio_attributes_t &attr
    SortedVector<audio_io_handle_t> srcOutputs = getOutputsForDevices(oldDevices, mPreviousOutputs);
    SortedVector<audio_io_handle_t> 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("%s(): policy related outputs", __func__);
    bool hasDynamicPolicy = false;
    for (size_t i = 0 ; i < mPreviousOutputs.size() ; i++) {
        const sp<SwAudioOutputDescriptor> desc = mPreviousOutputs.valueAt(i);
        if (desc != 0 && desc->mPolicyMix != NULL) {
            srcOutputs.add(desc->mIoHandle);
            hasDynamicPolicy = true;
            ALOGVV(" previous outputs: adding %d", desc->mIoHandle);
    uint32_t maxLatency = 0;
    bool invalidate = false;
    // take into account dynamic audio policies related changes: if a client is now associated
    // to a different policy mix than at creation time, invalidate corresponding stream
    for (size_t i = 0; i < mPreviousOutputs.size() && !invalidate; i++) {
        const sp<SwAudioOutputDescriptor>& desc = mPreviousOutputs.valueAt(i);
        if (desc->isDuplicated()) {
            continue;
        }
        for (const sp<TrackClientDescriptor>& client : desc->getClientIterable()) {
            if (mEngine->getProductStrategyForAttributes(client->attributes()) != psId) {
                continue;
            }
            sp<AudioPolicyMix> primaryMix;
            status_t status = mPolicyMixes.getOutputForAttr(client->attributes(), client->uid(),
                    client->flags(), primaryMix, nullptr);
            if (status != OK) {
                continue;
            }
            if (client->getPrimaryMix() != primaryMix) {
                invalidate = true;
                if (desc->isStrategyActive(psId)) {
                    maxLatency = desc->latency();
                }
                break;
            }
    for (size_t i = 0 ; i < mOutputs.size() ; i++) {
        const sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
        if (desc != 0 && desc->mPolicyMix != NULL) {
            dstOutputs.add(desc->mIoHandle);
            hasDynamicPolicy = true;
            ALOGVV(" new outputs: adding %d", desc->mIoHandle);
        }
    }

    if (srcOutputs != dstOutputs) {
    if (srcOutputs != dstOutputs || invalidate) {
        // 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;
        bool invalidate = hasDynamicPolicy;
        for (audio_io_handle_t srcOut : srcOutputs) {
            sp<SwAudioOutputDescriptor> desc = mPreviousOutputs.valueFor(srcOut);
            if (desc == nullptr) continue;