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

Commit 49bcb926 authored by Mikhail Naganov's avatar Mikhail Naganov
Browse files

audio: Implement getters for hardware mixer controls

The VTS test for volume accessors first determines whether
the accessor is supported by calling the getter. The getter
must return `UNSUPPORTED_OPERATION` if the control is not
supported. For this reason, wire the getter to the hardware
mixer implementation.

Bug: 302132812
Test: atest VtsHalAudioCoreTargetTest
Change-Id: Ia50def0d076b6d3c46db55123186eab34bbbb954
parent 55045b5f
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -848,7 +848,7 @@ ndk::ScopedAStatus StreamIn::setHwGain(const std::vector<float>& in_channelGains
}

StreamInHwGainHelper::StreamInHwGainHelper(const StreamContext* context)
    : mChannelCount(getChannelCount(context->getChannelLayout())) {}
    : mChannelCount(getChannelCount(context->getChannelLayout())), mHwGains(mChannelCount, 0.0f) {}

ndk::ScopedAStatus StreamInHwGainHelper::getHwGainImpl(std::vector<float>* _aidl_return) {
    *_aidl_return = mHwGains;
@@ -979,7 +979,8 @@ ndk::ScopedAStatus StreamOut::selectPresentation(int32_t in_presentationId, int3
}

StreamOutHwVolumeHelper::StreamOutHwVolumeHelper(const StreamContext* context)
    : mChannelCount(getChannelCount(context->getChannelLayout())) {}
    : mChannelCount(getChannelCount(context->getChannelLayout())),
      mHwVolumes(mChannelCount, 0.0f) {}

ndk::ScopedAStatus StreamOutHwVolumeHelper::getHwVolumeImpl(std::vector<float>* _aidl_return) {
    *_aidl_return = mHwVolumes;
+127 −29
Original line number Diff line number Diff line
@@ -20,9 +20,24 @@
#define LOG_TAG "AHAL_AlsaMixer"
#include <android-base/logging.h>
#include <android/binder_status.h>
#include <error/expected_utils.h>

#include "Mixer.h"

namespace ndk {

// This enables use of 'error/expected_utils' for ScopedAStatus.

inline bool errorIsOk(const ScopedAStatus& s) {
    return s.isOk();
}

inline std::string errorToString(const ScopedAStatus& s) {
    return s.getDescription();
}

}  // namespace ndk

namespace aidl::android::hardware::audio::core::alsa {

// static
@@ -93,6 +108,36 @@ Mixer::~Mixer() {
    }
}

ndk::ScopedAStatus Mixer::getMasterMute(bool* muted) {
    return getMixerControlMute(MASTER_SWITCH, muted);
}

ndk::ScopedAStatus Mixer::getMasterVolume(float* volume) {
    return getMixerControlVolume(MASTER_VOLUME, volume);
}

ndk::ScopedAStatus Mixer::getMicGain(float* gain) {
    return getMixerControlVolume(MIC_GAIN, gain);
}

ndk::ScopedAStatus Mixer::getMicMute(bool* muted) {
    return getMixerControlMute(MIC_SWITCH, muted);
}

ndk::ScopedAStatus Mixer::getVolumes(std::vector<float>* volumes) {
    struct mixer_ctl* mctl;
    RETURN_STATUS_IF_ERROR(findControl(Mixer::HW_VOLUME, &mctl));
    std::vector<int> percents;
    std::lock_guard l(mMixerAccess);
    if (int err = getMixerControlPercent(mctl, &percents); err != 0) {
        LOG(ERROR) << __func__ << ": failed to get volume, err=" << err;
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    }
    std::transform(percents.begin(), percents.end(), std::back_inserter(*volumes),
                   [](int percent) -> float { return std::clamp(percent / 100.0f, 0.0f, 1.0f); });
    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus Mixer::setMasterMute(bool muted) {
    return setMixerControlMute(MASTER_SWITCH, muted);
}
@@ -110,90 +155,143 @@ ndk::ScopedAStatus Mixer::setMicMute(bool muted) {
}

ndk::ScopedAStatus Mixer::setVolumes(const std::vector<float>& volumes) {
    if (!isValid()) {
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    }
    auto it = mMixerControls.find(Mixer::HW_VOLUME);
    if (it == mMixerControls.end()) {
        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
    }
    struct mixer_ctl* mctl;
    RETURN_STATUS_IF_ERROR(findControl(Mixer::HW_VOLUME, &mctl));
    std::vector<int> percents;
    std::transform(
            volumes.begin(), volumes.end(), std::back_inserter(percents),
            [](float volume) -> int { return std::floor(std::clamp(volume, 0.0f, 1.0f) * 100); });
    std::lock_guard l(mMixerAccess);
    if (int err = setMixerControlPercent(it->second, percents); err != 0) {
    if (int err = setMixerControlPercent(mctl, percents); err != 0) {
        LOG(ERROR) << __func__ << ": failed to set volume, err=" << err;
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    }
    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus Mixer::setMixerControlMute(Mixer::Control ctl, bool muted) {
ndk::ScopedAStatus Mixer::findControl(Control ctl, struct mixer_ctl** result) {
    if (!isValid()) {
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    }
    auto it = mMixerControls.find(ctl);
    if (it == mMixerControls.end()) {
    if (auto it = mMixerControls.find(ctl); it != mMixerControls.end()) {
        *result = it->second;
        return ndk::ScopedAStatus::ok();
    }
    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}

ndk::ScopedAStatus Mixer::getMixerControlMute(Control ctl, bool* muted) {
    struct mixer_ctl* mctl;
    RETURN_STATUS_IF_ERROR(findControl(ctl, &mctl));
    std::lock_guard l(mMixerAccess);
    if (int err = setMixerControlValue(it->second, muted ? 0 : 1); err != 0) {
        LOG(ERROR) << __func__ << ": failed to set " << ctl << " to " << muted << ", err=" << err;
    std::vector<int> mutedValues;
    if (int err = getMixerControlValues(mctl, &mutedValues); err != 0) {
        LOG(ERROR) << __func__ << ": failed to get " << ctl << ", err=" << err;
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    }
    if (mutedValues.empty()) {
        LOG(ERROR) << __func__ << ": got no values for " << ctl;
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    }
    *muted = mutedValues[0] != 0;
    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus Mixer::setMixerControlVolume(Control ctl, float volume) {
    if (!isValid()) {
ndk::ScopedAStatus Mixer::getMixerControlVolume(Control ctl, float* volume) {
    struct mixer_ctl* mctl;
    RETURN_STATUS_IF_ERROR(findControl(ctl, &mctl));
    std::lock_guard l(mMixerAccess);
    std::vector<int> percents;
    if (int err = getMixerControlPercent(mctl, &percents); err != 0) {
        LOG(ERROR) << __func__ << ": failed to get " << ctl << ", err=" << err;
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    }
    auto it = mMixerControls.find(ctl);
    if (it == mMixerControls.end()) {
        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
    if (percents.empty()) {
        LOG(ERROR) << __func__ << ": got no values for " << ctl;
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    }
    *volume = std::clamp(percents[0] / 100.0f, 0.0f, 1.0f);
    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus Mixer::setMixerControlMute(Control ctl, bool muted) {
    struct mixer_ctl* mctl;
    RETURN_STATUS_IF_ERROR(findControl(ctl, &mctl));
    std::lock_guard l(mMixerAccess);
    if (int err = setMixerControlValue(mctl, muted ? 0 : 1); err != 0) {
        LOG(ERROR) << __func__ << ": failed to set " << ctl << " to " << muted << ", err=" << err;
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    }
    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus Mixer::setMixerControlVolume(Control ctl, float volume) {
    struct mixer_ctl* mctl;
    RETURN_STATUS_IF_ERROR(findControl(ctl, &mctl));
    volume = std::clamp(volume, 0.0f, 1.0f);
    std::lock_guard l(mMixerAccess);
    if (int err = setMixerControlPercent(it->second, std::floor(volume * 100)); err != 0) {
    if (int err = setMixerControlPercent(mctl, std::floor(volume * 100)); err != 0) {
        LOG(ERROR) << __func__ << ": failed to set " << ctl << " to " << volume << ", err=" << err;
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    }
    return ndk::ScopedAStatus::ok();
}

int Mixer::getMixerControlPercent(struct mixer_ctl* ctl, std::vector<int>* percents) {
    const unsigned int n = mixer_ctl_get_num_values(ctl);
    percents->resize(n);
    for (unsigned int id = 0; id < n; id++) {
        if (int valueOrError = mixer_ctl_get_percent(ctl, id); valueOrError >= 0) {
            (*percents)[id] = valueOrError;
        } else {
            return valueOrError;
        }
    }
    return 0;
}

int Mixer::getMixerControlValues(struct mixer_ctl* ctl, std::vector<int>* values) {
    const unsigned int n = mixer_ctl_get_num_values(ctl);
    values->resize(n);
    for (unsigned int id = 0; id < n; id++) {
        if (int valueOrError = mixer_ctl_get_value(ctl, id); valueOrError >= 0) {
            (*values)[id] = valueOrError;
        } else {
            return valueOrError;
        }
    }
    return 0;
}

int Mixer::setMixerControlPercent(struct mixer_ctl* ctl, int percent) {
    int ret = 0;
    const unsigned int n = mixer_ctl_get_num_values(ctl);
    for (unsigned int id = 0; id < n; id++) {
        if (int error = mixer_ctl_set_percent(ctl, id, percent); error != 0) {
            ret = error;
            return error;
        }
    }
    return ret;
    return 0;
}

int Mixer::setMixerControlPercent(struct mixer_ctl* ctl, const std::vector<int>& percents) {
    int ret = 0;
    const unsigned int n = mixer_ctl_get_num_values(ctl);
    for (unsigned int id = 0; id < n; id++) {
        if (int error = mixer_ctl_set_percent(ctl, id, id < percents.size() ? percents[id] : 0);
            error != 0) {
            ret = error;
            return error;
        }
    }
    return ret;
    return 0;
}

int Mixer::setMixerControlValue(struct mixer_ctl* ctl, int value) {
    int ret = 0;
    const unsigned int n = mixer_ctl_get_num_values(ctl);
    for (unsigned int id = 0; id < n; id++) {
        if (int error = mixer_ctl_set_value(ctl, id, value); error != 0) {
            ret = error;
            return error;
        }
    }
    return ret;
    return 0;
}

}  // namespace aidl::android::hardware::audio::core::alsa
+12 −0
Original line number Diff line number Diff line
@@ -39,6 +39,11 @@ class Mixer {

    bool isValid() const { return mMixer != nullptr; }

    ndk::ScopedAStatus getMasterMute(bool* muted);
    ndk::ScopedAStatus getMasterVolume(float* volume);
    ndk::ScopedAStatus getMicGain(float* gain);
    ndk::ScopedAStatus getMicMute(bool* muted);
    ndk::ScopedAStatus getVolumes(std::vector<float>* volumes);
    ndk::ScopedAStatus setMasterMute(bool muted);
    ndk::ScopedAStatus setMasterVolume(float volume);
    ndk::ScopedAStatus setMicGain(float gain);
@@ -60,9 +65,16 @@ class Mixer {
    static const std::map<Control, std::vector<ControlNamesAndExpectedCtlType>> kPossibleControls;
    static Controls initializeMixerControls(struct mixer* mixer);

    ndk::ScopedAStatus findControl(Control ctl, struct mixer_ctl** result);
    ndk::ScopedAStatus getMixerControlMute(Control ctl, bool* muted);
    ndk::ScopedAStatus getMixerControlVolume(Control ctl, float* volume);
    ndk::ScopedAStatus setMixerControlMute(Control ctl, bool muted);
    ndk::ScopedAStatus setMixerControlVolume(Control ctl, float volume);

    int getMixerControlPercent(struct mixer_ctl* ctl, std::vector<int>* percents)
            REQUIRES(mMixerAccess);
    int getMixerControlValues(struct mixer_ctl* ctl, std::vector<int>* values)
            REQUIRES(mMixerAccess);
    int setMixerControlPercent(struct mixer_ctl* ctl, int percent) REQUIRES(mMixerAccess);
    int setMixerControlPercent(struct mixer_ctl* ctl, const std::vector<int>& percents)
            REQUIRES(mMixerAccess);
+8 −0
Original line number Diff line number Diff line
@@ -127,6 +127,11 @@ ndk::ScopedAStatus StreamInPrimary::getHwGain(std::vector<float>* _aidl_return)
    if (isStubStream()) {
        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
    }
    float gain;
    RETURN_STATUS_IF_ERROR(primary::PrimaryMixer::getInstance().getMicGain(&gain));
    _aidl_return->resize(0);
    _aidl_return->resize(mChannelCount, gain);
    RETURN_STATUS_IF_ERROR(setHwGainImpl(*_aidl_return));
    return getHwGainImpl(_aidl_return);
}

@@ -194,6 +199,9 @@ ndk::ScopedAStatus StreamOutPrimary::getHwVolume(std::vector<float>* _aidl_retur
    if (isStubStream()) {
        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
    }
    RETURN_STATUS_IF_ERROR(primary::PrimaryMixer::getInstance().getVolumes(_aidl_return));
    _aidl_return->resize(mChannelCount);
    RETURN_STATUS_IF_ERROR(setHwVolumeImpl(*_aidl_return));
    return getHwVolumeImpl(_aidl_return);
}