// This file is part of the 64k demo project. // It implements a test backend that simulates jittered audio consumption. #if !defined(STRIP_ALL) #include "jittered_audio_backend.h" #include "audio.h" #include "ring_buffer.h" #include #include #include #include #include JitteredAudioBackend::JitteredAudioBackend() : running_(false), should_stop_(false), jitter_ms_(5.0f), base_interval_ms_(10.0f), min_chunk_frames_(256), max_chunk_frames_(1024), total_frames_consumed_(0), underrun_count_(0) { } JitteredAudioBackend::~JitteredAudioBackend() { shutdown(); } void JitteredAudioBackend::init() { // Nothing to initialize } void JitteredAudioBackend::start() { if (running_.load()) return; should_stop_.store(false); running_.store(true); // Start audio thread audio_thread_ = std::thread(&JitteredAudioBackend::audio_thread_loop, this); } void JitteredAudioBackend::shutdown() { if (!running_.load()) return; should_stop_.store(true); if (audio_thread_.joinable()) { audio_thread_.join(); } running_.store(false); } void JitteredAudioBackend::set_jitter_amount(float jitter_ms) { jitter_ms_ = jitter_ms; } void JitteredAudioBackend::set_base_interval(float interval_ms) { base_interval_ms_ = interval_ms; } void JitteredAudioBackend::set_chunk_size_range(int min_frames, int max_frames) { min_chunk_frames_ = min_frames; max_chunk_frames_ = max_frames; } void JitteredAudioBackend::audio_thread_loop() { AudioRingBuffer* ring_buffer = audio_get_ring_buffer(); if (ring_buffer == nullptr) return; // Random number generator for jitter std::random_device rd; std::mt19937 gen(rd()); std::uniform_real_distribution jitter_dist(-jitter_ms_, jitter_ms_); std::uniform_int_distribution chunk_dist(min_chunk_frames_, max_chunk_frames_); while (!should_stop_.load()) { // Calculate jittered wait time const float jitter = jitter_dist(gen); const float wait_ms = base_interval_ms_ + jitter; const int wait_us = (int)(wait_ms * 1000.0f); if (wait_us > 0) { std::this_thread::sleep_for(std::chrono::microseconds(wait_us)); } // Random chunk size const int chunk_frames = chunk_dist(gen); const int chunk_samples = chunk_frames * 2; // Stereo // Read from ring buffer float* temp_buffer = new float[chunk_samples]; const int read_samples = ring_buffer->read(temp_buffer, chunk_samples); // Check for underrun if (read_samples < chunk_samples) { underrun_count_.fetch_add(1); } // Track consumption total_frames_consumed_.fetch_add(read_samples / 2); // Notify of frames rendered (for tracking) on_frames_rendered(read_samples / 2); delete[] temp_buffer; } } #endif /* !defined(STRIP_ALL) */