Audio: per-game persisted format overrides + auto-learn
Persist audio overrides keyed by game image name (coop_audio_overrides.ini next to the exe) so a known-bad game is auto-corrected on its next launch: on attach to a guessed stream the host applies any saved override, and a manual Override now saves too. A format the hook catches exactly at IAudioClient::Initialize is auto-saved as that game's override (ground truth); if it overwrites a differing stored value, a warning is logged. Host-originated log lines now reach the Log window via IpcServer::host_log (color-coded). Validated live (harness): a pre-seeded override for coop_tone is auto-applied over the guess (state -> manual override, 48000/2/16). audio_overrides_test covers persist/reload/case-insensitive lookup/differing-overwrite. Trim README. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -4,10 +4,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "audio/audio_loopback.hpp"
|
||||
#include "audio/audio_overrides.hpp"
|
||||
#include "ipc/ipc_server.hpp"
|
||||
|
||||
namespace coop
|
||||
@@ -16,6 +19,11 @@ namespace coop
|
||||
class AudioPanel
|
||||
{
|
||||
public:
|
||||
AudioPanel()
|
||||
{
|
||||
overrides_.load();
|
||||
}
|
||||
|
||||
// The window whose process audio to mirror (0 if none); typically the
|
||||
// injected game's HWND.
|
||||
void set_target(HWND target)
|
||||
@@ -23,6 +31,13 @@ public:
|
||||
target_ = target;
|
||||
}
|
||||
|
||||
// Wire a sink for host-side log lines (override-overwrite warnings etc.). main
|
||||
// connects this to the injection panel's Log-window channel.
|
||||
void set_logger(std::function<void(std::uint32_t, const char*)> logger)
|
||||
{
|
||||
logger_ = std::move(logger);
|
||||
}
|
||||
|
||||
// `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);
|
||||
@@ -66,11 +81,24 @@ public:
|
||||
#endif
|
||||
|
||||
private:
|
||||
// Auto-apply a stored override over a guessed stream, and auto-save a format the hook
|
||||
// caught exactly at Initialize (warning if it overwrites a differing stored value).
|
||||
void manage_overrides(const HookStatusView& status, DWORD pid);
|
||||
static std::wstring image_name_from_pid(DWORD pid);
|
||||
|
||||
HWND target_ = nullptr;
|
||||
DWORD dev_pid_ = 0; // test harness only: force a (windowless) target pid; 0 in production
|
||||
bool enabled_ = false;
|
||||
AudioMirror mirror_;
|
||||
|
||||
// Per-game persisted overrides + per-target session bookkeeping.
|
||||
AudioOverrideStore overrides_;
|
||||
std::function<void(std::uint32_t, const char*)> logger_;
|
||||
DWORD applied_pid_ = 0; // pid the session flags below were reset for
|
||||
std::wstring target_image_; // current target's image path (store keys on the basename)
|
||||
bool override_applied_ = false; // applied (or confirmed none) the stored override this session
|
||||
bool exact_saved_ = false; // saved the exact Initialize format this session
|
||||
|
||||
// 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
|
||||
|
||||
Reference in New Issue
Block a user