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

Commit 12c4bf6b authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge changes from topic "fix-b-264712385-primary-module" into main

* changes:
  audio: Move StreamContext ownership out from StreamCommonImpl
  audio: Use ChildInterface in StreamCommonImpl
  audio: Update StreamAlsa and alsa utils for built-in devices
  audio: Simplify and extend alsa::Mixer
parents 2a5366d8 6ddefdbc
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -675,7 +675,7 @@ ndk::ScopedAStatus Module::openInputStream(const OpenInputStreamArguments& in_ar
                                               nullptr, nullptr, &context));
    context.fillDescriptor(&_aidl_return->desc);
    std::shared_ptr<StreamIn> stream;
    RETURN_STATUS_IF_ERROR(createInputStream(in_args.sinkMetadata, std::move(context),
    RETURN_STATUS_IF_ERROR(createInputStream(std::move(context), in_args.sinkMetadata,
                                             mConfig->microphones, &stream));
    StreamWrapper streamWrapper(stream);
    if (auto patchIt = mPatches.find(in_args.portConfigId); patchIt != mPatches.end()) {
@@ -721,7 +721,7 @@ ndk::ScopedAStatus Module::openOutputStream(const OpenOutputStreamArguments& in_
                                               in_args.eventCallback, &context));
    context.fillDescriptor(&_aidl_return->desc);
    std::shared_ptr<StreamOut> stream;
    RETURN_STATUS_IF_ERROR(createOutputStream(in_args.sourceMetadata, std::move(context),
    RETURN_STATUS_IF_ERROR(createOutputStream(std::move(context), in_args.sourceMetadata,
                                              in_args.offloadInfo, &stream));
    StreamWrapper streamWrapper(stream);
    if (auto patchIt = mPatches.find(in_args.portConfigId); patchIt != mPatches.end()) {
+7 −6
Original line number Diff line number Diff line
@@ -38,22 +38,23 @@ ndk::ScopedAStatus ModulePrimary::getTelephony(std::shared_ptr<ITelephony>* _aid
        mTelephony = ndk::SharedRefBase::make<Telephony>();
    }
    *_aidl_return = mTelephony.getPtr();
    LOG(DEBUG) << __func__ << ": returning instance of ITelephony: " << _aidl_return->get();
    LOG(DEBUG) << __func__
               << ": returning instance of ITelephony: " << _aidl_return->get()->asBinder().get();
    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus ModulePrimary::createInputStream(const SinkMetadata& sinkMetadata,
                                                    StreamContext&& context,
ndk::ScopedAStatus ModulePrimary::createInputStream(StreamContext&& context,
                                                    const SinkMetadata& sinkMetadata,
                                                    const std::vector<MicrophoneInfo>& microphones,
                                                    std::shared_ptr<StreamIn>* result) {
    return createStreamInstance<StreamInStub>(result, sinkMetadata, std::move(context),
    return createStreamInstance<StreamInStub>(result, std::move(context), sinkMetadata,
                                              microphones);
}

ndk::ScopedAStatus ModulePrimary::createOutputStream(
        const SourceMetadata& sourceMetadata, StreamContext&& context,
        StreamContext&& context, const SourceMetadata& sourceMetadata,
        const std::optional<AudioOffloadInfo>& offloadInfo, std::shared_ptr<StreamOut>* result) {
    return createStreamInstance<StreamOutStub>(result, sourceMetadata, std::move(context),
    return createStreamInstance<StreamOutStub>(result, std::move(context), sourceMetadata,
                                               offloadInfo);
}

+24 −12
Original line number Diff line number Diff line
@@ -47,13 +47,19 @@ void StreamContext::fillDescriptor(StreamDescriptor* desc) {
        desc->reply = mReplyMQ->dupeDesc();
    }
    if (mDataMQ) {
        const size_t frameSize = getFrameSize();
        desc->frameSizeBytes = frameSize;
        desc->bufferSizeFrames = mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize() / frameSize;
        desc->frameSizeBytes = getFrameSize();
        desc->bufferSizeFrames = getBufferSizeInFrames();
        desc->audio.set<StreamDescriptor::AudioBuffer::Tag::fmq>(mDataMQ->dupeDesc());
    }
}

size_t StreamContext::getBufferSizeInFrames() const {
    if (mDataMQ) {
        return mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize() / getFrameSize();
    }
    return 0;
}

size_t StreamContext::getFrameSize() const {
    return getFrameSizeInBytes(mFormat, mChannelLayout);
}
@@ -597,18 +603,16 @@ StreamCommonImpl::~StreamCommonImpl() {
ndk::ScopedAStatus StreamCommonImpl::initInstance(
        const std::shared_ptr<StreamCommonInterface>& delegate) {
    mCommon = ndk::SharedRefBase::make<StreamCommonDelegator>(delegate);
    mCommonBinder = mCommon->asBinder();
    AIBinder_setMinSchedulerPolicy(mCommonBinder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
    return mWorker->start() ? ndk::ScopedAStatus::ok()
                            : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}

ndk::ScopedAStatus StreamCommonImpl::getStreamCommonCommon(
        std::shared_ptr<IStreamCommon>* _aidl_return) {
    if (mCommon == nullptr) {
    if (!mCommon) {
        LOG(FATAL) << __func__ << ": the common interface was not created";
    }
    *_aidl_return = mCommon;
    *_aidl_return = mCommon.getPtr();
    LOG(DEBUG) << __func__ << ": returning " << _aidl_return->get()->asBinder().get();
    return ndk::ScopedAStatus::ok();
}
@@ -659,7 +663,7 @@ ndk::ScopedAStatus StreamCommonImpl::close() {
        LOG(DEBUG) << __func__ << ": joining the worker thread...";
        mWorker->stop();
        LOG(DEBUG) << __func__ << ": worker thread joined";
        mContext.reset();
        onClose();
        mWorker->setClosed();
        return ndk::ScopedAStatus::ok();
    } else {
@@ -723,11 +727,15 @@ static std::map<AudioDevice, std::string> transformMicrophones(
}
}  // namespace

StreamIn::StreamIn(const std::vector<MicrophoneInfo>& microphones)
    : mMicrophones(transformMicrophones(microphones)) {
StreamIn::StreamIn(StreamContext&& context, const std::vector<MicrophoneInfo>& microphones)
    : mContext(std::move(context)), mMicrophones(transformMicrophones(microphones)) {
    LOG(DEBUG) << __func__;
}

void StreamIn::defaultOnClose() {
    mContext.reset();
}

ndk::ScopedAStatus StreamIn::getActiveMicrophones(
        std::vector<MicrophoneDynamicInfo>* _aidl_return) {
    std::vector<MicrophoneDynamicInfo> result;
@@ -780,11 +788,15 @@ ndk::ScopedAStatus StreamIn::setHwGain(const std::vector<float>& in_channelGains
    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}

StreamOut::StreamOut(const std::optional<AudioOffloadInfo>& offloadInfo)
    : mOffloadInfo(offloadInfo) {
StreamOut::StreamOut(StreamContext&& context, const std::optional<AudioOffloadInfo>& offloadInfo)
    : mContext(std::move(context)), mOffloadInfo(offloadInfo) {
    LOG(DEBUG) << __func__;
}

void StreamOut::defaultOnClose() {
    mContext.reset();
}

ndk::ScopedAStatus StreamOut::updateOffloadMetadata(
        const AudioOffloadMetadata& in_offloadMetadata) {
    LOG(DEBUG) << __func__;
+115 −70
Original line number Diff line number Diff line
@@ -14,44 +14,17 @@
 * limitations under the License.
 */

#define LOG_TAG "AHAL_AlsaMixer"
#include <android-base/logging.h>

#include <algorithm>
#include <cmath>

#define LOG_TAG "AHAL_AlsaMixer"
#include <android-base/logging.h>
#include <android/binder_status.h>

#include "Mixer.h"

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

//-----------------------------------------------------------------------------

MixerControl::MixerControl(struct mixer_ctl* ctl)
    : mCtl(ctl),
      mNumValues(mixer_ctl_get_num_values(ctl)),
      mMinValue(mixer_ctl_get_range_min(ctl)),
      mMaxValue(mixer_ctl_get_range_max(ctl)) {}

unsigned int MixerControl::getNumValues() const {
    return mNumValues;
}

int MixerControl::getMaxValue() const {
    return mMaxValue;
}

int MixerControl::getMinValue() const {
    return mMinValue;
}

int MixerControl::setArray(const void* array, size_t count) {
    const std::lock_guard guard(mLock);
    return mixer_ctl_set_array(mCtl, array, count);
}

//-----------------------------------------------------------------------------

// static
const std::map<Mixer::Control, std::vector<Mixer::ControlNamesAndExpectedCtlType>>
        Mixer::kPossibleControls = {
@@ -60,18 +33,20 @@ const std::map<Mixer::Control, std::vector<Mixer::ControlNamesAndExpectedCtlType
                {Mixer::HW_VOLUME,
                 {{"Headphone Playback Volume", MIXER_CTL_TYPE_INT},
                  {"Headset Playback Volume", MIXER_CTL_TYPE_INT},
                  {"PCM Playback Volume", MIXER_CTL_TYPE_INT}}}};
                  {"PCM Playback Volume", MIXER_CTL_TYPE_INT}}},
                {Mixer::MIC_SWITCH, {{"Capture Switch", MIXER_CTL_TYPE_BOOL}}},
                {Mixer::MIC_GAIN, {{"Capture Volume", MIXER_CTL_TYPE_INT}}}};

// static
std::map<Mixer::Control, std::shared_ptr<MixerControl>> Mixer::initializeMixerControls(
        struct mixer* mixer) {
    std::map<Mixer::Control, std::shared_ptr<MixerControl>> mixerControls;
Mixer::Controls Mixer::initializeMixerControls(struct mixer* mixer) {
    if (mixer == nullptr) return {};
    Controls mixerControls;
    std::string mixerCtlNames;
    for (const auto& [control, possibleCtls] : kPossibleControls) {
        for (const auto& [ctlName, expectedCtlType] : possibleCtls) {
            struct mixer_ctl* ctl = mixer_get_ctl_by_name(mixer, ctlName.c_str());
            if (ctl != nullptr && mixer_ctl_get_type(ctl) == expectedCtlType) {
                mixerControls.emplace(control, std::make_unique<MixerControl>(ctl));
                mixerControls.emplace(control, ctl);
                if (!mixerCtlNames.empty()) {
                    mixerCtlNames += ",";
                }
@@ -84,71 +59,141 @@ std::map<Mixer::Control, std::shared_ptr<MixerControl>> Mixer::initializeMixerCo
    return mixerControls;
}

Mixer::Mixer(struct mixer* mixer)
    : mMixer(mixer), mMixerControls(initializeMixerControls(mMixer)) {}
std::ostream& operator<<(std::ostream& s, Mixer::Control c) {
    switch (c) {
        case Mixer::Control::MASTER_SWITCH:
            s << "master mute";
            break;
        case Mixer::Control::MASTER_VOLUME:
            s << "master volume";
            break;
        case Mixer::Control::HW_VOLUME:
            s << "volume";
            break;
        case Mixer::Control::MIC_SWITCH:
            s << "mic mute";
            break;
        case Mixer::Control::MIC_GAIN:
            s << "mic gain";
            break;
    }
    return s;
}

Mixer::Mixer(int card) : mMixer(mixer_open(card)), mMixerControls(initializeMixerControls(mMixer)) {
    if (!isValid()) {
        PLOG(ERROR) << __func__ << ": failed to open mixer for card=" << card;
    }
}

Mixer::~Mixer() {
    if (isValid()) {
        std::lock_guard l(mMixerAccess);
        mixer_close(mMixer);
    }
}

namespace {
ndk::ScopedAStatus Mixer::setMasterMute(bool muted) {
    return setMixerControlMute(MASTER_SWITCH, muted);
}

int volumeFloatToInteger(float fValue, int maxValue, int minValue) {
    return minValue + std::ceil((maxValue - minValue) * fValue);
ndk::ScopedAStatus Mixer::setMasterVolume(float volume) {
    return setMixerControlVolume(MASTER_VOLUME, volume);
}

}  // namespace
ndk::ScopedAStatus Mixer::setMicGain(float gain) {
    return setMixerControlVolume(MIC_GAIN, gain);
}

ndk::ScopedAStatus Mixer::setMasterMute(bool muted) {
    auto it = mMixerControls.find(Mixer::MASTER_SWITCH);
ndk::ScopedAStatus Mixer::setMicMute(bool muted) {
    return setMixerControlMute(MIC_SWITCH, 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);
    }
    const int numValues = it->second->getNumValues();
    std::vector<int> values(numValues, muted ? 0 : 1);
    if (int err = it->second->setArray(values.data(), numValues); err != 0) {
        LOG(ERROR) << __func__ << ": failed to set master mute, err=" << err;
    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) {
        LOG(ERROR) << __func__ << ": failed to set volume, err=" << err;
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    }
    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus Mixer::setMasterVolume(float volume) {
    auto it = mMixerControls.find(Mixer::MASTER_VOLUME);
ndk::ScopedAStatus Mixer::setMixerControlMute(Mixer::Control ctl, bool muted) {
    if (!isValid()) {
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    }
    auto it = mMixerControls.find(ctl);
    if (it == mMixerControls.end()) {
        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
    }
    const int numValues = it->second->getNumValues();
    std::vector<int> values(numValues, volumeFloatToInteger(volume, it->second->getMaxValue(),
                                                            it->second->getMinValue()));
    if (int err = it->second->setArray(values.data(), numValues); err != 0) {
        LOG(ERROR) << __func__ << ": failed to set master volume, err=" << err;
    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;
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    }
    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus Mixer::setVolumes(const std::vector<float>& volumes) {
    auto it = mMixerControls.find(Mixer::HW_VOLUME);
ndk::ScopedAStatus Mixer::setMixerControlVolume(Control ctl, float volume) {
    if (!isValid()) {
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    }
    auto it = mMixerControls.find(ctl);
    if (it == mMixerControls.end()) {
        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
    }
    const int numValues = it->second->getNumValues();
    if (numValues < 0) {
        LOG(FATAL) << __func__ << ": negative number of values: " << numValues;
    }
    const int maxValue = it->second->getMaxValue();
    const int minValue = it->second->getMinValue();
    std::vector<int> values;
    size_t i = 0;
    for (; i < static_cast<size_t>(numValues) && i < values.size(); ++i) {
        values.emplace_back(volumeFloatToInteger(volumes[i], maxValue, minValue));
    }
    if (int err = it->second->setArray(values.data(), values.size()); err != 0) {
        LOG(ERROR) << __func__ << ": failed to set volume, err=" << err;
    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) {
        LOG(ERROR) << __func__ << ": failed to set " << ctl << " to " << volume << ", err=" << err;
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    }
    return ndk::ScopedAStatus::ok();
}

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 ret;
}

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 ret;
}

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 ret;
}

}  // namespace aidl::android::hardware::audio::core::alsa
+24 −25
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

#pragma once

#include <iostream>
#include <map>
#include <memory>
#include <mutex>
@@ -31,34 +32,17 @@ extern "C" {

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

class MixerControl {
  public:
    explicit MixerControl(struct mixer_ctl* ctl);

    unsigned int getNumValues() const;
    int getMaxValue() const;
    int getMinValue() const;
    int setArray(const void* array, size_t count);

  private:
    std::mutex mLock;
    // The mixer_ctl object is owned by ALSA and will be released when the mixer is closed.
    struct mixer_ctl* mCtl GUARDED_BY(mLock);
    const unsigned int mNumValues;
    const int mMinValue;
    const int mMaxValue;
};

class Mixer {
  public:
    explicit Mixer(struct mixer* mixer);

    explicit Mixer(int card);
    ~Mixer();

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

    ndk::ScopedAStatus setMasterMute(bool muted);
    ndk::ScopedAStatus setMasterVolume(float volume);
    ndk::ScopedAStatus setMicGain(float gain);
    ndk::ScopedAStatus setMicMute(bool muted);
    ndk::ScopedAStatus setVolumes(const std::vector<float>& volumes);

  private:
@@ -66,17 +50,32 @@ class Mixer {
        MASTER_SWITCH,
        MASTER_VOLUME,
        HW_VOLUME,
        MIC_SWITCH,
        MIC_GAIN,
    };
    using ControlNamesAndExpectedCtlType = std::pair<std::string, enum mixer_ctl_type>;
    using Controls = std::map<Control, struct mixer_ctl*>;

    friend std::ostream& operator<<(std::ostream&, Control);
    static const std::map<Control, std::vector<ControlNamesAndExpectedCtlType>> kPossibleControls;
    static std::map<Control, std::shared_ptr<MixerControl>> initializeMixerControls(
            struct mixer* mixer);
    static Controls initializeMixerControls(struct mixer* mixer);

    ndk::ScopedAStatus setMixerControlMute(Control ctl, bool muted);
    ndk::ScopedAStatus setMixerControlVolume(Control ctl, float volume);

    int setMixerControlPercent(struct mixer_ctl* ctl, int percent) REQUIRES(mMixerAccess);
    int setMixerControlPercent(struct mixer_ctl* ctl, const std::vector<int>& percents)
            REQUIRES(mMixerAccess);
    int setMixerControlValue(struct mixer_ctl* ctl, int value) REQUIRES(mMixerAccess);

    // Since ALSA functions do not use internal locking, enforce thread safety at our level.
    std::mutex mMixerAccess;
    // The mixer object is owned by ALSA and will be released when the mixer is closed.
    struct mixer* mMixer;
    struct mixer* const mMixer;
    // `mMixerControls` will only be initialized in constructor. After that, it wil only be
    // read but not be modified.
    const std::map<Control, std::shared_ptr<MixerControl>> mMixerControls;
    // read but not be modified. Each mixer_ctl object is owned by ALSA, it's life span is
    // the same as of the mixer itself.
    const Controls mMixerControls;
};

}  // namespace aidl::android::hardware::audio::core::alsa
Loading