// Owns the audio-mirror pipeline (render-hook ring or WASAPI process loopback + // re-render) and its UI. The target process is derived from the injected game's // window; the render-stream debug view reads the hook's diagnostics back-channel. #pragma once #include #include #include "audio/audio_loopback.hpp" #include "ipc/ipc_server.hpp" namespace coop { class AudioPanel { public: // The window whose process audio to mirror (0 if none); typically the // injected game's HWND. void set_target(HWND target) { target_ = target; } // `status` is the hook's back-channel, for the render-stream view. With // `debug_details` on, the per-stream table is shown. void draw_ui(const HookStatusView& status, bool debug_details); private: HWND target_ = nullptr; bool enabled_ = false; AudioMirror mirror_; // Per-stream activity tracking for the "live" column. Audio buffers release in // bursts, so most UI frames see no change; comparing to just the previous frame // flickers. Instead we remember when each stream last advanced and debounce the // live/idle indicator over a short window, plus a ~2 Hz frames/s estimate. std::uint64_t prev_frames_[kMaxAudioStreams] = {}; double last_active_[kMaxAudioStreams] = {}; // ImGui time a stream last advanced std::uint64_t rate_base_frames_[kMaxAudioStreams] = {}; double frames_per_s_[kMaxAudioStreams] = {}; double rate_base_time_ = 0.0; }; } // namespace coop