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

Commit 9ffe064d authored by Xin Li's avatar Xin Li
Browse files

Merge 25Q1 (ab/BP1A.250305.020) to AOSP main

Bug: 385190204
Merged-In: I9feb973fa9387d4dbc3f3ef6352948d17a1aa5ee
Change-Id: I1ba2e44aa7411ef164095c9bec1f627f5626a859
parents ac3f49f3 49d2deaa
Loading
Loading
Loading
Loading
+41 −0
Original line number Diff line number Diff line
@@ -202,6 +202,47 @@ cc_test {
    test_suites: ["general-tests"],
}

cc_test {
    name: "audio_alsa_utils_tests",
    vendor_available: true,
    defaults: [
        "latest_android_media_audio_common_types_ndk_static",
        "latest_android_hardware_audio_core_ndk_static",
    ],
    static_libs: [
        "libalsautilsv2",
        "libtinyalsav2",
    ],
    shared_libs: [
        "libaudio_aidl_conversion_common_ndk",
        "libaudioaidlcommon",
        "libaudioutils",
        "libbase",
        "libbinder_ndk",
        "libcutils",
        "libfmq",
        "libmedia_helper",
        "libstagefright_foundation",
        "libutils",
    ],
    header_libs: [
        "libaudio_system_headers",
        "libaudioaidl_headers",
    ],
    srcs: [
        "alsa/Utils.cpp",
        "tests/AlsaUtilsTest.cpp",
    ],
    cflags: [
        "-Wall",
        "-Wextra",
        "-Werror",
        "-Wthread-safety",
        "-DBACKEND_NDK",
    ],
    test_suites: ["general-tests"],
}

cc_defaults {
    name: "aidlaudioeffectservice_defaults",
    defaults: [
+114 −46
Original line number Diff line number Diff line
@@ -39,6 +39,8 @@ using aidl::android::media::audio::common::PcmType;

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

const float kUnityGainFloat = 1.0f;

DeviceProxy::DeviceProxy() : mProfile(nullptr), mProxy(nullptr, alsaProxyDeleter) {}

DeviceProxy::DeviceProxy(const DeviceProfile& deviceProfile)
@@ -140,7 +142,6 @@ AudioFormatDescription make_AudioFormatDescription(PcmType pcm) {

const AudioFormatDescToPcmFormatMap& getAudioFormatDescriptorToPcmFormatMap() {
    static const AudioFormatDescToPcmFormatMap formatDescToPcmFormatMap = {
            {make_AudioFormatDescription(PcmType::UINT_8_BIT), PCM_FORMAT_S8},
            {make_AudioFormatDescription(PcmType::INT_16_BIT), PCM_FORMAT_S16_LE},
            {make_AudioFormatDescription(PcmType::FIXED_Q_8_24), PCM_FORMAT_S24_LE},
            {make_AudioFormatDescription(PcmType::INT_24_BIT), PCM_FORMAT_S24_3LE},
@@ -165,6 +166,92 @@ const PcmFormatToAudioFormatDescMap& getPcmFormatToAudioFormatDescMap() {
    return pcmFormatToFormatDescMap;
}

void applyGainToInt16Buffer(void* buffer, const size_t bufferSizeBytes, const float gain,
                            int channelCount) {
    const uint16_t unityGainQ4_12 = u4_12_from_float(kUnityGainFloat);
    const uint16_t vl = u4_12_from_float(gain);
    const uint32_t vrl = (vl << 16) | vl;
    int numFrames = 0;
    if (channelCount == 2) {
        numFrames = bufferSizeBytes / sizeof(uint32_t);
        if (numFrames == 0) {
            return;
        }
        uint32_t* intBuffer = (uint32_t*)buffer;
        if (CC_UNLIKELY(vl > unityGainQ4_12)) {
            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 = bufferSizeBytes / sizeof(uint16_t);
        if (numFrames == 0) {
            return;
        }
        int16_t* intBuffer = (int16_t*)buffer;
        if (CC_UNLIKELY(vl > unityGainQ4_12)) {
            do {
                int32_t mono = mul(*intBuffer, static_cast<int16_t>(vl)) >> 12;
                *intBuffer++ = clamp16(mono);
            } while (--numFrames);
        } else {
            do {
                int32_t mono = mul(*intBuffer, static_cast<int16_t>(vl)) >> 12;
                *intBuffer++ = static_cast<int16_t>(mono & 0xFFFF);
            } while (--numFrames);
        }
    }
}

void applyGainToInt32Buffer(int32_t* typedBuffer, const size_t bufferSizeBytes, const float gain) {
    int numSamples = bufferSizeBytes / sizeof(int32_t);
    if (numSamples == 0) {
        return;
    }
    if (CC_UNLIKELY(gain > kUnityGainFloat)) {
        do {
            float multiplied = (*typedBuffer) * gain;
            if (multiplied > INT32_MAX) {
                *typedBuffer++ = INT32_MAX;
            } else if (multiplied < INT32_MIN) {
                *typedBuffer++ = INT32_MIN;
            } else {
                *typedBuffer++ = multiplied;
            }
        } while (--numSamples);
    } else {
        do {
            *typedBuffer++ = (*typedBuffer) * gain;
        } while (--numSamples);
    }
}

void applyGainToFloatBuffer(float* floatBuffer, const size_t bufferSizeBytes, const float gain) {
    int numSamples = bufferSizeBytes / sizeof(float);
    if (numSamples == 0) {
        return;
    }
    if (CC_UNLIKELY(gain > kUnityGainFloat)) {
        do {
            *floatBuffer++ = std::clamp((*floatBuffer) * gain, -kUnityGainFloat, kUnityGainFloat);
        } while (--numSamples);
    } else {
        do {
            *floatBuffer++ = (*floatBuffer) * gain;
        } while (--numSamples);
    }
}

}  // namespace

std::ostream& operator<<(std::ostream& os, const DeviceProfile& device) {
@@ -345,7 +432,7 @@ 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,
void applyGain(void* buffer, float gain, size_t bufferSizeBytes, enum pcm_format pcmFormat,
               int channelCount) {
    if (channelCount != 1 && channelCount != 2) {
        LOG(WARNING) << __func__ << ": unsupported channel count " << channelCount;
@@ -355,56 +442,37 @@ void applyGain(void* buffer, float gain, size_t bytesToTransfer, enum pcm_format
        LOG(WARNING) << __func__ << ": unsupported pcm format " << pcmFormat;
        return;
    }
    const float unityGainFloat = 1.0f;
    if (std::abs(gain - unityGainFloat) < 1e-6) {
    if (std::abs(gain - kUnityGainFloat) < 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);
                }
        case PCM_FORMAT_S16_LE:
            applyGainToInt16Buffer(buffer, bufferSizeBytes, gain, channelCount);
            break;
        case PCM_FORMAT_FLOAT_LE: {
            float* floatBuffer = (float*)buffer;
            applyGainToFloatBuffer(floatBuffer, bufferSizeBytes, gain);
        } break;
        case PCM_FORMAT_S24_LE:
            // PCM_FORMAT_S24_LE buffer is composed of signed fixed-point 32-bit Q8.23 data with
            // min and max limits of the same bit representation as min and max limits of
            // PCM_FORMAT_S32_LE buffer.
        case PCM_FORMAT_S32_LE: {
            int32_t* typedBuffer = (int32_t*)buffer;
            applyGainToInt32Buffer(typedBuffer, bufferSizeBytes, gain);
        } break;
        case PCM_FORMAT_S24_3LE: {
            int numSamples = bufferSizeBytes / (sizeof(uint8_t) * 3);
            if (numSamples == 0) {
                return;
            }
            std::unique_ptr<int32_t[]> typedBuffer(new int32_t[numSamples]);
            memcpy_to_i32_from_p24(typedBuffer.get(), (uint8_t*)buffer, numSamples);
            applyGainToInt32Buffer(typedBuffer.get(), numSamples * sizeof(int32_t), gain);
            memcpy_to_p24_from_i32((uint8_t*)buffer, typedBuffer.get(), numSamples);
        } break;
        default:
            // TODO(336370745): Implement gain for other supported formats
            LOG(FATAL) << __func__ << ": unsupported pcm format " << pcmFormat;
            break;
    }
}
+12 −0
Original line number Diff line number Diff line
@@ -223,6 +223,18 @@ package android.audio.policy.configuration {
    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_FLAC;
    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_HE_AAC_V1;
    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_HE_AAC_V2;
    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_IAMF_BASE_AAC;
    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_IAMF_BASE_ENHANCED_AAC;
    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_IAMF_BASE_ENHANCED_FLAC;
    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_IAMF_BASE_ENHANCED_OPUS;
    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_IAMF_BASE_ENHANCED_PCM;
    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_IAMF_BASE_FLAC;
    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_IAMF_BASE_OPUS;
    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_IAMF_BASE_PCM;
    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_IAMF_SIMPLE_AAC;
    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_IAMF_SIMPLE_FLAC;
    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_IAMF_SIMPLE_OPUS;
    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_IAMF_SIMPLE_PCM;
    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_IEC60958;
    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_IEC61937;
    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_LC3;
+12 −0
Original line number Diff line number Diff line
@@ -417,6 +417,18 @@
            <xs:enumeration value="AUDIO_FORMAT_APTX_ADAPTIVE_R4"/>
            <xs:enumeration value="AUDIO_FORMAT_DTS_HD_MA"/>
            <xs:enumeration value="AUDIO_FORMAT_DTS_UHD_P2"/>
            <xs:enumeration value="AUDIO_FORMAT_IAMF_SIMPLE_OPUS"/>
            <xs:enumeration value="AUDIO_FORMAT_IAMF_SIMPLE_AAC"/>
            <xs:enumeration value="AUDIO_FORMAT_IAMF_SIMPLE_PCM"/>
            <xs:enumeration value="AUDIO_FORMAT_IAMF_SIMPLE_FLAC"/>
            <xs:enumeration value="AUDIO_FORMAT_IAMF_BASE_OPUS"/>
            <xs:enumeration value="AUDIO_FORMAT_IAMF_BASE_AAC"/>
            <xs:enumeration value="AUDIO_FORMAT_IAMF_BASE_PCM"/>
            <xs:enumeration value="AUDIO_FORMAT_IAMF_BASE_FLAC"/>
            <xs:enumeration value="AUDIO_FORMAT_IAMF_BASE_ENHANCED_OPUS"/>
            <xs:enumeration value="AUDIO_FORMAT_IAMF_BASE_ENHANCED_AAC"/>
            <xs:enumeration value="AUDIO_FORMAT_IAMF_BASE_ENHANCED_PCM"/>
            <xs:enumeration value="AUDIO_FORMAT_IAMF_BASE_ENHANCED_FLAC"/>
        </xs:restriction>
    </xs:simpleType>
    <xs:simpleType name="extendableAudioFormat">
+253 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "AlsaUtilsTest"

#include <alsa/Utils.h>
#include <android-base/macros.h>
#include <audio_utils/primitives.h>
#include <gtest/gtest.h>
#include <log/log.h>

extern "C" {
#include <tinyalsa/pcm.h>
}

namespace alsa = ::aidl::android::hardware::audio::core::alsa;

namespace {

const static constexpr float kInt16tTolerance = 4;
const static constexpr float kIntTolerance = 1;
const static constexpr float kFloatTolerance = 1e-4;
const static constexpr float kUnityGain = 1;
const static constexpr int32_t kInt24Min = -(1 << 23);
const static constexpr int32_t kInt24Max = (1 << 23) - 1;
const static constexpr float kFloatMin = -1;
const static constexpr float kFloatMax = 1;
const static int32_t kQ8_23Min = 0x80000000;
const static int32_t kQ8_23Max = 0x7FFFFFFF;
const static std::vector<int16_t> kInt16Buffer = {10000,     100,   0,    INT16_MAX,
                                                  INT16_MIN, -2500, 1000, -5800};
const static std::vector<float> kFloatBuffer = {0.5, -0.6, kFloatMin, 0.01, kFloatMax, 0.0};
const static std::vector<int32_t> kInt32Buffer = {100, 0, 8000, INT32_MAX, INT32_MIN, -300};
const static std::vector<int32_t> kQ8_23Buffer = {
        kQ8_23Min, kQ8_23Max, 0x00000000, 0x00000001, 0x00400000, static_cast<int32_t>(0xFFD33333)};
const static std::vector<int32_t> kInt24Buffer = {200, 10, -100, 0, kInt24Min, kInt24Max};

template <typename T>
void* CopyToBuffer(int& bytesToTransfer, std::vector<T>& destBuffer,
                   const std::vector<T>& srcBuffer) {
    bytesToTransfer = srcBuffer.size() * sizeof(T);
    destBuffer = srcBuffer;
    return destBuffer.data();
}

template <typename T>
void VerifyTypedBufferResults(const std::vector<T>& bufferWithGain, const std::vector<T>& srcBuffer,
                              float gain, float tolerance) {
    for (size_t i = 0; i < srcBuffer.size(); i++) {
        EXPECT_NEAR(srcBuffer[i] * gain, static_cast<float>(bufferWithGain[i]), tolerance);
    }
}

template <typename T>
void VerifyTypedBufferResultsWithClamp(const std::vector<T>& bufferWithGain,
                                       const std::vector<T>& srcBuffer, float gain, float tolerance,
                                       T minValue, T maxValue) {
    for (size_t i = 0; i < srcBuffer.size(); i++) {
        float expectedResult = std::clamp(srcBuffer[i] * gain, static_cast<float>(minValue),
                                          static_cast<float>(maxValue));
        EXPECT_NEAR(expectedResult, static_cast<float>(bufferWithGain[i]), tolerance);
    }
}

}  // namespace

using ApplyGainTestParameters = std::tuple<pcm_format, int, float>;
enum { INDEX_PCM_FORMAT, INDEX_CHANNEL_COUNT, INDEX_GAIN };

class ApplyGainTest : public ::testing::TestWithParam<ApplyGainTestParameters> {
  protected:
    void SetUp() override;
    void VerifyBufferResult(const pcm_format pcmFormat, const float gain);
    void VerifyBufferResultWithClamp(const pcm_format pcmFormat, const float gain);

    pcm_format mPcmFormat;
    int mBufferSizeBytes;
    void* mBuffer;

  private:
    std::vector<int16_t> mInt16BufferToConvert;
    std::vector<float> mFloatBufferToConvert;
    std::vector<int32_t> mInt32BufferToConvert;
    std::vector<int32_t> mQ8_23BufferToConvert;
    std::vector<int32_t> mInt24BufferToConvert;
};

void ApplyGainTest::SetUp() {
    mPcmFormat = std::get<INDEX_PCM_FORMAT>(GetParam());
    switch (mPcmFormat) {
        case PCM_FORMAT_S16_LE:
            mBuffer = CopyToBuffer(mBufferSizeBytes, mInt16BufferToConvert, kInt16Buffer);
            break;
        case PCM_FORMAT_FLOAT_LE:
            mBuffer = CopyToBuffer(mBufferSizeBytes, mFloatBufferToConvert, kFloatBuffer);
            break;
        case PCM_FORMAT_S32_LE:
            mBuffer = CopyToBuffer(mBufferSizeBytes, mInt32BufferToConvert, kInt32Buffer);
            break;
        case PCM_FORMAT_S24_LE:
            mBuffer = CopyToBuffer(mBufferSizeBytes, mQ8_23BufferToConvert, kQ8_23Buffer);
            break;
        case PCM_FORMAT_S24_3LE: {
            std::vector<int32_t> original32BitBuffer(kInt24Buffer.begin(), kInt24Buffer.end());
            for (auto& val : original32BitBuffer) {
                val <<= 8;
            }
            mInt24BufferToConvert = std::vector<int32_t>(kInt24Buffer.size());
            mBufferSizeBytes = kInt24Buffer.size() * 3 * sizeof(uint8_t);
            memcpy_to_p24_from_i32(reinterpret_cast<uint8_t*>(mInt24BufferToConvert.data()),
                                   original32BitBuffer.data(), kInt24Buffer.size());
            mBuffer = mInt24BufferToConvert.data();
        } break;
        default:
            FAIL() << "Unsupported pcm format: " << mPcmFormat;
            return;
    }
}

void ApplyGainTest::VerifyBufferResult(const pcm_format pcmFormat, const float gain) {
    switch (pcmFormat) {
        case PCM_FORMAT_S16_LE:
            VerifyTypedBufferResults(mInt16BufferToConvert, kInt16Buffer, gain, kInt16tTolerance);
            break;
        case PCM_FORMAT_FLOAT_LE:
            VerifyTypedBufferResults(mFloatBufferToConvert, kFloatBuffer, gain, kFloatTolerance);
            break;
        case PCM_FORMAT_S32_LE:
            VerifyTypedBufferResults(mInt32BufferToConvert, kInt32Buffer, gain, kIntTolerance);
            break;
        case PCM_FORMAT_S24_LE: {
            for (size_t i = 0; i < kQ8_23Buffer.size(); i++) {
                EXPECT_NEAR(float_from_q8_23(kQ8_23Buffer[i]) * gain,
                            static_cast<float>(float_from_q8_23(mQ8_23BufferToConvert[i])),
                            kFloatTolerance);
            }
        } break;
        case PCM_FORMAT_S24_3LE: {
            size_t bufferSize = kInt24Buffer.size();
            std::vector<int32_t> result32BitBuffer(bufferSize);
            memcpy_to_i32_from_p24(result32BitBuffer.data(),
                                   reinterpret_cast<uint8_t*>(mInt24BufferToConvert.data()),
                                   bufferSize);
            for (size_t i = 0; i < bufferSize; i++) {
                EXPECT_NEAR(kInt24Buffer[i] * gain, result32BitBuffer[i] >> 8, kIntTolerance);
            }
        } break;
        default:
            return;
    }
}

void ApplyGainTest::VerifyBufferResultWithClamp(const pcm_format pcmFormat, const float gain) {
    switch (pcmFormat) {
        case PCM_FORMAT_S16_LE:
            VerifyTypedBufferResultsWithClamp(mInt16BufferToConvert, kInt16Buffer, gain,
                                              kInt16tTolerance, static_cast<int16_t>(INT16_MIN),
                                              static_cast<int16_t>(INT16_MAX));
            break;
        case PCM_FORMAT_FLOAT_LE:
            VerifyTypedBufferResultsWithClamp(mFloatBufferToConvert, kFloatBuffer, gain,
                                              kFloatTolerance, kFloatMin, kFloatMax);
            break;
        case PCM_FORMAT_S32_LE:
            VerifyTypedBufferResultsWithClamp(mInt32BufferToConvert, kInt32Buffer, gain,
                                              kIntTolerance, INT32_MIN, INT32_MAX);
            break;
        case PCM_FORMAT_S24_LE: {
            for (size_t i = 0; i < kQ8_23Buffer.size(); i++) {
                float expectedResult =
                        std::clamp(float_from_q8_23(kQ8_23Buffer[i]) * gain,
                                   float_from_q8_23(kQ8_23Min), float_from_q8_23(kQ8_23Max));
                EXPECT_NEAR(expectedResult,
                            static_cast<float>(float_from_q8_23(mQ8_23BufferToConvert[i])),
                            kFloatTolerance);
            }
        } break;
        case PCM_FORMAT_S24_3LE: {
            size_t bufferSize = kInt24Buffer.size();
            std::vector<int32_t> result32BitBuffer(bufferSize);
            memcpy_to_i32_from_p24(result32BitBuffer.data(),
                                   reinterpret_cast<uint8_t*>(mInt24BufferToConvert.data()),
                                   bufferSize);
            for (size_t i = 0; i < bufferSize; i++) {
                result32BitBuffer[i] >>= 8;
            }
            VerifyTypedBufferResultsWithClamp(result32BitBuffer, kInt24Buffer, gain, kIntTolerance,
                                              kInt24Min, kInt24Max);
        } break;
        default:
            return;
    }
}

TEST_P(ApplyGainTest, ApplyGain) {
    float gain = std::get<INDEX_GAIN>(GetParam());
    int channelCount = std::get<INDEX_CHANNEL_COUNT>(GetParam());

    alsa::applyGain(mBuffer, gain, mBufferSizeBytes, mPcmFormat, channelCount);

    if (gain <= kUnityGain) {
        VerifyBufferResult(mPcmFormat, gain);
    } else {
        VerifyBufferResultWithClamp(mPcmFormat, gain);
    }
}

std::string GetApplyGainTestName(const testing::TestParamInfo<ApplyGainTestParameters>& info) {
    std::string testNameStr;
    switch (std::get<INDEX_PCM_FORMAT>(info.param)) {
        case PCM_FORMAT_S16_LE:
            testNameStr = "S16_LE";
            break;
        case PCM_FORMAT_FLOAT_LE:
            testNameStr = "Float_LE";
            break;
        case PCM_FORMAT_S32_LE:
            testNameStr = "S32_LE";
            break;
        case PCM_FORMAT_S24_LE:
            testNameStr = "S24_LE";
            break;
        case PCM_FORMAT_S24_3LE:
            testNameStr = "S24_3LE";
            break;
        default:
            testNameStr = "UnsupportedPcmFormat";
            break;
    }
    testNameStr += std::get<INDEX_CHANNEL_COUNT>(info.param) == 1 ? "_Mono_" : "_Stereo_";
    testNameStr += std::get<INDEX_GAIN>(info.param) <= kUnityGain ? "WithoutClamp" : "WithClamp";
    return testNameStr;
}

INSTANTIATE_TEST_SUITE_P(PerPcmFormat, ApplyGainTest,
                         testing::Combine(testing::Values(PCM_FORMAT_S16_LE, PCM_FORMAT_FLOAT_LE,
                                                          PCM_FORMAT_S32_LE, PCM_FORMAT_S24_LE,
                                                          PCM_FORMAT_S24_3LE),
                                          testing::Values(1, 2), testing::Values(0.6f, 1.5f)),
                         GetApplyGainTestName);
Loading