Apply PR #262's device-buffer fix for clicks caused by audio underruns. Reconfigure on both output-device and hardware sample-rate changes, respect the device's frame range, and read back the actual buffer size. Avoid rewriting unchanged sizes when buffer changes notify the format listener. Remove listeners before teardown, including failed initialization, so they cannot configure a device that the AudioUnit has already released. Add hardware-independent regression coverage for switching, rate changes, scope filtering, limits, synchronous notifications, diagnostic overrides, absent devices, and listener cleanup. Record the original gameplay evidence and the additional silent Core Audio validation in the audio reference. Validation: full host tests, Mac host build, docs checks, and the iOS source compile check (178 files) passed. Silent USB/speaker switching and speaker rates of 44.1/96/48 kHz verified 221/480/240 frames. HDMI switching and gameplay listening after these listener changes remain unvalidated. Co-authored-by: parsifal295 <130349765+parsifal295@users.noreply.github.com>
184 lines
10 KiB
Makefile
184 lines
10 KiB
Makefile
# dm/host unit tests in one command: make -C dm/host/tests GAME=<base game title ID> run (takes seconds; build output goes to build/ and is not committed)
|
|
B = build
|
|
PYTHON ?= python3
|
|
# game profile header (dm.h needs game_profile.h, generated by the host Makefile into ../gen/<profile>/)
|
|
# tests that use the game profile need GAME=<base game title ID> (there is no default game); GINC only expands when used, so tests without the profile build as before
|
|
GINC = $(if $(strip $(GAME)),-I../gen/$(GAME) -I../../games/$(GAME),$(error GAME is not set: make GAME=<base game title ID>: $(shell python3 ../../games/game.py list | awk -F'\t' '{printf "%s (%s) ", $$1, $$3}')))
|
|
GAME_H = ../gen/$(GAME)/game_profile.h
|
|
run: $(B)/t_heap_size $(B)/t_touch $(B)/t_gesture $(B)/t_oe $(B)/t_fs $(B)/t_fs_commit_list $(B)/t_thread_leak $(B)/t_fs_case $(B)/t_audio $(B)/t_audio_spsc $(B)/t_swkbd $(B)/t_altstack $(B)/t_condvar $(B)/t_condvar_old $(B)/t_pctl $(B)/t_time $(B)/t_shared_font $(B)/t_vorbis $(B)/t_vorbis_divides $(B)/t_hid $(B)/t_haptics $(B)/t_haptics_apple
|
|
$(B)/t_heap_size
|
|
$(B)/t_touch
|
|
$(B)/t_gesture
|
|
$(B)/t_oe 2>/dev/null
|
|
$(B)/t_fs 2>/dev/null
|
|
TMPDIR="$(abspath $(B))" $(B)/t_fs_commit_list
|
|
$(B)/t_thread_leak
|
|
TMPDIR="$(abspath $(B))" $(B)/t_fs_case 2>/dev/null
|
|
$(B)/t_audio
|
|
$(B)/t_audio_spsc
|
|
$(B)/t_fpslock
|
|
$(B)/t_audren_work
|
|
$(B)/t_swkbd
|
|
$(B)/t_altstack
|
|
$(B)/t_condvar
|
|
$(B)/t_condvar_old
|
|
$(B)/t_preempt
|
|
$(B)/t_preempt --all-peers
|
|
$(B)/t_pctl
|
|
$(B)/t_time
|
|
$(B)/t_shared_font
|
|
$(B)/t_system_event
|
|
$(B)/t_vorbis
|
|
$(B)/t_vorbis_divides
|
|
$(B)/t_movie_vpx
|
|
$(B)/t_hid
|
|
$(B)/t_haptics
|
|
$(B)/t_haptics_apple
|
|
$(B)/t_nro
|
|
$(B)/t_symbols
|
|
run: $(B)/t_nro
|
|
run: $(B)/t_symbols
|
|
$(B)/t_symbols: t_symbols.c ../hle.c ../loader.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -g -Wall -Werror -Wno-unused-function -Wno-deprecated-declarations -I.. $(GINC) -o $@ t_symbols.c
|
|
.PHONY: symbols
|
|
symbols: $(B)/t_symbols
|
|
$(B)/t_symbols
|
|
run: $(B)/t_system_event
|
|
run: $(B)/t_audren_work
|
|
$(B)/t_audren_work: t_audren_work.c ../hle_audren.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -g -Wall -Werror -Wno-unused-function -I.. $(GINC) -o $@ t_audren_work.c
|
|
.PHONY: audren-work
|
|
audren-work: $(B)/t_audren_work
|
|
$(B)/t_audren_work
|
|
$(B)/t_system_event: t_system_event.c ../hle_thread.c ../hle_sdk16.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -g -Wall -Werror -Wno-unused-function -Wno-frame-address -I.. $(GINC) -o $@ t_system_event.c
|
|
.PHONY: system-event
|
|
system-event: $(B)/t_system_event
|
|
$(B)/t_system_event
|
|
$(B)/t_nro: t_nro.c ../loader.c ../hle_ro.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -g -Wall -Wno-unused-function -Wno-deprecated-declarations -I.. $(GINC) -o $@ t_nro.c
|
|
.PHONY: nro
|
|
nro: $(B)/t_nro
|
|
$(B)/t_nro
|
|
$(GAME_H):
|
|
$(MAKE) -C .. game_profile GAME=$(GAME)
|
|
$(B)/t_heap_size: t_heap_size.c ../hle_svc.c ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wall -Werror -Wno-unused-function -fsanitize=undefined -I.. $(GINC) -o $@ t_heap_size.c
|
|
.PHONY: heap_size
|
|
heap_size: $(B)/t_heap_size
|
|
$(B)/t_heap_size
|
|
$(B)/t_touch: t_touch.c ../hle_touch.c ../front.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wno-unused-function -I.. $(GINC) -o $@ t_touch.c ../hle_touch.c
|
|
$(B)/t_gesture: t_gesture.c ../hle_touch.c ../front.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wall -Wno-unused-function -I.. $(GINC) -o $@ t_gesture.c ../hle_touch.c
|
|
$(B)/t_thread_leak: t_thread_leak.c ../thread.c ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wno-unused-function -I.. $(GINC) -o $@ t_thread_leak.c
|
|
$(B)/t_fs: t_fs.c t_fs_stub.c ../hle_fs.c ../hle_bigstack.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wno-unused-function -I.. $(GINC) -o $@ t_fs.c t_fs_stub.c ../hle_bigstack.c
|
|
$(B)/t_fs_commit_list: t_fs_commit_list.c t_fs_stub.c ../hle_fs.c ../hle_bigstack.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wall -Wno-unused-function -I.. $(GINC) -o $@ t_fs_commit_list.c t_fs_stub.c ../hle_bigstack.c
|
|
$(B)/t_fs_commit_list_tsan: t_fs_commit_list.c t_fs_stub.c ../hle_fs.c ../hle_bigstack.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -g -fsanitize=thread -Wall -Wno-unused-function -I.. $(GINC) -o $@ t_fs_commit_list.c t_fs_stub.c ../hle_bigstack.c
|
|
.PHONY: fs-tsan
|
|
fs-tsan: $(B)/t_fs_commit_list_tsan
|
|
TMPDIR="$(abspath $(B))" $(B)/t_fs_commit_list_tsan
|
|
$(B)/t_fs_case: t_fs_case.c ../hle_fs.c ../hle_bigstack.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wno-unused-function -I.. $(GINC) -o $@ t_fs_case.c ../hle_bigstack.c
|
|
$(B)/t_audio: t_audio.c ../hle_audio.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wno-unused-function -I.. $(GINC) -o $@ t_audio.c -framework AudioToolbox
|
|
$(B)/t_audio_spsc: t_audio_spsc.c ../hle_audio.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wno-unused-function -I.. $(GINC) -o $@ t_audio_spsc.c -framework AudioToolbox
|
|
$(B)/t_audio_device: t_audio_device.c ../hle_audio.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -g -Wall -Werror -Wno-unused-function -I.. $(GINC) -o $@ t_audio_device.c -framework AudioToolbox
|
|
.PHONY: audio-device
|
|
audio-device: $(B)/t_audio_device
|
|
$(B)/t_audio_device
|
|
run: audio-device
|
|
$(B)/t_audio_spsc_tsan: t_audio_spsc.c ../hle_audio.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -g -O1 -fsanitize=thread -Wno-unused-function -I.. $(GINC) -o $@ t_audio_spsc.c -framework AudioToolbox
|
|
run: $(B)/t_fpslock
|
|
$(B)/t_fpslock: t_fpslock.c ../hle_fpslock.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -g -Wno-unused-function $(GINC) -o $@ t_fpslock.c
|
|
$(B)/t_swkbd: t_swkbd.c ../hle_swkbd.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wno-unused-function -I.. $(GINC) -o $@ t_swkbd.c ../hle_swkbd.c
|
|
$(B)/t_altstack: t_altstack.c t_altstack_stub.c ../crash.c ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wno-unused-function -I.. $(GINC) -o $@ t_altstack.c t_altstack_stub.c ../crash.c
|
|
$(B)/t_pctl: t_pctl.c ../hle_misc.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wall -Werror -Wno-unused-function -I.. $(GINC) -o $@ t_pctl.c
|
|
$(B)/t_shared_font: t_shared_font.c ../hle_sdk16.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wall -Werror -Wno-unused-function -Wno-frame-address -I.. $(GINC) -o $@ t_shared_font.c
|
|
$(B)/t_hid: t_hid.c ../hle_hid.c ../hle_haptics.c ../hle_haptics.h ../pad_slots.h ../dm_input.h ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wall -Werror -Wno-unused-function -I.. $(GINC) -o $@ t_hid.c ../hle_haptics.c
|
|
$(B)/t_hid_tsan: t_hid.c ../hle_hid.c ../hle_haptics.c ../hle_haptics.h ../pad_slots.h ../dm_input.h ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -g -fsanitize=thread -Wall -Werror -Wno-unused-function -I.. $(GINC) -o $@ t_hid.c ../hle_haptics.c
|
|
$(B)/t_haptics: t_haptics.c ../hle_haptics.c ../hle_haptics.h ../dm_input.h | $(B)
|
|
clang -O1 -g -Wall -Werror -I.. -o $@ t_haptics.c ../hle_haptics.c
|
|
$(B)/t_haptics_apple: t_haptics_apple.m ../haptics_apple.m ../haptics_apple.h ../hle_haptics.c ../hle_haptics.h | $(B)
|
|
clang -O1 -g -fobjc-arc -Wall -Werror -I.. -o $@ t_haptics_apple.m ../hle_haptics.c -framework Cocoa -framework GameController -framework CoreHaptics
|
|
$(B)/t_time: t_time.c ../hle_time.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wall -Werror -Wno-unused-function -I.. $(GINC) -o $@ t_time.c
|
|
$(B)/t_oe: t_oe.c ../hle_oe.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wno-unused-function -I.. $(GINC) -o $@ t_oe.c
|
|
$(B)/t_condvar: t_condvar.c t_condvar_stub.c ../hle_thread.c ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wno-unused-function -DDM_TEST_HOOKS -I.. $(GINC) -o $@ t_condvar.c t_condvar_stub.c ../hle_thread.c
|
|
$(B)/t_condvar_old: t_condvar.c t_condvar_stub.c ../hle_thread.c ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wno-unused-function -DDM_TEST_HOOKS -DDM_TEST_CV_OLD_ORDER -I.. $(GINC) -o $@ t_condvar.c t_condvar_stub.c ../hle_thread.c
|
|
$(B)/t_preempt: t_preempt.c t_condvar_stub.c ../hle_thread.c ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -g -Wall -Werror -Wno-unused-function -I.. $(GINC) -o $@ t_preempt.c t_condvar_stub.c
|
|
.PHONY: preempt
|
|
preempt: $(B)/t_preempt
|
|
$(B)/t_preempt
|
|
$(B)/t_preempt --all-peers
|
|
run: $(B)/t_preempt
|
|
# the Vorbis tests build their own packets and need no game profile (they build without GAME)
|
|
$(B)/t_vorbis: t_vorbis.c ../../third_party/stb_vorbis/stb_vorbis.c | $(B)
|
|
clang -O1 -g -Wno-unused-function -Wno-tautological-compare -o $@ t_vorbis.c
|
|
$(B)/t_vorbis_divides: t_vorbis.c ../../third_party/stb_vorbis/stb_vorbis.c | $(B)
|
|
clang -O1 -g -DSTB_VORBIS_DIVIDES_IN_RESIDUE -Wno-unused-function -Wno-tautological-compare -o $@ t_vorbis.c
|
|
run: $(B)/t_movie_vpx
|
|
$(B)/t_movie_vpx: t_movie_vpx.c ../hle_movie.c $(GAME_H) ../gen/vpx/libvpx.a | $(B)
|
|
clang -O1 -g -Wno-unused-function -Wno-tautological-compare $(GINC) -I../../third_party/libvpx -I../../third_party/libvpx/config -I../../third_party/stb_vorbis -Wl,-dead_strip -o $@ t_movie_vpx.c ../gen/vpx/libvpx.a -framework AudioToolbox
|
|
../gen/vpx/libvpx.a: FORCE_VPX
|
|
$(MAKE) -C .. GAME=$(GAME) gen/vpx/libvpx.a
|
|
.PHONY: FORCE_VPX
|
|
$(B):
|
|
mkdir -p $@
|
|
.PHONY: run tsan
|
|
tsan: $(B)/t_audio_spsc_tsan $(B)/t_hid_tsan
|
|
$(B)/t_audio_spsc_tsan
|
|
$(B)/t_hid_tsan
|
|
|
|
MEM_FLAGS = -O1 -Wall -Werror -Wno-unused-function -Imemory_profile -I..
|
|
MEM_DEPS = t_svc_memory.c memory_profile/game_profile.h ../hle_svc.c ../hle_guestthread.c ../hle.h ../dm.h
|
|
$(B)/t_svc_memory: $(MEM_DEPS) | $(B)
|
|
clang $(MEM_FLAGS) -fsanitize=undefined -o $@ t_svc_memory.c
|
|
$(B)/t_svc_memory_unlimited: $(MEM_DEPS) | $(B)
|
|
clang $(MEM_FLAGS) -fsanitize=undefined -DDM_GAME_MEM_MAP_LIMIT=0 -o $@ t_svc_memory.c
|
|
$(B)/t_svc_memory_16k: $(MEM_DEPS) | $(B)
|
|
clang $(MEM_FLAGS) -fsanitize=address,undefined -DTEST_PAGE_16K -o $@ t_svc_memory.c
|
|
$(B)/t_svc_memory_tsan: $(MEM_DEPS) | $(B)
|
|
clang $(MEM_FLAGS) -fsanitize=thread -o $@ t_svc_memory.c
|
|
$(B)/t_svc_memory_dirty: $(MEM_DEPS) ../../gfx/nvn/nvn_dirty.c ../../gfx/nvn/nvn_dirty.h | $(B)
|
|
clang $(MEM_FLAGS) -DTEST_REAL_DIRTY -o $@ t_svc_memory.c ../../gfx/nvn/nvn_dirty.c
|
|
.PHONY: memory memory-tsan memory-dirty memory-profile
|
|
memory: $(B)/t_svc_memory $(B)/t_svc_memory_unlimited $(B)/t_svc_memory_16k
|
|
$(B)/t_svc_memory
|
|
$(B)/t_svc_memory_unlimited
|
|
$(B)/t_svc_memory_16k
|
|
memory-tsan: $(B)/t_svc_memory_tsan
|
|
$(B)/t_svc_memory_tsan
|
|
memory-dirty: $(B)/t_svc_memory_dirty
|
|
$(B)/t_svc_memory_dirty
|
|
memory-profile: $(B)/t_svc_memory
|
|
$(PYTHON) test_memory_profile.py
|
|
run: memory memory-dirty memory-profile
|
|
|
|
# A native blocking notification wait must release the thread's guest core.
|
|
$(B)/t_notify_sched: t_notify_sched.c t_condvar_stub.c ../hle_thread.c ../hle_oe.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -g -Wall -Werror -Wno-unused-function -DDM_TEST_THREAD_ENTER -I.. $(GINC) -o $@ t_notify_sched.c t_condvar_stub.c
|
|
.PHONY: notify-scheduler
|
|
notify-scheduler: $(B)/t_notify_sched
|
|
$(B)/t_notify_sched
|
|
$(B)/t_notify_sched --all-peers
|
|
run: notify-scheduler
|