"""Barge-in detection, driven by a fake mic stream (no audio hardware).""" import sys from pathlib import Path import numpy as np sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) from bolt_pet.audio.barge_in import BargeInDetector class FakeStream: """Yields frames of a given amplitude, mimicking sounddevice's (data, overflowed) 2-D int16 return shape.""" def __init__(self, amplitudes): self._amplitudes = list(amplitudes) def read(self, frames): amplitude = self._amplitudes.pop(0) if self._amplitudes else 0 data = np.full((frames, 1), amplitude, dtype=np.int16) return data, False def test_silence_never_interrupts(): detector = BargeInDetector(FakeStream([0] * 20), threshold=1000, required_frames=3) assert not any(detector.check() for _ in range(20)) def test_sustained_speech_interrupts_after_the_required_frames(): detector = BargeInDetector(FakeStream([2000] * 5), threshold=1000, required_frames=3) assert detector.check() is False assert detector.check() is False assert detector.check() is True def test_a_single_thump_does_not_interrupt(): # loud, quiet, loud, quiet ... never three in a row detector = BargeInDetector(FakeStream([2000, 0, 2000, 0, 2000, 0]), threshold=1000, required_frames=3) assert not any(detector.check() for _ in range(6)) def test_counter_resets_after_a_quiet_frame(): detector = BargeInDetector(FakeStream([2000, 2000, 0, 2000, 2000, 2000]), threshold=1000, required_frames=3) results = [detector.check() for _ in range(6)] assert results == [False, False, False, False, False, True] def test_reset_clears_progress(): detector = BargeInDetector(FakeStream([2000] * 6), threshold=1000, required_frames=3) detector.check() detector.check() detector.reset() assert detector.check() is False assert detector.loud_frames == 1 def test_a_mic_error_mid_playback_is_not_fatal(): class BrokenStream: def read(self, frames): raise OSError("device disappeared") detector = BargeInDetector(BrokenStream(), threshold=1000, required_frames=1) assert detector.check() is False