Audio render-hook M1: shared audio ring + protocol diag fields
First milestone of the injection render-hook audio path (see docs/audio-render-hook-plan.md) that fixes the local audio echo without a virtual device. - common/include/coop/audio_ring.hpp: new lock-free SPSC shared-memory ring for PCM, separate from the input/status SharedBlock. Free-running 64-bit positions (release/acquire), format handshake, host-owned capture_enabled gate, drop-whole-packet overrun policy. - common/include/coop/protocol.hpp: add AudioStreamInfo + audio_streams_seen / audio_streams[] to the always-present HookStatus for the render-stream-count debug view; bump kProtocolVersion 3->4 (new members appended). - tests/audio_ring_test.cpp: in-process unit test (push/pop integrity, wrap-around, format handshake, overrun/drop). No hook or audio device. - docs/audio-render-hook-plan.md: the green-lit design this implements. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -11,7 +11,7 @@ namespace coop
|
||||
|
||||
// Bump whenever the layout of SharedBlock or CoopPadState changes. The hook
|
||||
// refuses to attach to a host with a mismatched version.
|
||||
inline constexpr std::uint32_t kProtocolVersion = 3;
|
||||
inline constexpr std::uint32_t kProtocolVersion = 4;
|
||||
|
||||
// 'COOP' little-endian, used to sanity-check the mapping before trusting it.
|
||||
inline constexpr std::uint32_t kProtocolMagic = 0x504F4F43u;
|
||||
@@ -42,6 +42,24 @@ struct CoopPadState
|
||||
|
||||
static_assert(sizeof(CoopPadState) == 20, "CoopPadState layout must stay stable across both modules");
|
||||
|
||||
// Maximum render streams the diagnostics track. The hook captures only the
|
||||
// first ("primary"); the rest are surfaced so a multi-stream game is visible.
|
||||
inline constexpr std::uint32_t kMaxAudioStreams = 4;
|
||||
|
||||
// One render stream the hook observed, for the Audio panel's debug view. Plain
|
||||
// POD (no atomics): diagnostics tolerate benign cross-process races like the
|
||||
// other HookStatus counters. frames_rendered is cumulative; the host derives
|
||||
// "live vs idle" from successive deltas.
|
||||
struct AudioStreamInfo
|
||||
{
|
||||
std::uint32_t is_primary; // 1 = the stream the hook captures/silences
|
||||
std::uint32_t sample_rate;
|
||||
std::uint16_t channels;
|
||||
std::uint16_t bits;
|
||||
std::uint32_t format_tag; // WAVE_FORMAT_* of this stream
|
||||
std::uint64_t frames_rendered;
|
||||
};
|
||||
|
||||
// Indices into HookStatus::focus_query_calls.
|
||||
enum FocusApi : std::uint32_t
|
||||
{
|
||||
@@ -73,6 +91,12 @@ struct HookStatus
|
||||
std::uint32_t raw_input_gamepad; // ... for a joystick/gamepad usage page
|
||||
std::uint32_t raw_input_gamepad_sink; // ... and that usage has RIDEV_INPUTSINK (bg delivery)
|
||||
std::uint32_t dinput_loaded; // dinput8.dll is present in the process
|
||||
|
||||
// Audio render-hook diagnostics. Stream counting runs whenever the DLL is
|
||||
// injected, independent of whether audio mirroring is enabled, so a
|
||||
// multi-stream game is visible before/without turning the mirror on.
|
||||
std::uint32_t audio_streams_seen; // distinct render clients ever created
|
||||
AudioStreamInfo audio_streams[kMaxAudioStreams]; // per-slot detail, [0] is primary
|
||||
};
|
||||
|
||||
// Top-level shared block. The host is the sole writer of pad state; the hook is
|
||||
|
||||
Reference in New Issue
Block a user