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

Commit 81d86fcd authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Implement volume control on default audio HAL" into main

parents 09b66d05 a33bb5ea
Loading
Loading
Loading
Loading
+50 −1
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ using aidl::android::media::audio::common::AudioDevice;
using aidl::android::media::audio::common::AudioDeviceType;
using aidl::android::media::audio::common::AudioFormatDescription;
using aidl::android::media::audio::common::AudioFormatType;
using aidl::android::media::audio::common::AudioGainConfig;
using aidl::android::media::audio::common::AudioInputFlags;
using aidl::android::media::audio::common::AudioIoFlags;
using aidl::android::media::audio::common::AudioMMapPolicy;
@@ -1200,7 +1201,9 @@ ndk::ScopedAStatus Module::setAudioPortConfigImpl(
    }

    if (in_requested.gain.has_value()) {
        // Let's pretend that gain can always be applied.
        if (!setAudioPortConfigGain(*portIt, in_requested.gain.value())) {
            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
        }
        out_suggested->gain = in_requested.gain.value();
    }

@@ -1242,6 +1245,52 @@ ndk::ScopedAStatus Module::setAudioPortConfigImpl(
    return ndk::ScopedAStatus::ok();
}

bool Module::setAudioPortConfigGain(const AudioPort& port, const AudioGainConfig& gainRequested) {
    auto& ports = getConfig().ports;
    if (gainRequested.index < 0 || gainRequested.index >= (int)port.gains.size()) {
        LOG(ERROR) << __func__ << ": gains for port " << port.id << " is undefined";
        return false;
    }
    int stepValue = port.gains[gainRequested.index].stepValue;
    if (stepValue == 0) {
        LOG(ERROR) << __func__ << ": port gain step value is 0";
        return false;
    }
    int minValue = port.gains[gainRequested.index].minValue;
    int maxValue = port.gains[gainRequested.index].maxValue;
    if (gainRequested.values[0] > maxValue || gainRequested.values[0] < minValue) {
        LOG(ERROR) << __func__ << ": gain value " << gainRequested.values[0]
                   << " out of range of min and max gain config";
        return false;
    }
    int gainIndex = (gainRequested.values[0] - minValue) / stepValue;
    int totalSteps = (maxValue - minValue) / stepValue;
    if (totalSteps == 0) {
        LOG(ERROR) << __func__ << ": difference between port gain min value " << minValue
                   << " and max value " << maxValue << " is less than step value " << stepValue;
        return false;
    }
    // Root-power quantities are used in curve:
    // 10^((minMb / 100 + (maxMb / 100 - minMb / 100) * gainIndex / totalSteps) / (10 * 2))
    // where 100 is the conversion from mB to dB, 10 comes from the log 10 conversion from power
    // ratios, and 2 means are the square of amplitude.
    float gain =
            pow(10, (minValue + (maxValue - minValue) * (gainIndex / (float)totalSteps)) / 2000);
    if (gain < 0) {
        LOG(ERROR) << __func__ << ": gain " << gain << " is less than 0";
        return false;
    }
    for (const auto& route : getConfig().routes) {
        if (route.sinkPortId != port.id) {
            continue;
        }
        for (const auto sourcePortId : route.sourcePortIds) {
            mStreams.setGain(sourcePortId, gain);
        }
    }
    return true;
}

ndk::ScopedAStatus Module::resetAudioPatch(int32_t in_patchId) {
    auto& patches = getConfig().patches;
    auto patchIt = findById<AudioPatch>(patches, in_patchId);
+5 −0
Original line number Diff line number Diff line
@@ -855,6 +855,11 @@ ndk::ScopedAStatus StreamCommonImpl::setConnectedDevices(
    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus StreamCommonImpl::setGain(float gain) {
    LOG(DEBUG) << __func__ << ": gain " << gain;
    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}

ndk::ScopedAStatus StreamCommonImpl::bluetoothParametersUpdated() {
    LOG(DEBUG) << __func__;
    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+8 −0
Original line number Diff line number Diff line
@@ -260,4 +260,12 @@ ndk::ScopedAStatus StreamSwitcher::bluetoothParametersUpdated() {
    return mStream->bluetoothParametersUpdated();
}

ndk::ScopedAStatus StreamSwitcher::setGain(float gain) {
    if (mStream == nullptr) {
        LOG(ERROR) << __func__ << ": stream was closed";
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    }
    return mStream->setGain(gain);
}

}  // namespace aidl::android::hardware::audio::core
+6 −0
Original line number Diff line number Diff line
@@ -117,6 +117,7 @@ StreamAlsa::~StreamAlsa() {
                                mReadWriteRetries);
        maxLatency = proxy_get_latency(mAlsaDeviceProxies[0].get());
    } else {
        alsa::applyGain(buffer, mGain, bytesToTransfer, mConfig.value().format, mConfig->channels);
        for (auto& proxy : mAlsaDeviceProxies) {
            proxy_write_with_retries(proxy.get(), buffer, bytesToTransfer, mReadWriteRetries);
            maxLatency = std::max(maxLatency, proxy_get_latency(proxy.get()));
@@ -166,4 +167,9 @@ void StreamAlsa::shutdown() {
    mAlsaDeviceProxies.clear();
}

ndk::ScopedAStatus StreamAlsa::setGain(float gain) {
    mGain = gain;
    return ndk::ScopedAStatus::ok();
}

}  // namespace aidl::android::hardware::audio::core
+66 −0
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@
#include <aidl/android/media/audio/common/AudioFormatType.h>
#include <aidl/android/media/audio/common/PcmType.h>
#include <android-base/logging.h>
#include <audio_utils/primitives.h>
#include <cutils/compiler.h>

#include "Utils.h"
#include "core-impl/utils.h"
@@ -343,4 +345,68 @@ pcm_format aidl2c_AudioFormatDescription_pcm_format(const AudioFormatDescription
    return findValueOrDefault(getAudioFormatDescriptorToPcmFormatMap(), aidl, PCM_FORMAT_INVALID);
}

void applyGain(void* buffer, float gain, size_t bytesToTransfer, enum pcm_format pcmFormat,
               int channelCount) {
    if (channelCount != 1 && channelCount != 2) {
        LOG(WARNING) << __func__ << ": unsupported channel count " << channelCount;
        return;
    }
    if (!getPcmFormatToAudioFormatDescMap().contains(pcmFormat)) {
        LOG(WARNING) << __func__ << ": unsupported pcm format " << pcmFormat;
        return;
    }
    const float unityGainFloat = 1.0f;
    if (std::abs(gain - unityGainFloat) < 1e-6) {
        return;
    }
    int numFrames;
    switch (pcmFormat) {
        case PCM_FORMAT_S16_LE: {
            const uint16_t unityGainQ4_12 = u4_12_from_float(unityGainFloat);
            const uint16_t vl = u4_12_from_float(gain);
            const uint32_t vrl = (vl << 16) | vl;
            if (channelCount == 2) {
                numFrames = bytesToTransfer / sizeof(uint32_t);
                uint32_t* intBuffer = (uint32_t*)buffer;
                if (CC_UNLIKELY(vl > unityGainQ4_12)) {
                    // volume is boosted, so we might need to clamp even though
                    // we process only one track.
                    do {
                        int32_t l = mulRL(1, *intBuffer, vrl) >> 12;
                        int32_t r = mulRL(0, *intBuffer, vrl) >> 12;
                        l = clamp16(l);
                        r = clamp16(r);
                        *intBuffer++ = (r << 16) | (l & 0xFFFF);
                    } while (--numFrames);
                } else {
                    do {
                        int32_t l = mulRL(1, *intBuffer, vrl) >> 12;
                        int32_t r = mulRL(0, *intBuffer, vrl) >> 12;
                        *intBuffer++ = (r << 16) | (l & 0xFFFF);
                    } while (--numFrames);
                }
            } else {
                numFrames = bytesToTransfer / sizeof(uint16_t);
                int16_t* intBuffer = (int16_t*)buffer;
                if (CC_UNLIKELY(vl > unityGainQ4_12)) {
                    // volume is boosted, so we might need to clamp even though
                    // we process only one track.
                    do {
                        int32_t mono = mulRL(1, *intBuffer, vrl) >> 12;
                        *intBuffer++ = clamp16(mono);
                    } while (--numFrames);
                } else {
                    do {
                        int32_t mono = mulRL(1, *intBuffer, vrl) >> 12;
                        *intBuffer++ = static_cast<int16_t>(mono & 0xFFFF);
                    } while (--numFrames);
                }
            }
        } break;
        default:
            // TODO(336370745): Implement gain for other supported formats
            break;
    }
}

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