Wait for the capture loop when the microphone stops
stop() closed the encoder and cleared the transmit state while the capture loop could still be in its last frame, which could turn the transmit indicator back on, or overlap the loop of a quick restart on the same speech detector and processing chain. It now closes the line to wake the loop and waits for it to finish before tearing down. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -46,6 +46,8 @@ public final class CaptureVoiceInput implements VoiceInput {
|
||||
Math.max(1, HANGOVER_MS * VoiceFormat.SAMPLE_RATE / 1000 / VoiceFormat.FRAME_SIZE);
|
||||
private static final int PREROLL_FRAMES =
|
||||
Math.max(1, PREROLL_MS * VoiceFormat.SAMPLE_RATE / 1000 / VoiceFormat.FRAME_SIZE);
|
||||
/** How long stop() waits for the capture loop to finish its frame. */
|
||||
private static final long STOP_TIMEOUT_MS = 500;
|
||||
|
||||
private final ConcurrentLinkedQueue<byte[]> queue = new ConcurrentLinkedQueue<>();
|
||||
private final AtomicBoolean muted = new AtomicBoolean(false);
|
||||
@@ -281,9 +283,20 @@ public final class CaptureVoiceInput implements VoiceInput {
|
||||
|
||||
public synchronized void stop() {
|
||||
running.set(false);
|
||||
if (captureThread != null) {
|
||||
captureThread.interrupt();
|
||||
Thread capture = captureThread;
|
||||
captureThread = null;
|
||||
if (line != null) {
|
||||
line.close(); // wakes the capture loop's blocking read
|
||||
line = null;
|
||||
}
|
||||
if (capture != null) {
|
||||
// Let the loop finish its frame, so it cannot reopen the gate or overlap a restart.
|
||||
capture.interrupt();
|
||||
try {
|
||||
capture.join(STOP_TIMEOUT_MS);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
cleanup();
|
||||
queue.clear();
|
||||
|
||||
Reference in New Issue
Block a user