249 lines
8.3 KiB
C++
249 lines
8.3 KiB
C++
// ================================================================================================
|
|
// Audio Backend - 测试模拟对象实现
|
|
// ================================================================================================
|
|
|
|
#include "mock_objects.h"
|
|
#include <random>
|
|
#include <chrono>
|
|
#include <cmath>
|
|
|
|
namespace audio_backend {
|
|
namespace test {
|
|
|
|
//===================================================================================================
|
|
// ResourceLimiter 实现
|
|
//===================================================================================================
|
|
struct ResourceLimiter::Impl {
|
|
size_t memory_limit = std::numeric_limits<size_t>::max();
|
|
float cpu_limit = 100.0f;
|
|
size_t io_limit = std::numeric_limits<size_t>::max();
|
|
size_t network_limit = std::numeric_limits<size_t>::max();
|
|
|
|
ResourceUsage current_usage;
|
|
std::mt19937 rng{static_cast<unsigned int>(std::chrono::steady_clock::now().time_since_epoch().count())};
|
|
};
|
|
|
|
ResourceLimiter::ResourceLimiter() : pimpl_(std::make_unique<Impl>()) {}
|
|
ResourceLimiter::~ResourceLimiter() = default;
|
|
|
|
void ResourceLimiter::set_memory_limit(size_t bytes) {
|
|
pimpl_->memory_limit = bytes;
|
|
}
|
|
|
|
void ResourceLimiter::set_cpu_limit(float percentage) {
|
|
pimpl_->cpu_limit = std::clamp(percentage, 0.0f, 100.0f);
|
|
}
|
|
|
|
void ResourceLimiter::set_io_limit(size_t bytes_per_sec) {
|
|
pimpl_->io_limit = bytes_per_sec;
|
|
}
|
|
|
|
void ResourceLimiter::set_network_limit(size_t bytes_per_sec) {
|
|
pimpl_->network_limit = bytes_per_sec;
|
|
}
|
|
|
|
void ResourceLimiter::reset_limits() {
|
|
pimpl_->memory_limit = std::numeric_limits<size_t>::max();
|
|
pimpl_->cpu_limit = 100.0f;
|
|
pimpl_->io_limit = std::numeric_limits<size_t>::max();
|
|
pimpl_->network_limit = std::numeric_limits<size_t>::max();
|
|
}
|
|
|
|
ResourceUsage ResourceLimiter::get_current_usage() const {
|
|
// 模拟随机资源使用
|
|
std::uniform_real_distribution<float> cpu_dist(0.0f, pimpl_->cpu_limit * 1.2f);
|
|
std::uniform_int_distribution<size_t> memory_dist(0, pimpl_->memory_limit);
|
|
std::uniform_int_distribution<size_t> io_dist(0, pimpl_->io_limit);
|
|
std::uniform_int_distribution<size_t> network_dist(0, pimpl_->network_limit);
|
|
|
|
ResourceUsage usage;
|
|
usage.memory_usage_bytes = memory_dist(pimpl_->rng);
|
|
usage.cpu_usage_percent = cpu_dist(pimpl_->rng);
|
|
usage.io_bytes_per_sec = io_dist(pimpl_->rng);
|
|
usage.network_bytes_per_sec = network_dist(pimpl_->rng);
|
|
|
|
return usage;
|
|
}
|
|
|
|
bool ResourceLimiter::is_limit_reached(ResourceType type) const {
|
|
auto usage = get_current_usage();
|
|
switch (type) {
|
|
case ResourceType::Memory:
|
|
return usage.memory_usage_bytes >= pimpl_->memory_limit;
|
|
case ResourceType::CPU:
|
|
return usage.cpu_usage_percent >= pimpl_->cpu_limit;
|
|
case ResourceType::IO:
|
|
return usage.io_bytes_per_sec >= pimpl_->io_limit;
|
|
case ResourceType::Network:
|
|
return usage.network_bytes_per_sec >= pimpl_->network_limit;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//===================================================================================================
|
|
// ErrorInjector 实现
|
|
//===================================================================================================
|
|
struct ErrorInjector::Impl {
|
|
std::map<std::string, std::map<std::string, ErrorCallback>> registered_errors;
|
|
float error_probability = 0.0f;
|
|
std::mt19937 rng{static_cast<unsigned int>(std::chrono::steady_clock::now().time_since_epoch().count())};
|
|
};
|
|
|
|
ErrorInjector::ErrorInjector() : pimpl_(std::make_unique<Impl>()) {}
|
|
ErrorInjector::~ErrorInjector() = default;
|
|
|
|
void ErrorInjector::register_error(const std::string& component, const std::string& operation, ErrorCallback callback) {
|
|
pimpl_->registered_errors[component][operation] = std::move(callback);
|
|
}
|
|
|
|
bool ErrorInjector::inject_error(const std::string& component, const std::string& operation) {
|
|
auto comp_it = pimpl_->registered_errors.find(component);
|
|
if (comp_it != pimpl_->registered_errors.end()) {
|
|
auto op_it = comp_it->second.find(operation);
|
|
if (op_it != comp_it->second.end()) {
|
|
op_it->second();
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool ErrorInjector::inject_random_error() {
|
|
std::uniform_real_distribution<float> dist(0.0f, 1.0f);
|
|
if (dist(pimpl_->rng) < pimpl_->error_probability) {
|
|
// 随机选择一个错误注入
|
|
if (pimpl_->registered_errors.empty()) {
|
|
return false;
|
|
}
|
|
|
|
std::vector<std::pair<std::string, std::string>> error_keys;
|
|
for (const auto& comp : pimpl_->registered_errors) {
|
|
for (const auto& op : comp.second) {
|
|
error_keys.emplace_back(comp.first, op.first);
|
|
}
|
|
}
|
|
|
|
if (error_keys.empty()) {
|
|
return false;
|
|
}
|
|
|
|
std::uniform_int_distribution<size_t> key_dist(0, error_keys.size() - 1);
|
|
auto selected = error_keys[key_dist(pimpl_->rng)];
|
|
return inject_error(selected.first, selected.second);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void ErrorInjector::set_error_probability(float probability) {
|
|
pimpl_->error_probability = std::clamp(probability, 0.0f, 1.0f);
|
|
}
|
|
|
|
void ErrorInjector::reset() {
|
|
pimpl_->registered_errors.clear();
|
|
pimpl_->error_probability = 0.0f;
|
|
}
|
|
|
|
//===================================================================================================
|
|
// MockAudioGenerator 实现
|
|
//===================================================================================================
|
|
struct MockAudioGenerator::Impl {
|
|
int sample_rate;
|
|
int channels;
|
|
SignalType type = SignalType::Sine;
|
|
float frequency = 440.0f;
|
|
float amplitude = 0.5f;
|
|
float phase = 0.0f;
|
|
float phase_increment = 0.0f;
|
|
|
|
std::mt19937 rng{static_cast<unsigned int>(std::chrono::steady_clock::now().time_since_epoch().count())};
|
|
|
|
Impl(int sr, int ch) : sample_rate(sr), channels(ch) {
|
|
update_phase_increment();
|
|
}
|
|
|
|
void update_phase_increment() {
|
|
phase_increment = 2.0f * M_PI * frequency / static_cast<float>(sample_rate);
|
|
}
|
|
|
|
float generate_sample() {
|
|
float sample = 0.0f;
|
|
|
|
switch (type) {
|
|
case SignalType::Sine:
|
|
sample = amplitude * std::sin(phase);
|
|
break;
|
|
|
|
case SignalType::Square:
|
|
sample = amplitude * (std::sin(phase) >= 0.0f ? 1.0f : -1.0f);
|
|
break;
|
|
|
|
case SignalType::Triangle:
|
|
sample = amplitude * (2.0f / M_PI) * std::asin(std::sin(phase));
|
|
break;
|
|
|
|
case SignalType::Sawtooth: {
|
|
float normalized_phase = std::fmod(phase, 2.0f * M_PI) / (2.0f * M_PI);
|
|
sample = amplitude * (2.0f * normalized_phase - 1.0f);
|
|
break;
|
|
}
|
|
|
|
case SignalType::Noise: {
|
|
std::uniform_real_distribution<float> dist(-amplitude, amplitude);
|
|
sample = dist(rng);
|
|
break;
|
|
}
|
|
|
|
case SignalType::Silence:
|
|
default:
|
|
sample = 0.0f;
|
|
break;
|
|
}
|
|
|
|
// 更新相位
|
|
phase += phase_increment;
|
|
if (phase > 2.0f * M_PI) {
|
|
phase -= 2.0f * M_PI;
|
|
}
|
|
|
|
return sample;
|
|
}
|
|
};
|
|
|
|
MockAudioGenerator::MockAudioGenerator(int sample_rate, int channels)
|
|
: pimpl_(std::make_unique<Impl>(sample_rate, channels)) {}
|
|
|
|
MockAudioGenerator::~MockAudioGenerator() = default;
|
|
|
|
void MockAudioGenerator::set_signal_type(SignalType type) {
|
|
pimpl_->type = type;
|
|
}
|
|
|
|
void MockAudioGenerator::set_frequency(float frequency_hz) {
|
|
pimpl_->frequency = frequency_hz;
|
|
pimpl_->update_phase_increment();
|
|
}
|
|
|
|
void MockAudioGenerator::set_amplitude(float amplitude) {
|
|
pimpl_->amplitude = amplitude;
|
|
}
|
|
|
|
void MockAudioGenerator::set_phase(float phase_radians) {
|
|
pimpl_->phase = phase_radians;
|
|
}
|
|
|
|
void MockAudioGenerator::generate(float* buffer, size_t frames) {
|
|
for (size_t i = 0; i < frames; ++i) {
|
|
float sample = pimpl_->generate_sample();
|
|
for (int ch = 0; ch < pimpl_->channels; ++ch) {
|
|
buffer[i * pimpl_->channels + ch] = sample;
|
|
}
|
|
}
|
|
}
|
|
|
|
void MockAudioGenerator::reset() {
|
|
pimpl_->phase = 0.0f;
|
|
}
|
|
|
|
} // namespace test
|
|
} // namespace audio_backend
|