Tell a recorder that died from one that was asked to stop

The pump now says when the capture ended with nothing captured, which is worth
saying: parec refusing the device looks like silence otherwise. But stop() ends
it the same way, so a recording shorter than 0.3 s raised that alarm first and
"Recording too short" second, sending the user after a sound server that is
fine. It follows the flag MeetingRecorder already carries for this.

test_desktop_compat.py moves into the files for the modules it covers, so a
test is where the next person looking at that module will find it.
This commit is contained in:
yusufipk
2026-08-01 20:34:15 +07:00
parent 1544cca15c
commit 45a064e545
2 changed files with 115 additions and 19 deletions
+19 -9
View File
@@ -44,6 +44,7 @@ class Recorder(QObject):
self._buffer = bytearray()
self._rms = []
self._cancelled = False
self._stopping = False
self._lock = threading.Lock()
@property
@@ -71,6 +72,7 @@ class Recorder(QObject):
self._buffer = bytearray()
self._rms = []
self._cancelled = False
self._stopping = False
self._max_bytes = int(max_seconds * RATE * SAMPLE_WIDTH * CHANNELS)
self._thread = threading.Thread(target=self._pump, daemon=True)
self._thread.start()
@@ -94,17 +96,25 @@ class Recorder(QObject):
break
except (OSError, ValueError):
pass
if not self._cancelled and not self._buffer and proc.poll() is not None:
try:
detail = proc.stderr.read().decode("utf-8", "replace").strip()
except (AttributeError, OSError):
detail = ""
self.failed.emit(t(
"Audio recorder stopped before receiving sound: {error}",
error=detail or f"exit code {proc.returncode}",
))
# Nobody asked it to end and it captured nothing: the recorder is not
# installed properly, or the device was refused. Said out loud here,
# because stop() would otherwise report it as a recording that was too
# short, which sends the user looking in the wrong place.
with self._lock:
captured = bool(self._buffer)
if self._stopping or self._cancelled or captured:
return
try:
detail = proc.stderr.read().decode("utf-8", "replace").strip()
except (AttributeError, OSError):
detail = ""
self.failed.emit(t(
"Audio recorder stopped before receiving sound: {error}",
error=detail or f"exit code {proc.returncode}",
))
def _terminate(self):
self._stopping = True
proc = self._proc
if proc and proc.poll() is None:
try: