Files
Alicho/tests/unit/engine/audio_buffer_test.cpp
2025-10-28 10:27:49 +08:00

340 lines
10 KiB
C++

// ================================================================================================
// Audio Backend - 音频缓冲区测试
// ================================================================================================
#include <gtest/gtest.h>
#include "engine/audio_buffer.h"
#include "tests/common/test_fixtures.h"
#include "tests/common/test_utils.h"
using namespace audio_backend;
using namespace audio_backend::engine;
// 音频缓冲区测试固定装置
class AudioBufferTest : public test::AudioEngineTest {
protected:
void SetUp() override {
test::AudioEngineTest::SetUp();
}
void TearDown() override {
test::AudioEngineTest::TearDown();
}
};
// 测试默认构造函数
TEST_F(AudioBufferTest, DefaultConstruction) {
AudioBuffer buffer;
EXPECT_TRUE(buffer.empty());
EXPECT_EQ(buffer.size_bytes(), 0);
EXPECT_EQ(buffer.channels(), 0);
EXPECT_EQ(buffer.frames(), 0);
EXPECT_EQ(buffer.format(), AudioFormat::UNKNOWN);
}
// 测试使用AudioConfig参数的构造
TEST_F(AudioBufferTest, ConfigConstruction) {
AudioConfig config;
config.sample_rate = 44100;
config.channels = 2;
config.format = AudioFormat::FLOAT32;
config.frames_per_buffer = 256;
// 交错格式
{
AudioBuffer buffer(config, true);
EXPECT_FALSE(buffer.empty());
EXPECT_EQ(buffer.size_bytes(), 2048); // 256帧 * 2声道 * 4字节
EXPECT_EQ(buffer.channels(), 2);
EXPECT_EQ(buffer.frames(), 256);
EXPECT_EQ(buffer.format(), AudioFormat::FLOAT32);
EXPECT_EQ(buffer.sample_rate(), 44100);
EXPECT_TRUE(buffer.is_interleaved());
}
// 非交错格式
{
AudioBuffer buffer(config, false);
EXPECT_FALSE(buffer.empty());
EXPECT_EQ(buffer.size_bytes(), 2048); // 256帧 * 2声道 * 4字节
EXPECT_EQ(buffer.channels(), 2);
EXPECT_EQ(buffer.frames(), 256);
EXPECT_EQ(buffer.format(), AudioFormat::FLOAT32);
EXPECT_EQ(buffer.sample_rate(), 44100);
EXPECT_FALSE(buffer.is_interleaved());
}
}
// 测试使用参数列表的构造
TEST_F(AudioBufferTest, ParameterConstruction) {
// 交错格式
{
AudioBuffer buffer(256, 2, AudioFormat::FLOAT32, true);
EXPECT_FALSE(buffer.empty());
EXPECT_EQ(buffer.size_bytes(), 2048); // 256帧 * 2声道 * 4字节
EXPECT_EQ(buffer.channels(), 2);
EXPECT_EQ(buffer.frames(), 256);
EXPECT_EQ(buffer.format(), AudioFormat::FLOAT32);
EXPECT_TRUE(buffer.is_interleaved());
}
// 非交错格式
{
AudioBuffer buffer(256, 2, AudioFormat::FLOAT32, false);
EXPECT_FALSE(buffer.empty());
EXPECT_EQ(buffer.size_bytes(), 2048); // 256帧 * 2声道 * 4字节
EXPECT_EQ(buffer.channels(), 2);
EXPECT_EQ(buffer.frames(), 256);
EXPECT_EQ(buffer.format(), AudioFormat::FLOAT32);
EXPECT_FALSE(buffer.is_interleaved());
}
}
// 测试移动构造函数
TEST_F(AudioBufferTest, MoveConstruction) {
AudioBuffer original(256, 2, AudioFormat::FLOAT32);
// 填充一些数据
float* data = original.interleaved_data<float>();
for (size_t i = 0; i < 256 * 2; ++i) {
data[i] = static_cast<float>(i) / 100.0f;
}
// 移动构造
AudioBuffer moved(std::move(original));
// 检查移动后的状态
EXPECT_FALSE(moved.empty());
EXPECT_EQ(moved.size_bytes(), 2048);
EXPECT_EQ(moved.channels(), 2);
EXPECT_EQ(moved.frames(), 256);
EXPECT_EQ(moved.format(), AudioFormat::FLOAT32);
EXPECT_TRUE(moved.is_interleaved());
// 原始缓冲区应该被清空
EXPECT_TRUE(original.empty());
EXPECT_EQ(original.size_bytes(), 0);
}
// 测试移动赋值操作符
TEST_F(AudioBufferTest, MoveAssignment) {
AudioBuffer original(256, 2, AudioFormat::FLOAT32);
AudioBuffer target;
// 填充一些数据
float* data = original.interleaved_data<float>();
for (size_t i = 0; i < 256 * 2; ++i) {
data[i] = static_cast<float>(i) / 100.0f;
}
// 移动赋值
target = std::move(original);
// 检查移动后的状态
EXPECT_FALSE(target.empty());
EXPECT_EQ(target.size_bytes(), 2048);
EXPECT_EQ(target.channels(), 2);
EXPECT_EQ(target.frames(), 256);
EXPECT_EQ(target.format(), AudioFormat::FLOAT32);
EXPECT_TRUE(target.is_interleaved());
// 原始缓冲区应该被清空
EXPECT_TRUE(original.empty());
EXPECT_EQ(original.size_bytes(), 0);
}
// 测试克隆方法
TEST_F(AudioBufferTest, Clone) {
AudioBuffer original(256, 2, AudioFormat::FLOAT32);
// 填充一些数据
float* data = original.interleaved_data<float>();
for (size_t i = 0; i < 256 * 2; ++i) {
data[i] = static_cast<float>(i) / 100.0f;
}
// 克隆
AudioBuffer cloned = original.clone();
// 检查克隆后的状态
EXPECT_FALSE(cloned.empty());
EXPECT_EQ(cloned.size_bytes(), original.size_bytes());
EXPECT_EQ(cloned.channels(), original.channels());
EXPECT_EQ(cloned.frames(), original.frames());
EXPECT_EQ(cloned.format(), original.format());
EXPECT_EQ(cloned.is_interleaved(), original.is_interleaved());
// 原始缓冲区应该保持不变
EXPECT_FALSE(original.empty());
// 数据应该一样,但地址不同
EXPECT_NE(cloned.data(), original.data());
EXPECT_EQ(memcmp(cloned.data(), original.data(), original.size_bytes()), 0);
}
// 测试重新分配缓冲区
TEST_F(AudioBufferTest, Allocation) {
AudioBuffer buffer;
// 初始状态
EXPECT_TRUE(buffer.empty());
// 第一次分配
buffer.allocate(256, 2, AudioFormat::FLOAT32);
EXPECT_FALSE(buffer.empty());
EXPECT_EQ(buffer.size_bytes(), 2048);
// 再次分配(扩大)
buffer.allocate(512, 2, AudioFormat::FLOAT32);
EXPECT_FALSE(buffer.empty());
EXPECT_EQ(buffer.size_bytes(), 4096);
// 再次分配(缩小)
buffer.allocate(128, 2, AudioFormat::FLOAT32);
EXPECT_FALSE(buffer.empty());
EXPECT_EQ(buffer.size_bytes(), 1024);
// 使用配置分配
AudioConfig config;
config.frames_per_buffer = 1024;
config.channels = 4;
config.format = AudioFormat::INT16;
buffer.allocate(config);
EXPECT_FALSE(buffer.empty());
EXPECT_EQ(buffer.size_bytes(), 8192); // 1024帧 * 4声道 * 2字节
// 释放
buffer.release();
EXPECT_TRUE(buffer.empty());
EXPECT_EQ(buffer.size_bytes(), 0);
}
// 测试清空缓冲区
TEST_F(AudioBufferTest, Clear) {
AudioBuffer buffer(256, 2, AudioFormat::FLOAT32);
// 填充一些数据
float* data = buffer.interleaved_data<float>();
for (size_t i = 0; i < 256 * 2; ++i) {
data[i] = 1.0f; // 全部设为1.0
}
// 清空
buffer.clear();
// 验证所有数据都是0
for (size_t i = 0; i < 256 * 2; ++i) {
EXPECT_FLOAT_EQ(data[i], 0.0f);
}
}
// 测试交错格式数据访问
TEST_F(AudioBufferTest, InterleavedAccess) {
AudioBuffer buffer(256, 2, AudioFormat::FLOAT32, true);
// 获取交错数据指针
float* data = buffer.interleaved_data<float>();
EXPECT_NE(data, nullptr);
// 填充一些数据
for (size_t i = 0; i < 256 * 2; ++i) {
data[i] = static_cast<float>(i) / 100.0f;
}
// 读取数据
for (size_t i = 0; i < 256 * 2; ++i) {
EXPECT_FLOAT_EQ(data[i], static_cast<float>(i) / 100.0f);
}
// 对于交错缓冲区,尝试访问独立通道应该抛出异常
EXPECT_THROW(buffer.channel_data<float>(0), common::AudioException);
}
// 测试非交错格式数据访问
TEST_F(AudioBufferTest, NonInterleavedAccess) {
AudioBuffer buffer(256, 2, AudioFormat::FLOAT32, false);
// 获取各声道数据指针
float* ch0 = buffer.channel_data<float>(0);
float* ch1 = buffer.channel_data<float>(1);
EXPECT_NE(ch0, nullptr);
EXPECT_NE(ch1, nullptr);
EXPECT_NE(ch0, ch1);
// 填充一些数据
for (size_t i = 0; i < 256; ++i) {
ch0[i] = static_cast<float>(i) / 100.0f;
ch1[i] = -static_cast<float>(i) / 100.0f; // 使第二个声道为负值
}
// 读取数据
for (size_t i = 0; i < 256; ++i) {
EXPECT_FLOAT_EQ(ch0[i], static_cast<float>(i) / 100.0f);
EXPECT_FLOAT_EQ(ch1[i], -static_cast<float>(i) / 100.0f);
}
// 超出范围的声道访问应该抛出异常
EXPECT_THROW(buffer.channel_data<float>(2), common::AudioException);
// 对于非交错缓冲区,尝试访问交错数据应该抛出异常
EXPECT_THROW(buffer.interleaved_data<float>(), common::AudioException);
}
// 测试交错/非交错格式转换
TEST_F(AudioBufferTest, FormatConversion) {
// 创建交错缓冲区
AudioBuffer interleaved(256, 2, AudioFormat::FLOAT32, true);
// 填充一些数据
float* data = interleaved.interleaved_data<float>();
for (size_t i = 0; i < 256 * 2; ++i) {
data[i] = static_cast<float>(i) / 100.0f;
}
// 转换为非交错格式
AudioBuffer non_interleaved = interleaved.to_non_interleaved();
EXPECT_FALSE(non_interleaved.is_interleaved());
EXPECT_EQ(non_interleaved.channels(), 2);
EXPECT_EQ(non_interleaved.frames(), 256);
// 验证数据正确性
float* ch0 = non_interleaved.channel_data<float>(0);
float* ch1 = non_interleaved.channel_data<float>(1);
for (size_t i = 0; i < 256; ++i) {
// 交错格式: [L0,R0,L1,R1,...]
// 非交错格式: [L0,L1,...], [R0,R1,...]
EXPECT_FLOAT_EQ(ch0[i], data[i * 2]);
EXPECT_FLOAT_EQ(ch1[i], data[i * 2 + 1]);
}
// 转换回交错格式
AudioBuffer back_to_interleaved = non_interleaved.to_interleaved();
EXPECT_TRUE(back_to_interleaved.is_interleaved());
// 验证转换后的数据与原始数据一致
float* converted_data = back_to_interleaved.interleaved_data<float>();
for (size_t i = 0; i < 256 * 2; ++i) {
EXPECT_FLOAT_EQ(converted_data[i], data[i]);
}
}
// 测试对齐检查
TEST_F(AudioBufferTest, Alignment) {
AudioBuffer buffer(256, 2, AudioFormat::FLOAT32);
// 检查缓冲区是否正确对齐
EXPECT_TRUE(buffer.is_aligned());
}
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}