Require cancel listener availability before entering recording state
This commit is contained in:
parent
aa77dbc395
commit
2b494851a6
2 changed files with 46 additions and 3 deletions
17
src/aman.py
17
src/aman.py
|
|
@ -77,11 +77,13 @@ class Daemon:
|
||||||
self.vocabulary = VocabularyEngine(cfg.vocabulary)
|
self.vocabulary = VocabularyEngine(cfg.vocabulary)
|
||||||
self._stt_hint_kwargs_cache: dict[str, Any] | None = None
|
self._stt_hint_kwargs_cache: dict[str, Any] | None = None
|
||||||
|
|
||||||
def _arm_cancel_listener(self):
|
def _arm_cancel_listener(self) -> bool:
|
||||||
try:
|
try:
|
||||||
self.desktop.start_cancel_listener(lambda: self.cancel_recording())
|
self.desktop.start_cancel_listener(lambda: self.cancel_recording())
|
||||||
|
return True
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logging.error("failed to start cancel listener: %s", exc)
|
logging.error("failed to start cancel listener: %s", exc)
|
||||||
|
return False
|
||||||
|
|
||||||
def _disarm_cancel_listener(self):
|
def _disarm_cancel_listener(self):
|
||||||
try:
|
try:
|
||||||
|
|
@ -130,12 +132,23 @@ class Daemon:
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logging.error("record start failed: %s", exc)
|
logging.error("record start failed: %s", exc)
|
||||||
return
|
return
|
||||||
|
if not self._arm_cancel_listener():
|
||||||
|
try:
|
||||||
|
stream.stop()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
stream.close()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
logging.error("recording start aborted because cancel listener is unavailable")
|
||||||
|
return
|
||||||
|
|
||||||
self.stream = stream
|
self.stream = stream
|
||||||
self.record = record
|
self.record = record
|
||||||
prev = self.state
|
prev = self.state
|
||||||
self.state = State.RECORDING
|
self.state = State.RECORDING
|
||||||
logging.debug("state: %s -> %s", prev, self.state)
|
logging.debug("state: %s -> %s", prev, self.state)
|
||||||
self._arm_cancel_listener()
|
|
||||||
logging.info("recording started")
|
logging.info("recording started")
|
||||||
if self.timer:
|
if self.timer:
|
||||||
self.timer.cancel()
|
self.timer.cancel()
|
||||||
|
|
|
||||||
|
|
@ -15,14 +15,17 @@ from config import Config, VocabularyReplacement
|
||||||
|
|
||||||
|
|
||||||
class FakeDesktop:
|
class FakeDesktop:
|
||||||
def __init__(self):
|
def __init__(self, *, fail_cancel_listener: bool = False):
|
||||||
self.inject_calls = []
|
self.inject_calls = []
|
||||||
self.quit_calls = 0
|
self.quit_calls = 0
|
||||||
self.cancel_listener_start_calls = 0
|
self.cancel_listener_start_calls = 0
|
||||||
self.cancel_listener_stop_calls = 0
|
self.cancel_listener_stop_calls = 0
|
||||||
self.cancel_listener_callback = None
|
self.cancel_listener_callback = None
|
||||||
|
self.fail_cancel_listener = fail_cancel_listener
|
||||||
|
|
||||||
def start_cancel_listener(self, callback) -> None:
|
def start_cancel_listener(self, callback) -> None:
|
||||||
|
if self.fail_cancel_listener:
|
||||||
|
raise RuntimeError("cancel listener unavailable")
|
||||||
self.cancel_listener_start_calls += 1
|
self.cancel_listener_start_calls += 1
|
||||||
self.cancel_listener_callback = callback
|
self.cancel_listener_callback = callback
|
||||||
|
|
||||||
|
|
@ -93,6 +96,18 @@ class FakeAudio:
|
||||||
self.size = size
|
self.size = size
|
||||||
|
|
||||||
|
|
||||||
|
class FakeStream:
|
||||||
|
def __init__(self):
|
||||||
|
self.stop_calls = 0
|
||||||
|
self.close_calls = 0
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.stop_calls += 1
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
self.close_calls += 1
|
||||||
|
|
||||||
|
|
||||||
class DaemonTests(unittest.TestCase):
|
class DaemonTests(unittest.TestCase):
|
||||||
def _config(self) -> Config:
|
def _config(self) -> Config:
|
||||||
cfg = Config()
|
cfg = Config()
|
||||||
|
|
@ -272,6 +287,21 @@ class DaemonTests(unittest.TestCase):
|
||||||
self.assertEqual(desktop.cancel_listener_stop_calls, 1)
|
self.assertEqual(desktop.cancel_listener_stop_calls, 1)
|
||||||
self.assertIsNone(desktop.cancel_listener_callback)
|
self.assertIsNone(desktop.cancel_listener_callback)
|
||||||
|
|
||||||
|
@patch("aman.start_audio_recording")
|
||||||
|
def test_recording_does_not_start_when_cancel_listener_fails(self, start_mock):
|
||||||
|
stream = FakeStream()
|
||||||
|
start_mock.return_value = (stream, object())
|
||||||
|
desktop = FakeDesktop(fail_cancel_listener=True)
|
||||||
|
daemon = self._build_daemon(desktop, FakeModel(), verbose=False)
|
||||||
|
|
||||||
|
daemon.toggle()
|
||||||
|
|
||||||
|
self.assertEqual(daemon.get_state(), aman.State.IDLE)
|
||||||
|
self.assertIsNone(daemon.stream)
|
||||||
|
self.assertIsNone(daemon.record)
|
||||||
|
self.assertEqual(stream.stop_calls, 1)
|
||||||
|
self.assertEqual(stream.close_calls, 1)
|
||||||
|
|
||||||
|
|
||||||
class LockTests(unittest.TestCase):
|
class LockTests(unittest.TestCase):
|
||||||
def test_lock_rejects_second_instance(self):
|
def test_lock_rejects_second_instance(self):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue