From 070cc0767a9885d5abf4d7ecf2b557cb99869280 Mon Sep 17 00:00:00 2001 From: Assistant builder Date: Fri, 12 Jun 2026 13:38:09 +0000 Subject: [PATCH] Test 3: per-cycle PlaybackDoneFlag + log timeout in fire-and-forget cleanup Stale Set() from a delayed cleanup task could short-circuit a future PLAYBACK state; new flag per cycle avoids the cross-cycle leak. Also log when the 2 s done.Wait timeout fires so silent PortAudio callback faults are visible during hardware debugging. --- tests/03-full-cycle-cs/Program.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/03-full-cycle-cs/Program.cs b/tests/03-full-cycle-cs/Program.cs index 416c5c2..dabe81f 100644 --- a/tests/03-full-cycle-cs/Program.cs +++ b/tests/03-full-cycle-cs/Program.cs @@ -96,7 +96,7 @@ try int beepFrames = 0; int recordOffset = 0; short[] recordBuf = null!; // assigned on BEEPING→RECORDING transition - var playbackDone = new PlaybackDoneFlag(); + PlaybackDoneFlag? playbackDone = null; try { @@ -157,6 +157,7 @@ try { try { + playbackDone = new PlaybackDoneFlag(); FireAndForgetPlayback(device, recordBuf, playbackDone); } catch (Exception ex) @@ -177,7 +178,7 @@ try case State.Playback: { // Discard input during playback (gate the detector). - if (playbackDone.Consume()) + if (playbackDone!.Consume()) { model.Reset(); Console.WriteLine("[state] IDLE"); @@ -287,7 +288,8 @@ static void FireAndForgetBeep(int device, short[] beepBuffer) // 2 s timeout so a failed callback (which PortAudio silently swallows // and would leave 'done' unset) eventually releases the stream + handle // instead of leaking them for the process lifetime. - done.Wait(TimeSpan.FromSeconds(2)); + if (!done.Wait(TimeSpan.FromSeconds(2))) + Console.Error.WriteLine("[error] beep playback timed out — callback may have faulted"); Thread.Sleep(200); stream.Stop(); stream.Dispose(); @@ -348,7 +350,8 @@ static void FireAndForgetPlayback(int device, short[] recordBuf, PlaybackDoneFla Task.Run(() => { // Same 2 s safety timeout as the beep cleanup. - done.Wait(TimeSpan.FromSeconds(2)); + if (!done.Wait(TimeSpan.FromSeconds(2))) + Console.Error.WriteLine("[error] recording playback timed out — callback may have faulted"); Thread.Sleep(200); stream.Stop(); stream.Dispose();