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

Commit 1c87855f authored by François Gaffie's avatar François Gaffie Committed by Eric Laurent
Browse files

audiopolicy: rework stream activity for volume management on output



-Manage duplicated output ref count in client itself
-Use VolumeSource to track volume activity in output
(today mapped on legacy stream type)
-Use accessor APIs to control activity/mute from apm.

Test: audio smoke tests
Bug: 124767636

Change-Id: I452e3973f6869d41231d984896a5886ebb86afb1
Signed-off-by: default avatarFrançois Gaffie <francois.gaffie@renault.com>
parent e690a6da
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -20,6 +20,22 @@
#include <utils/Log.h>
#include <math.h>

namespace android {
/**
 * VolumeSource is the discriminent for volume management on an output.
 * It used to be the stream type by legacy, it may be host volume group or a volume curves if
 * we allow to have more than one curve per volume group.
 */
enum VolumeSource : std::underlying_type<audio_stream_type_t>::type;
static const VolumeSource VOLUME_SOURCE_NONE = static_cast<VolumeSource>(AUDIO_STREAM_DEFAULT);

static inline VolumeSource streamToVolumeSource(audio_stream_type_t stream) {
    return static_cast<VolumeSource>(stream);
}


} // namespace android

// Absolute min volume in dB (can be represented in single precision normal float value)
#define VOLUME_MIN_DB (-758)

+142 −41
Original line number Diff line number Diff line
@@ -73,7 +73,7 @@ public:

    virtual void dump(String8 *dst, int spaces) const
    {
        dst->appendFormat("%*s- ActivityCount: %d, StopTime: %" PRId64 " \n", spaces, "",
        dst->appendFormat("%*s- ActivityCount: %d, StopTime: %" PRId64 ", ", spaces, "",
                          getActivityCount(), getStopTime());
    }
private:
@@ -81,6 +81,37 @@ private:
    nsecs_t mStopTime = 0;
};

/**
 * @brief VolumeActivity: it tracks the activity for volume policy (volume index, mute,
 * memorize previous stop, and store mute if incompatible device with another strategy.
 */
class VolumeActivity : public ActivityTracking
{
public:
    bool isMuted() const { return mMuteCount > 0; }
    int getMuteCount() const { return mMuteCount; }
    int incMuteCount() { return ++mMuteCount; }
    int decMuteCount() { return mMuteCount > 0 ? --mMuteCount : -1; }

    void dump(String8 *dst, int spaces) const override
    {
        ActivityTracking::dump(dst, spaces);
        dst->appendFormat(", Volume: %.03f, MuteCount: %02d\n", mCurVolumeDb, mMuteCount);
    }
    void setVolume(float volume) { mCurVolumeDb = volume; }
    float getVolume() const { return mCurVolumeDb; }

private:
    int mMuteCount = 0; /**< mute request counter */
    float mCurVolumeDb = NAN; /**< current volume in dB. */
};
/**
 * Note: volume activities shall be indexed by CurvesId if we want to allow multiple
 * curves per volume group, inferring a mute management or volume balancing between HW and SW is
 * done
 */
using VolumeActivities = std::map<VolumeSource, VolumeActivity>;

/**
 * @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.
@@ -92,6 +123,10 @@ public:
    void setMutedByDevice( bool isMuted) { mIsMutedByDevice = isMuted; }
    bool isMutedByDevice() const { return mIsMutedByDevice; }

    void dump(String8 *dst, int spaces) const override {
        ActivityTracking::dump(dst, spaces);
        dst->appendFormat("\n");
    }
private:
    /**
     * strategies muted because of incompatible device selection.
@@ -127,15 +162,6 @@ public:
                           uint32_t delayMs,
                           bool force);

    /**
     * Changes the stream active count and mActiveClients only.
     * This does not change the client->active() state or the output descriptor's
     * global active count.
     */
    virtual void changeStreamActiveCount(const sp<TrackClientDescriptor>& client, int delta);
            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
@@ -148,13 +174,61 @@ public:
     * Changes the client->active() state and the output descriptor's global active count,
     * along with the stream active count and mActiveClients.
     * The client must be previously added by the base class addClient().
     * In case of duplicating thread, client shall be added on the duplicated thread, not on the
     * involved outputs but setClientActive will be called on all output to track strategy and
     * active client for a given output.
     * Active ref count of the client will be incremented/decremented through setActive API
     */
            void setClientActive(const sp<TrackClientDescriptor>& client, bool active);
    virtual void setClientActive(const sp<TrackClientDescriptor>& client, bool active);

    bool isActive(uint32_t inPastMs = 0) const;
    bool isStreamActive(audio_stream_type_t stream,
    bool isActive(uint32_t inPastMs) const;
    bool isActive(VolumeSource volumeSource = VOLUME_SOURCE_NONE,
                  uint32_t inPastMs = 0,
                  nsecs_t sysTime = 0) const;
    bool isAnyActive(VolumeSource volumeSourceToIgnore) const;

    std::vector<VolumeSource> getActiveVolumeSources() const {
        std::vector<VolumeSource> activeList;
        for (const auto &iter : mVolumeActivities) {
            if (iter.second.isActive()) {
                activeList.push_back(iter.first);
            }
        }
        return activeList;
    }
    uint32_t getActivityCount(VolumeSource vs) const
    {
        return mVolumeActivities.find(vs) != std::end(mVolumeActivities)?
                    mVolumeActivities.at(vs).getActivityCount() : 0;
    }
    bool isMuted(VolumeSource vs) const
    {
        return mVolumeActivities.find(vs) != std::end(mVolumeActivities)?
                    mVolumeActivities.at(vs).isMuted() : false;
    }
    int getMuteCount(VolumeSource vs) const
    {
        return mVolumeActivities.find(vs) != std::end(mVolumeActivities)?
                    mVolumeActivities.at(vs).getMuteCount() : 0;
    }
    int incMuteCount(VolumeSource vs)
    {
        return mVolumeActivities[vs].incMuteCount();
    }
    int decMuteCount(VolumeSource vs)
    {
        return mVolumeActivities[vs].decMuteCount();
    }
    void setCurVolume(VolumeSource vs, float volume)
    {
        // Even if not activity for this group registered, need to create anyway
        mVolumeActivities[vs].setVolume(volume);
    }
    float getCurVolume(VolumeSource vs) const
    {
        return mVolumeActivities.find(vs) != std::end(mVolumeActivities) ?
                    mVolumeActivities.at(vs).getVolume() : NAN;
    }

    bool isStrategyActive(product_strategy_t ps, uint32_t inPastMs = 0, nsecs_t sysTime = 0) const
    {
@@ -195,40 +269,36 @@ public:
        // it is possible that when a client is removed, we could remove its
        // associated active count by calling changeStreamActiveCount(),
        // but that would be hiding a problem, so we log fatal instead.
        auto it2 = mActiveClients.find(client);
        LOG_ALWAYS_FATAL_IF(it2 != mActiveClients.end(),
                "%s(%d) removing client portId %d which is active (count %zu)",
                __func__, mId, portId, it2->second);
        auto clientIter = std::find(begin(mActiveClients), end(mActiveClients), client);
        LOG_ALWAYS_FATAL_IF(clientIter != mActiveClients.end(),
                            "%s(%d) removing client portId %d which is active (count %d)",
                            __func__, mId, portId, client->getActivityCount());
        ClientMapHandler<TrackClientDescriptor>::removeClient(portId);
    }

    using ActiveClientMap = std::map<sp<TrackClientDescriptor>, size_t /* count */>;
    // required for duplicating thread
    const ActiveClientMap& getActiveClients() const {
    const TrackClientVector& getActiveClients() const {
        return mActiveClients;
    }

    DeviceVector mDevices; /**< current devices this output is routed to */
    nsecs_t mStopTime[AUDIO_STREAM_CNT];
    int mMuteCount[AUDIO_STREAM_CNT];            // mute request counter
    AudioMix *mPolicyMix = nullptr;              // non NULL when used by a dynamic policy

protected:
    const sp<AudioPort> mPort;
    AudioPolicyClientInterface * const mClientInterface;
    float mCurVolume[AUDIO_STREAM_CNT];   // current stream volume in dB
    uint32_t mActiveCount[AUDIO_STREAM_CNT]; // number of streams of each type active on this output
    uint32_t mGlobalActiveCount = 0;  // non-client-specific active count
    audio_patch_handle_t mPatchHandle = AUDIO_PATCH_HANDLE_NONE;
    audio_port_handle_t mId = AUDIO_PORT_HANDLE_NONE;

    // The ActiveClientMap shows the clients that contribute to the streams counts
    // The ActiveClients shows the clients that contribute to the @VolumeSource counts
    // and may include upstream clients from a duplicating thread.
    // Compare with the ClientMap (mClients) which are external AudioTrack clients of the
    // output descriptor (and do not count internal PatchTracks).
    ActiveClientMap mActiveClients;
    TrackClientVector mActiveClients;

    RoutingActivities mRoutingActivities; /**< track routing activity on this ouput.*/

    VolumeActivities mVolumeActivities; /**< track volume activity on this ouput.*/
};

// Audio output driven by a software mixer in audio flinger.
@@ -250,8 +320,13 @@ public:
    virtual bool isFixedVolume(audio_devices_t device);
    sp<SwAudioOutputDescriptor> subOutput1() { return mOutput1; }
    sp<SwAudioOutputDescriptor> subOutput2() { return mOutput2; }
            void changeStreamActiveCount(
                    const sp<TrackClientDescriptor>& client, int delta) override;
    void setClientActive(const sp<TrackClientDescriptor>& client, bool active) override;
    void setAllClientsInactive()
    {
        for (const auto &client : clientsList(true)) {
            setClientActive(client, false);
        }
    }
    virtual bool setVolume(float volume,
                           audio_stream_type_t stream,
                           audio_devices_t device,
@@ -344,25 +419,27 @@ class SwAudioOutputCollection :
        public DefaultKeyedVector< audio_io_handle_t, sp<SwAudioOutputDescriptor> >
{
public:
    bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
    bool isActive(VolumeSource volumeSource, uint32_t inPastMs = 0) const;

    /**
     * return whether a stream is playing remotely, override to change the definition of
     * return whether any source contributing to VolumeSource is playing remotely, override 
     * to change the definition of
     * local/remote playback, used for instance by notification manager to not make
     * media players lose audio focus when not playing locally
     * For the base implementation, "remotely" means playing during screen mirroring which
     * uses an output for playback with a non-empty, non "0" address.
     */
    bool isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
    bool isActiveRemotely(VolumeSource volumeSource, uint32_t inPastMs = 0) const;

    /**
     * return whether a stream is playing, but not on a "remote" device.
     * return whether any source contributing to VolumeSource is playing, but not on a "remote"
     * device.
     * Override to change the definition of a local/remote playback.
     * Used for instance by policy manager to alter the speaker playback ("speaker safe" behavior)
     * when media plays or not locally.
     * For the base implementation, "remotely" means playing during screen mirroring.
     */
    bool isStreamActiveLocally(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
    bool isActiveLocally(VolumeSource volumeSource, uint32_t inPastMs = 0) const;

    /**
     * @brief isStrategyActiveOnSameModule checks if the given strategy is active (or was active
@@ -409,9 +486,21 @@ public:
    sp<SwAudioOutputDescriptor> getPrimaryOutput() const;

    /**
     * return true if any output is playing anything besides the stream to ignore
     * @brief isAnyOutputActive checks if any output is active (aka playing) except the one(s) that
     * hold the volume source to be ignored
     * @param volumeSourceToIgnore source not considered in the activity detection
     * @return true if any output is active for any source except the one to be ignored
     */
    bool isAnyOutputActive(audio_stream_type_t streamToIgnore) const;
    bool isAnyOutputActive(VolumeSource volumeSourceToIgnore) const
    {
        for (size_t i = 0; i < size(); i++) {
            const sp<AudioOutputDescriptor> &outputDesc = valueAt(i);
            if (outputDesc->isAnyActive(volumeSourceToIgnore)) {
                return true;
            }
        }
        return false;
    }

    audio_devices_t getSupportedDevices(audio_io_handle_t handle) const;

@@ -424,12 +513,24 @@ class HwAudioOutputCollection :
        public DefaultKeyedVector< audio_io_handle_t, sp<HwAudioOutputDescriptor> >
{
public:
    bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
    bool isActive(VolumeSource volumeSource, uint32_t inPastMs = 0) const;

    /**
     * return true if any output is playing anything besides the stream to ignore
     * @brief isAnyOutputActive checks if any output is active (aka playing) except the one(s) that
     * hold the volume source to be ignored
     * @param volumeSourceToIgnore source not considered in the activity detection
     * @return true if any output is active for any source except the one to be ignored
     */
    bool isAnyOutputActive(audio_stream_type_t streamToIgnore) const;
    bool isAnyOutputActive(VolumeSource volumeSourceToIgnore) const
    {
        for (size_t i = 0; i < size(); i++) {
            const sp<AudioOutputDescriptor> &outputDesc = valueAt(i);
            if (outputDesc->isAnyActive(volumeSourceToIgnore)) {
                return true;
            }
        }
        return false;
    }

    void dump(String8 *dst) const;
};
+36 −4
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#include <utils/RefBase.h>
#include <utils/String8.h>
#include <policy.h>
#include <Volume.h>
#include "AudioPatch.h"
#include "EffectDescriptor.h"

@@ -62,7 +63,7 @@ public:
        mPreferredDeviceId = preferredDeviceId;
    }
    bool isPreferredDeviceForExclusiveUse() const { return mPreferredDeviceForExclusiveUse; }
    void setActive(bool active) { mActive = active; }
    virtual void setActive(bool active) { mActive = active; }
    bool active() const { return mActive; }
    bool hasPreferredDevice(bool activeOnly = false) const {
        return mPreferredDeviceId != AUDIO_PORT_HANDLE_NONE && (!activeOnly || mActive);
@@ -85,12 +86,13 @@ 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,
                          product_strategy_t strategy, audio_output_flags_t flags,
                          product_strategy_t strategy, VolumeSource volumeSource,
                          audio_output_flags_t flags,
                          bool isPreferredDeviceForExclusiveUse,
                          std::vector<wp<SwAudioOutputDescriptor>> secondaryOutputs) :
        ClientDescriptor(portId, uid, sessionId, attributes, config, preferredDeviceId,
                         isPreferredDeviceForExclusiveUse),
        mStream(stream), mStrategy(strategy), mFlags(flags),
        mStream(stream), mStrategy(strategy), mVolumeSource(volumeSource), mFlags(flags),
        mSecondaryOutputs(std::move(secondaryOutputs)) {}
    ~TrackClientDescriptor() override = default;

@@ -104,12 +106,41 @@ public:
    const std::vector<wp<SwAudioOutputDescriptor>>& getSecondaryOutputs() const {
        return mSecondaryOutputs;
    };
    VolumeSource volumeSource() const { return mVolumeSource; }

    void setActive(bool active) override
    {
        int delta = active ? 1 : -1;
        changeActivityCount(delta);
    }
    void changeActivityCount(int delta)
    {
        if (delta > 0) {
            mActivityCount += delta;
        } else {
            LOG_ALWAYS_FATAL_IF(!mActivityCount, "%s(%s) invalid delta %d, inactive client",
                                 __func__, toShortString().c_str(), delta);
            LOG_ALWAYS_FATAL_IF(static_cast<int>(mActivityCount) < -delta,
                                "%s(%s) invalid delta %d, active client count %d",
                                 __func__, toShortString().c_str(), delta, mActivityCount);
            mActivityCount += delta;
        }
        ClientDescriptor::setActive(mActivityCount > 0);
    }
    uint32_t getActivityCount() const { return mActivityCount; }

private:
    const audio_stream_type_t mStream;
    const product_strategy_t mStrategy;
    const VolumeSource mVolumeSource;
    const audio_output_flags_t mFlags;
    const std::vector<wp<SwAudioOutputDescriptor>> mSecondaryOutputs;

    /**
     * required for duplicating thread, prevent from removing active client from an output
     * involved in a duplication.
     */
    uint32_t mActivityCount = 0;
};

class RecordClientDescriptor: public ClientDescriptor
@@ -148,7 +179,8 @@ 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, product_strategy_t strategy);
                           audio_stream_type_t stream, product_strategy_t strategy,
                           VolumeSource volumeSource);
    ~SourceClientDescriptor() override = default;

    sp<AudioPatch> patchDesc() const { return mPatchDesc; }
+69 −156

File changed.

Preview size limit exceeded, changes collapsed.

+5 −2
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <sstream>
#include <utils/Log.h>
#include <utils/String8.h>
#include <TypeConverter.h>
#include "AudioGain.h"
#include "AudioOutputDescriptor.h"
#include "AudioPatch.h"
@@ -45,6 +46,7 @@ void ClientDescriptor::dump(String8 *dst, int spaces, int index) const
             mPortId, mSessionId, mUid);
    dst->appendFormat("%*s- Format: %08x Sampling rate: %d Channels: %08x\n", spaces, "",
             mConfig.format, mConfig.sample_rate, mConfig.channel_mask);
    dst->appendFormat("%*s- Attributes: %s\n", spaces, "", toString(mAttributes).c_str());
    dst->appendFormat("%*s- Preferred Device Id: %08x\n", spaces, "", mPreferredDeviceId);
    dst->appendFormat("%*s- State: %s\n", spaces, "", mActive ? "Active" : "Inactive");
}
@@ -53,6 +55,7 @@ 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);
}

std::string TrackClientDescriptor::toShortString() const
@@ -82,10 +85,10 @@ 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,
         product_strategy_t strategy) :
         product_strategy_t strategy, VolumeSource volumeSource) :
    TrackClientDescriptor::TrackClientDescriptor(portId, uid, AUDIO_SESSION_NONE, attributes,
        AUDIO_CONFIG_BASE_INITIALIZER, AUDIO_PORT_HANDLE_NONE,
        stream, strategy, AUDIO_OUTPUT_FLAG_NONE, false,
        stream, strategy, volumeSource, AUDIO_OUTPUT_FLAG_NONE, false,
        {} /* Sources do not support secondary outputs*/),
        mPatchDesc(patchDesc), mSrcDevice(srcDevice)
{
Loading