#include "audio/apm_processor.h" #include #include #include namespace voicecat::audio { namespace { int64_t steady_now_ms() { return std::chrono::duration_cast( std::chrono::steady_clock::now().time_since_epoch()) .count(); } } // namespace // ── ApmPassthrough ──────────────────────────────────────────────────────────── // No-op: returns true (VAD always open), does not modify PCM. // Replaced by WebrtcApmProcessor when VOICECAT_HAS_APM is defined. class ApmPassthrough final : public ApmProcessor { public: void process_render(const int16_t*, int, int) override {} bool process_capture(int16_t*, int, int) override { return true; } }; // ── EnergyVadProcessor ────────────────────────────────────────────────────── // Lightweight, dependency-free energy/RMS VAD — see apm_processor.h's create_vad() doc comment // for why this exists instead of a real APM. No AEC (process_render is a no-op); doesn't modify // the PCM it's given, only inspects it. class EnergyVadProcessor final : public ApmProcessor { public: EnergyVadProcessor(float rms_threshold, int64_t hang_time_ms) : threshold_(rms_threshold), hang_time_ms_(hang_time_ms) {} void process_render(const int16_t*, int, int) override {} bool process_capture(int16_t* pcm, int samples, int /*sample_rate*/) override { if (samples > 0) { double sum_sq = 0.0; for (int i = 0; i < samples; ++i) { double s = static_cast(pcm[i]) / 32768.0; sum_sq += s * s; } double rms = std::sqrt(sum_sq / samples); if (rms >= threshold_.load(std::memory_order_relaxed)) last_voice_ms_ = steady_now_ms(); } return (steady_now_ms() - last_voice_ms_) < hang_time_ms_; } void set_threshold(float t) override { threshold_.store(t, std::memory_order_relaxed); } private: std::atomic threshold_; int64_t hang_time_ms_; int64_t last_voice_ms_ = 0; // epoch start -> gate begins closed until first loud frame }; std::unique_ptr ApmProcessor::create() { #ifdef VOICECAT_HAS_APM // TODO: return std::make_unique(); — see create_vad()'s doc comment for // why this isn't wired up yet (no working Windows/MSVC build upstream). #endif return std::make_unique(); } std::unique_ptr ApmProcessor::create_vad(float rms_threshold, int64_t hang_time_ms) { return std::make_unique(rms_threshold, hang_time_ms); } } // namespace voicecat::audio