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.
This commit is contained in:
@@ -96,7 +96,7 @@ try
|
|||||||
int beepFrames = 0;
|
int beepFrames = 0;
|
||||||
int recordOffset = 0;
|
int recordOffset = 0;
|
||||||
short[] recordBuf = null!; // assigned on BEEPING→RECORDING transition
|
short[] recordBuf = null!; // assigned on BEEPING→RECORDING transition
|
||||||
var playbackDone = new PlaybackDoneFlag();
|
PlaybackDoneFlag? playbackDone = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -157,6 +157,7 @@ try
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
playbackDone = new PlaybackDoneFlag();
|
||||||
FireAndForgetPlayback(device, recordBuf, playbackDone);
|
FireAndForgetPlayback(device, recordBuf, playbackDone);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -177,7 +178,7 @@ try
|
|||||||
case State.Playback:
|
case State.Playback:
|
||||||
{
|
{
|
||||||
// Discard input during playback (gate the detector).
|
// Discard input during playback (gate the detector).
|
||||||
if (playbackDone.Consume())
|
if (playbackDone!.Consume())
|
||||||
{
|
{
|
||||||
model.Reset();
|
model.Reset();
|
||||||
Console.WriteLine("[state] IDLE");
|
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
|
// 2 s timeout so a failed callback (which PortAudio silently swallows
|
||||||
// and would leave 'done' unset) eventually releases the stream + handle
|
// and would leave 'done' unset) eventually releases the stream + handle
|
||||||
// instead of leaking them for the process lifetime.
|
// 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);
|
Thread.Sleep(200);
|
||||||
stream.Stop();
|
stream.Stop();
|
||||||
stream.Dispose();
|
stream.Dispose();
|
||||||
@@ -348,7 +350,8 @@ static void FireAndForgetPlayback(int device, short[] recordBuf, PlaybackDoneFla
|
|||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
// Same 2 s safety timeout as the beep cleanup.
|
// 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);
|
Thread.Sleep(200);
|
||||||
stream.Stop();
|
stream.Stop();
|
||||||
stream.Dispose();
|
stream.Dispose();
|
||||||
|
|||||||
Reference in New Issue
Block a user