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

Commit 593634d6 authored by Francois Gaffie's avatar Francois Gaffie
Browse files

[BUG] AudioPolicy: combo UC: mute may not work



When a SwOutput hosts a combo use case, if this output is routed
to a device using an HW Gain, the highest priority product strategy/
volume source will only be allowed for volume operation.
If muting the other volume source (adjustStreamVolume on AudioService
translated into setVolumeIndexForAttributes), the AudioPolicyManager
will block the volume change.

This CL fixes this issue by considering the mute and implement it
through Sw gain on AudioFlinger in case of concurrent UC on Output.

Test: audio smoke tests
Bug: 187173302

Signed-off-by: default avatarFrancois Gaffie <francois.gaffie@renault.com>
Change-Id: I2799ac7140970c1e94e0c6424e9e840b83fe8ef7
parent 3523ab3e
Loading
Loading
Loading
Loading
+18 −3
Original line number Diff line number Diff line
@@ -158,7 +158,7 @@ public:
    virtual bool isDuplicated() const { return false; }
    virtual uint32_t latency() { return 0; }
    virtual bool isFixedVolume(const DeviceTypeSet& deviceTypes);
    virtual bool setVolume(float volumeDb,
    virtual bool setVolume(float volumeDb, bool muted,
                           VolumeSource volumeSource, const StreamTypeVector &streams,
                           const DeviceTypeSet& deviceTypes,
                           uint32_t delayMs,
@@ -352,7 +352,22 @@ public:
            setClientActive(client, false);
        }
    }
    virtual bool setVolume(float volumeDb,

    /**
     * @brief setSwMute for SwOutput routed on a device that supports Hw Gain, this function allows
     * to mute the tracks associated to a given volume source only.
     * As an output may host one or more source(s), and as AudioPolicyManager may dispatch or not
     * the volume change request according to the priority of the volume source to control the
     * unique hw gain controller, a separated API allows to force a mute/unmute of a volume source.
     * @param muted true to mute, false otherwise
     * @param vs volume source to be considered
     * @param device scoped for the change
     * @param delayMs potentially applyed to prevent cut sounds.
     */
    void setSwMute(bool muted, VolumeSource vs, const StreamTypeVector &streams,
                   const DeviceTypeSet& device, uint32_t delayMs);

    virtual bool setVolume(float volumeDb, bool muted,
                           VolumeSource volumeSource, const StreamTypeVector &streams,
                           const DeviceTypeSet& device,
                           uint32_t delayMs,
@@ -435,7 +450,7 @@ public:

            void dump(String8 *dst) const override;

    virtual bool setVolume(float volumeDb,
    virtual bool setVolume(float volumeDb, bool muted,
                           VolumeSource volumeSource, const StreamTypeVector &streams,
                           const DeviceTypeSet& deviceTypes,
                           uint32_t delayMs,
+37 −9
Original line number Diff line number Diff line
@@ -155,7 +155,7 @@ bool AudioOutputDescriptor::isFixedVolume(const DeviceTypeSet& deviceTypes __unu
    return false;
}

bool AudioOutputDescriptor::setVolume(float volumeDb,
bool AudioOutputDescriptor::setVolume(float volumeDb, bool /*muted*/,
                                      VolumeSource volumeSource,
                                      const StreamTypeVector &/*streams*/,
                                      const DeviceTypeSet& deviceTypes,
@@ -435,14 +435,36 @@ void SwAudioOutputDescriptor::toAudioPort(struct audio_port_v7 *port) const
            mFlags & AUDIO_OUTPUT_FLAG_FAST ? AUDIO_LATENCY_LOW : AUDIO_LATENCY_NORMAL;
}

bool SwAudioOutputDescriptor::setVolume(float volumeDb,
void SwAudioOutputDescriptor::setSwMute(
        bool muted, VolumeSource vs, const StreamTypeVector &streamTypes,
        const DeviceTypeSet& deviceTypes, uint32_t delayMs) {
    // volume source active and more than one volume source is active, otherwise, no-op or let
    // setVolume controlling SW and/or HW Gains
    if (!streamTypes.empty() && isActive(vs) && (getActiveVolumeSources().size() > 1)) {
        for (const auto& devicePort : devices()) {
            if (isSingleDeviceType(deviceTypes, devicePort->type()) &&
                    devicePort->hasGainController(true /*canUseForVolume*/)) {
                float volumeAmpl = muted ? 0.0f : Volume::DbToAmpl(0);
                ALOGV("%s: output: %d, vs: %d, muted: %d, active vs count: %zu", __func__,
                      mIoHandle, vs, muted, getActiveVolumeSources().size());
                for (const auto &stream : streamTypes) {
                    mClientInterface->setStreamVolume(stream, volumeAmpl, mIoHandle, delayMs);
                }
                return;
            }
        }
    }
}

bool SwAudioOutputDescriptor::setVolume(float volumeDb, bool muted,
                                        VolumeSource vs, const StreamTypeVector &streamTypes,
                                        const DeviceTypeSet& deviceTypes,
                                        uint32_t delayMs,
                                        bool force)
{
    StreamTypeVector streams = streamTypes;
    if (!AudioOutputDescriptor::setVolume(volumeDb, vs, streamTypes, deviceTypes, delayMs, force)) {
    if (!AudioOutputDescriptor::setVolume(
            volumeDb, muted, vs, streamTypes, deviceTypes, delayMs, force)) {
        return false;
    }
    if (streams.empty()) {
@@ -459,11 +481,17 @@ bool SwAudioOutputDescriptor::setVolume(float volumeDb,
            // different Volume Source (or if we allow several curves within same volume group)
            //
            // @todo: default stream volume to max (0) when using HW Port gain?
            float volumeAmpl = Volume::DbToAmpl(0);
            // Allows to set SW Gain on AudioFlinger if:
            //    -volume group has explicit stream(s) associated
            //    -volume group with no explicit stream(s) is the only active source on this output
            // Allows to mute SW Gain on AudioFlinger only for volume group with explicit stream(s)
            if (!streamTypes.empty() || (getActiveVolumeSources().size() == 1)) {
                const bool canMute = muted && (volumeDb != 0.0f) && !streamTypes.empty();
                float volumeAmpl = canMute ? 0.0f : Volume::DbToAmpl(0);
                for (const auto &stream : streams) {
                    mClientInterface->setStreamVolume(stream, volumeAmpl, mIoHandle, delayMs);
                }

            }
            AudioGains gains = devicePort->getGains();
            int gainMinValueInMb = gains[0]->getMinValueInMb();
            int gainMaxValueInMb = gains[0]->getMaxValueInMb();
@@ -679,14 +707,14 @@ void HwAudioOutputDescriptor::toAudioPort(struct audio_port_v7 *port) const
}


bool HwAudioOutputDescriptor::setVolume(float volumeDb,
bool HwAudioOutputDescriptor::setVolume(float volumeDb, bool muted,
                                        VolumeSource volumeSource, const StreamTypeVector &streams,
                                        const DeviceTypeSet& deviceTypes,
                                        uint32_t delayMs,
                                        bool force)
{
    bool changed = AudioOutputDescriptor::setVolume(
            volumeDb, volumeSource, streams, deviceTypes, delayMs, force);
            volumeDb, muted, volumeSource, streams, deviceTypes, delayMs, force);

    if (changed) {
      // TODO: use gain controller on source device if any to adjust volume
+4 −1
Original line number Diff line number Diff line
@@ -2801,6 +2801,8 @@ status_t AudioPolicyManager::setVolumeIndexForAttributes(const audio_attributes_
        // HW Gain management, do not change the volume
        if (desc->useHwGain()) {
            applyVolume = false;
            // If the volume source is active with higher priority source, ensure at least Sw Muted
            desc->setSwMute((index == 0), vs, curves.getStreamTypes(), curDevices, 0 /*delayMs*/);
            for (const auto &productStrategy : mEngine->getOrderedProductStrategies()) {
                auto activeClients = desc->clientsList(true /*activeOnly*/, productStrategy,
                                                       false /*preferredDevice*/);
@@ -6575,8 +6577,9 @@ status_t AudioPolicyManager::checkAndSetVolume(IVolumeCurves &curves,
                    isSingleDeviceType(deviceTypes, audio_is_bluetooth_out_sco_device))) {
        volumeDb = 0.0f;
    }
    const bool muted = (index == 0) && (volumeDb != 0.0f);
    outputDesc->setVolume(
            volumeDb, volumeSource, curves.getStreamTypes(), deviceTypes, delayMs, force);
            volumeDb, muted, volumeSource, curves.getStreamTypes(), deviceTypes, delayMs, force);

    if (outputDesc == mPrimaryOutput && (isVoiceVolSrc || isBtScoVolSrc)) {
        float voiceVolume;