Recover a guessed audio stream's rate by correlating hook vs loopback (step a)
When the host attaches to an already-running game it never saw the stream's Initialize, so the render-hook assumes the device mix format and measures only the sample rate from the render cadence -- which a jittery game can make wrong (intermittent pitch shift). But during the measurement window the game is still audible, so we have the same audio twice: the hook (pre-mix, unknown format) and a process-loopback (post-mix, the known device format). Cross-correlating them pins the true rate from ground truth. - common/include/coop/audio_correlate.hpp: the pure correlator. Resample the hook by each candidate standard rate up to the device rate and score how well it aligns with the loopback across the window (drift-detecting). audio_correlation_test recovers every rate (score ~1.0 vs ~0.01 for wrong ones), incl. 44100-vs-48000, and rejects unrelated signals. - Hook measurement tap: a host-set verify_capture ring flag makes the hook push a still-being-measured (guessed) stream's raw pre-mix bytes WITHOUT silencing, so the host can co-capture both signals (a silenced game's loopback is silent). Inert by default -- the shipping no-echo path is untouched. - host/src/audio/audio_format_verifier: co-captures hook + loopback and correlates, feeding a correction into the existing override channel. Wired into AudioMirror's measurement window (hidden in the gap loopback already covers, so exact streams pay nothing). audio_verify_test drives it end-to-end against coop_mock_game. Rate vs layout are coupled (correlating the waveform needs the right channel de-interleaving), so this step assumes the hook layout matches the device (the common stereo-on-stereo case); recovering a different channel count / bit depth is step b. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -44,6 +44,14 @@ add_executable(tone_analysis_test tone_analysis_test.cpp)
|
||||
target_link_libraries(tone_analysis_test PRIVATE coop_common)
|
||||
add_test(NAME tone_analysis_test COMMAND tone_analysis_test)
|
||||
|
||||
# Unit test for the two-path audio-format correlator (common/include/coop/audio_correlate.hpp).
|
||||
# Synthesizes one continuous signal sampled at two rates (the hook's true rate + the device rate,
|
||||
# with capture skew + noise) and asserts correlate_rate() recovers the true rate -- including the
|
||||
# 44100-vs-48000 case the cadence method can misread. Pure header logic, no device.
|
||||
add_executable(audio_correlation_test audio_correlation_test.cpp)
|
||||
target_link_libraries(audio_correlation_test PRIVATE coop_common)
|
||||
add_test(NAME audio_correlation_test COMMAND audio_correlation_test)
|
||||
|
||||
# Unit test for the audio-mirror render pacing policy (host/src/audio/render_pacer.hpp).
|
||||
# Simulates a producer/consumer device timeline and asserts the shipping RenderPacer rides
|
||||
# through producer jitter that makes the old re-prime-on-partial-fill policy glitch
|
||||
@@ -170,6 +178,20 @@ target_link_libraries(mock_game_test PRIVATE coop_common d3d11 dxgi)
|
||||
add_dependencies(mock_game_test coop_mock_game coop_hook)
|
||||
add_test(NAME mock_game_test COMMAND mock_game_test)
|
||||
|
||||
# Integration test for the two-path audio-format verifier: launches coop_mock_game rendering a
|
||||
# NON-device rate (44100 on a 48000 endpoint), injects coop_hook.dll late (guessed stream), and
|
||||
# runs the real verify_stream_format() -- co-capturing the hook (pre-mix) + a parallel loopback
|
||||
# (post-mix) and correlating to recover the true rate. Skips cleanly without an audio endpoint.
|
||||
add_executable(audio_verify_test
|
||||
audio_verify_test.cpp
|
||||
${CMAKE_SOURCE_DIR}/host/src/audio/audio_format_verifier.cpp
|
||||
${CMAKE_SOURCE_DIR}/host/src/audio/process_loopback_capture.cpp)
|
||||
target_include_directories(audio_verify_test PRIVATE ${CMAKE_SOURCE_DIR}/host/src)
|
||||
target_compile_definitions(audio_verify_test PRIVATE NTDDI_VERSION=0x0A00000B)
|
||||
target_link_libraries(audio_verify_test PRIVATE coop_common ole32 mmdevapi)
|
||||
add_dependencies(audio_verify_test coop_mock_game coop_hook)
|
||||
add_test(NAME audio_verify_test COMMAND audio_verify_test)
|
||||
|
||||
# In-process self-test for the OpenGL capture path. Reuses the shipping
|
||||
# opengl_hook.cpp and drives a real OpenGL context in the same process, so it
|
||||
# exercises the SwapBuffers hook, the glReadPixels readback, and the upload into
|
||||
@@ -201,6 +223,7 @@ add_executable(ui_fit_test
|
||||
${CMAKE_SOURCE_DIR}/host/src/audio_panel.cpp
|
||||
${CMAKE_SOURCE_DIR}/host/src/controllers_panel.cpp
|
||||
${CMAKE_SOURCE_DIR}/host/src/audio/audio_loopback.cpp
|
||||
${CMAKE_SOURCE_DIR}/host/src/audio/audio_format_verifier.cpp
|
||||
${CMAKE_SOURCE_DIR}/host/src/audio/process_loopback_capture.cpp
|
||||
${CMAKE_SOURCE_DIR}/host/src/audio/audio_overrides.cpp
|
||||
${CMAKE_SOURCE_DIR}/host/src/ui/app_chrome.cpp)
|
||||
@@ -224,6 +247,7 @@ coop_output_subdir(tests
|
||||
mkb_map_test
|
||||
audio_mix_test
|
||||
tone_analysis_test
|
||||
audio_correlation_test
|
||||
render_pacer_test
|
||||
rate_estimator_test
|
||||
audio_overrides_test
|
||||
@@ -234,4 +258,5 @@ coop_output_subdir(tests
|
||||
dx12_present_hook_test
|
||||
opengl_hook_test
|
||||
mock_game_test
|
||||
audio_verify_test
|
||||
ui_fit_test)
|
||||
|
||||
Reference in New Issue
Block a user