Audio: operator re-measure + format override (host<->hook op channel)

Add a per-stream op channel in AudioRingHeader (op_seq + op_* fields, version
2): the host posts re-measure / override commands, the hook applies them and
re-publishes (bumping format_generation), and the host rebuilds its render
client live on the change. The Audio panel (under Debug details) gains a
"Re-measure rate" button and a rate/channels/bit-depth/format override -- for
when detection is wrong or the channels/bit-depth were unrecoverable.

Also add a debug-only IPC test harness (-DCOOP_TEST_HARNESS, off by default,
absent from the shipped host): a file-based command channel that drives the
host's real UI code paths (inject / audio / re-measure / override / screenshot
/ status) for scripted validation, instead of unreliable synthetic mouse input.
Used to validate live: late-attach to coop_tone@44100 -> measured 44100,
promoted to hooked; override -> 2ch state, re-measure -> reconverge.

Trim the README roadmap to what's left; document the harness + rate_estimator_test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-22 01:46:59 +02:00
parent c24bfdd64f
commit 90f40ae479
13 changed files with 607 additions and 111 deletions

43
host/src/test_harness.hpp Normal file
View File

@@ -0,0 +1,43 @@
// Debug-only IPC test harness (compiled only when COOP_TEST_HARNESS is defined; the
// shipped product never contains it). Lets a test script drive the real overlay code
// paths -- inject, enable audio, re-measure, override, etc. -- by writing a command to
// %TEMP%\coop_test_cmd.txt and reading the reply from %TEMP%\coop_test_resp.txt, instead
// of simulating mouse/keyboard input (which ImGui doesn't accept reliably via PostMessage).
//
// Protocol: the driver writes one command line to the cmd file; the host consumes it
// (deleting the cmd file to ack), runs it on the main thread (so it hits the same code
// the UI buttons do), and writes a single response line to the resp file. One command at
// a time. See tools/test_drive notes / the per-phase validation scripts.
#pragma once
#include <string>
namespace coop
{
class TestHarness
{
public:
#ifdef COOP_TEST_HARNESS
void init(); // resolve the %TEMP% file paths and clear any stale command
// Main thread: returns the next pending command line (acking by deleting the cmd
// file), or an empty string if none is waiting.
std::string poll_command();
// Main thread: write the response for the command just handled.
void write_response(const std::string& resp);
private:
std::wstring cmd_path_;
std::wstring resp_path_;
#else
// No-op shims so call sites don't need their own #ifdef.
void init() {}
std::string poll_command()
{
return {};
}
void write_response(const std::string&) {}
#endif
};
} // namespace coop