Files
voice-cat/tests/CMakeLists.txt

90 lines
5.0 KiB
CMake
Raw Permalink Normal View History

2026-06-15 23:48:44 +02:00
# Tests use plain asserts + exit codes (no framework dep needed).
# Behavior tests — not just "it compiles" — are how milestones are judged (AGENTS.md).
add_executable(test_smoke test_smoke.cpp)
target_link_libraries(test_smoke PRIVATE voicecat::voicecat)
target_compile_features(test_smoke PRIVATE cxx_std_20)
add_test(NAME smoke COMMAND test_smoke)
2026-06-15 23:48:44 +02:00
# frame_codec has no third-party deps; runs under both dev and m1-dev.
# Needs core/src on the include path to reach internal headers (protocol/, session/, etc.).
add_executable(test_frame_codec test_frame_codec.cpp)
target_link_libraries(test_frame_codec PRIVATE voicecat::voicecat)
target_compile_features(test_frame_codec PRIVATE cxx_std_20)
target_include_directories(test_frame_codec PRIVATE ${CMAKE_SOURCE_DIR}/core/src)
add_test(NAME frame_codec COMMAND test_frame_codec)
if(VOICECAT_USE_VCPKG_DEPS)
set(VC_TEST_INTERNAL_INCLUDES
${CMAKE_SOURCE_DIR}/core/src
${CMAKE_SOURCE_DIR}/server/src
${CMAKE_BINARY_DIR}/core/generated) # protobuf-generated headers
add_executable(test_envelope test_envelope.cpp)
target_link_libraries(test_envelope PRIVATE voicecat::voicecat)
target_compile_features(test_envelope PRIVATE cxx_std_20)
target_include_directories(test_envelope PRIVATE ${VC_TEST_INTERNAL_INCLUDES})
add_test(NAME envelope COMMAND test_envelope)
add_executable(test_tls_loopback test_tls_loopback.cpp)
target_link_libraries(test_tls_loopback PRIVATE voicecat::voicecat)
target_compile_features(test_tls_loopback PRIVATE cxx_std_20)
target_include_directories(test_tls_loopback PRIVATE ${VC_TEST_INTERNAL_INCLUDES})
add_test(NAME tls_loopback COMMAND test_tls_loopback)
# Links voicecat::server (which pulls in voicecat::voicecat + all deps transitively).
add_executable(test_m1_integration test_m1_integration.cpp)
target_link_libraries(test_m1_integration PRIVATE voicecat::server)
target_compile_features(test_m1_integration PRIVATE cxx_std_20)
target_include_directories(test_m1_integration PRIVATE ${VC_TEST_INTERNAL_INCLUDES})
add_test(NAME m1_integration COMMAND test_m1_integration)
set_tests_properties(m1_integration PROPERTIES TIMEOUT 60)
# ── M2 unit tests ──────────────────────────────────────────────────────────
add_executable(test_voice_frame test_voice_frame.cpp)
target_link_libraries(test_voice_frame PRIVATE voicecat::voicecat)
target_compile_features(test_voice_frame PRIVATE cxx_std_20)
target_include_directories(test_voice_frame PRIVATE ${VC_TEST_INTERNAL_INCLUDES})
add_test(NAME voice_frame COMMAND test_voice_frame)
add_executable(test_media_aead test_media_aead.cpp)
target_link_libraries(test_media_aead PRIVATE voicecat::voicecat)
target_compile_features(test_media_aead PRIVATE cxx_std_20)
target_include_directories(test_media_aead PRIVATE ${VC_TEST_INTERNAL_INCLUDES})
add_test(NAME media_aead COMMAND test_media_aead)
add_executable(test_opus_codec test_opus_codec.cpp)
target_link_libraries(test_opus_codec PRIVATE voicecat::voicecat)
target_compile_features(test_opus_codec PRIVATE cxx_std_20)
target_include_directories(test_opus_codec PRIVATE ${VC_TEST_INTERNAL_INCLUDES})
add_test(NAME opus_codec COMMAND test_opus_codec)
# M2 exit criterion: two headless clients relay encrypted Opus frames via the SFU.
add_executable(test_m2_voice test_m2_voice.cpp)
target_link_libraries(test_m2_voice PRIVATE voicecat::server)
target_compile_features(test_m2_voice PRIVATE cxx_std_20)
target_include_directories(test_m2_voice PRIVATE ${VC_TEST_INTERNAL_INCLUDES})
add_test(NAME m2_voice COMMAND test_m2_voice)
set_tests_properties(m2_voice PROPERTIES TIMEOUT 120)
# Same exit criterion, but through the real C ABI (vc_client), not raw sockets —
# proves stream_start/stop/UDP-binding in core/src/core/client.cpp actually work.
add_executable(test_voice_client_abi test_voice_client_abi.cpp)
target_link_libraries(test_voice_client_abi PRIVATE voicecat::server)
target_compile_features(test_voice_client_abi PRIVATE cxx_std_20)
target_include_directories(test_voice_client_abi PRIVATE ${VC_TEST_INTERNAL_INCLUDES})
add_test(NAME voice_client_abi COMMAND test_voice_client_abi)
set_tests_properties(voice_client_abi PROPERTIES TIMEOUT 60)
feat(M3): multi-stream & per-channel tuning Implements docs/roadmap.md M3: multiple concurrent streams per user (MIC + SCREEN_AUDIO + AUX_DEVICE), independent per-stream receiver gain/mute/noise- reduction, talk indicators, and enforced per-channel Opus configurability (mono/stereo, bitrate, frame size, FEC/DTX, application). Bugs fixed along the way (found while implementing, not pre-existing scope): - Server hard-coded stream_id=1 for every announce, so a second stream from the same user silently overwrote the first in SessionRegistry::set_user_stream. Now a per-session counter (ConnSession::next_stream_id_); handle_stream_stop validates against announced_stream_ids_ before clearing. - Client dropped mode/dtx/complexity/application from effective_audio even for the single M2 stream -- only sample_rate/bitrate_bps/frame_ms/fec were ever applied to OpusParams. Fixed on both the send (handle_stream_announce_result) and receive (sync_remote_streams) paths via a shared opus_params_from_audio_config() helper. - OpusEncoder always used OPUS_APPLICATION_VOIP; added OpusParams::application and wired it through. - on_playback's per-stream decode passed the wrong frame_size to opus_decode (total samples instead of samples-per-channel), which would have overflowed the decode buffer for any stereo stream. - teardown_voice() raced when called concurrently from run_io()'s own cleanup and from disconnect() on a different thread -- both could see udp_thread_/talk_timer_thread_ as joinable() at once and race to join() the same std::thread (intermittent std::system_error under ctest). Fixed with a teardown_mu_ guard instead of carrying the flake forward. New: - Per-channel AudioConfig: SessionRegistry now seeds Lobby (mono/24kbps/VOIP/ FEC+DTX) and a new "Music Room" channel (stereo/128kbps/AUDIO/no DTX); handle_stream_announce enforces the channel's config, clamping (not overriding) bitrate_bps to its ceiling. - core/src/core/client.h/.cpp: local-stream state is now a std::unordered_map<int, LocalStream> keyed by vc_stream_kind, with request_id-correlated announce/result handling (request_id already round-tripped on the wire; just wasn't read before). on_capture_frame is kind-aware and upmixes mono capture to stereo when a stream's config calls for it. set_self_mute's mic_muted now only gates the MIC kind. NS is wired through set_remote_stream. New run_talk_timer() thread emits VC_EVENT_TALK_STATE from both remote and local edge detection. - core/src/audio/audio_engine.h/.cpp: kind-keyed injection taps (inject_capture), stereo-to-mono downmix at the decode/mix boundary, RemoteStream gains recv_ns (lazy ApmProcessor) + noise_reduction_enabled and last_voice_ms/talking; new set_stream_noise_reduction() and poll_talk_transitions(). - core/src/session/session.h/.cpp: Stream now carries the full AudioConfig, not just sample_rate/frame_ms. - New additive C ABI (core/include/voicecat.h): vc_audio_config + vc_get_stream_audio_config (effective Opus config for any stream you own or a peer's); vc_test_inject_capture (test-only synthetic PCM injection, clearly marked, mirrors AudioEngine::inject_capture). - tests/test_m3_multistream.cpp: the M3 exit criterion through the real ABI (mirrors test_voice_client_abi.cpp's approach, not raw sockets) -- two concurrent local streams, independent gain/mute/NS control, per-channel config divergence via vc_get_stream_audio_config, talk indicators. Explicitly out of scope for this pass (tracked in PROGRESS.md, not silently dropped): VAD/PTT input gate + device enumeration; real WASAPI loopback capture for SCREEN_AUDIO (synthetic injection only); true stereo playback output (AudioEngine's mixer/output device stays mono -- Opus itself is fully stereo-correct on the wire). ctest --test-dir build/m1-dev: 11/11 green, verified across 3 consecutive full-suite runs plus 8 standalone runs of the new test. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-16 14:12:37 +02:00
# M3 exit criterion: multi-stream (mic + desktop audio), independent per-stream
# gain/mute/NS, per-channel Opus configurability, talk indicators -- all through the
# real C ABI (vc_client), not raw sockets.
add_executable(test_m3_multistream test_m3_multistream.cpp)
target_link_libraries(test_m3_multistream PRIVATE voicecat::server)
target_compile_features(test_m3_multistream PRIVATE cxx_std_20)
target_include_directories(test_m3_multistream PRIVATE ${VC_TEST_INTERNAL_INCLUDES})
add_test(NAME m3_multistream COMMAND test_m3_multistream)
set_tests_properties(m3_multistream PROPERTIES TIMEOUT 60)
2026-06-15 23:48:44 +02:00
endif()