mirror of
https://github.com/smittix/intercept.git
synced 2026-07-18 14:28:10 -07:00
Harden Morse PCM read loop and add stream diagnostics
This commit is contained in:
+69
-13
@@ -744,6 +744,8 @@ def morse_decoder_thread(
|
|||||||
CHUNK = 4096
|
CHUNK = 4096
|
||||||
SCOPE_INTERVAL = 0.10
|
SCOPE_INTERVAL = 0.10
|
||||||
WAITING_INTERVAL = 0.25
|
WAITING_INTERVAL = 0.25
|
||||||
|
IDLE_SLEEP = 0.04
|
||||||
|
STALLED_AFTER_DATA_SECONDS = 1.5
|
||||||
|
|
||||||
cfg = dict(decoder_config or {})
|
cfg = dict(decoder_config or {})
|
||||||
decoder = MorseDecoder(
|
decoder = MorseDecoder(
|
||||||
@@ -765,11 +767,20 @@ def morse_decoder_thread(
|
|||||||
last_scope = time.monotonic()
|
last_scope = time.monotonic()
|
||||||
last_waiting_emit = 0.0
|
last_waiting_emit = 0.0
|
||||||
waiting_since: float | None = None
|
waiting_since: float | None = None
|
||||||
|
last_pcm_at: float | None = None
|
||||||
|
pcm_bytes = 0
|
||||||
|
pcm_report_at = time.monotonic()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
fd: int | None
|
fd: int | None
|
||||||
|
non_blocking = False
|
||||||
try:
|
try:
|
||||||
fd = rtl_stdout.fileno()
|
fd = rtl_stdout.fileno()
|
||||||
|
try:
|
||||||
|
os.set_blocking(fd, False)
|
||||||
|
non_blocking = True
|
||||||
|
except Exception:
|
||||||
|
non_blocking = False
|
||||||
except Exception:
|
except Exception:
|
||||||
fd = None
|
fd = None
|
||||||
|
|
||||||
@@ -779,21 +790,53 @@ def morse_decoder_thread(
|
|||||||
|
|
||||||
data = b''
|
data = b''
|
||||||
if fd is not None:
|
if fd is not None:
|
||||||
try:
|
if non_blocking:
|
||||||
ready, _, _ = select.select([fd], [], [], 0.20)
|
try:
|
||||||
except Exception:
|
data = os.read(fd, CHUNK)
|
||||||
break
|
except BlockingIOError:
|
||||||
|
data = None
|
||||||
|
except Exception:
|
||||||
|
break
|
||||||
|
|
||||||
if ready:
|
if data is None:
|
||||||
data = os.read(fd, CHUNK)
|
now = time.monotonic()
|
||||||
|
should_emit_waiting = False
|
||||||
|
if last_pcm_at is None:
|
||||||
|
should_emit_waiting = True
|
||||||
|
elif (now - last_pcm_at) >= STALLED_AFTER_DATA_SECONDS:
|
||||||
|
should_emit_waiting = True
|
||||||
|
|
||||||
|
if should_emit_waiting and waiting_since is None:
|
||||||
|
waiting_since = now
|
||||||
|
now = time.monotonic()
|
||||||
|
if should_emit_waiting and now - last_waiting_emit >= WAITING_INTERVAL:
|
||||||
|
last_waiting_emit = now
|
||||||
|
_emit_waiting_scope(output_queue, waiting_since)
|
||||||
|
time.sleep(IDLE_SLEEP)
|
||||||
|
continue
|
||||||
else:
|
else:
|
||||||
if waiting_since is None:
|
try:
|
||||||
waiting_since = time.monotonic()
|
ready, _, _ = select.select([fd], [], [], 0.20)
|
||||||
now = time.monotonic()
|
except Exception:
|
||||||
if now - last_waiting_emit >= WAITING_INTERVAL:
|
break
|
||||||
last_waiting_emit = now
|
|
||||||
_emit_waiting_scope(output_queue, waiting_since)
|
if ready:
|
||||||
continue
|
data = os.read(fd, CHUNK)
|
||||||
|
else:
|
||||||
|
now = time.monotonic()
|
||||||
|
should_emit_waiting = False
|
||||||
|
if last_pcm_at is None:
|
||||||
|
should_emit_waiting = True
|
||||||
|
elif (now - last_pcm_at) >= STALLED_AFTER_DATA_SECONDS:
|
||||||
|
should_emit_waiting = True
|
||||||
|
|
||||||
|
if should_emit_waiting and waiting_since is None:
|
||||||
|
waiting_since = now
|
||||||
|
now = time.monotonic()
|
||||||
|
if should_emit_waiting and now - last_waiting_emit >= WAITING_INTERVAL:
|
||||||
|
last_waiting_emit = now
|
||||||
|
_emit_waiting_scope(output_queue, waiting_since)
|
||||||
|
continue
|
||||||
else:
|
else:
|
||||||
# Fallback for test streams without fileno().
|
# Fallback for test streams without fileno().
|
||||||
data = rtl_stdout.read(CHUNK)
|
data = rtl_stdout.read(CHUNK)
|
||||||
@@ -802,6 +845,8 @@ def morse_decoder_thread(
|
|||||||
break
|
break
|
||||||
|
|
||||||
waiting_since = None
|
waiting_since = None
|
||||||
|
last_pcm_at = time.monotonic()
|
||||||
|
pcm_bytes += len(data)
|
||||||
|
|
||||||
events = decoder.process_block(data)
|
events = decoder.process_block(data)
|
||||||
for event in events:
|
for event in events:
|
||||||
@@ -815,6 +860,17 @@ def morse_decoder_thread(
|
|||||||
with contextlib.suppress(queue.Full):
|
with contextlib.suppress(queue.Full):
|
||||||
output_queue.put_nowait(event)
|
output_queue.put_nowait(event)
|
||||||
|
|
||||||
|
now = time.monotonic()
|
||||||
|
if (now - pcm_report_at) >= 1.0:
|
||||||
|
kbps = (pcm_bytes * 8.0) / max(1e-6, (now - pcm_report_at)) / 1000.0
|
||||||
|
with contextlib.suppress(queue.Full):
|
||||||
|
output_queue.put_nowait({
|
||||||
|
'type': 'info',
|
||||||
|
'text': f'[pcm] {pcm_bytes} B in {now - pcm_report_at:.1f}s ({kbps:.1f} kbps)',
|
||||||
|
})
|
||||||
|
pcm_bytes = 0
|
||||||
|
pcm_report_at = now
|
||||||
|
|
||||||
except Exception as e: # pragma: no cover - defensive runtime guard
|
except Exception as e: # pragma: no cover - defensive runtime guard
|
||||||
logger.debug(f'Morse decoder thread error: {e}')
|
logger.debug(f'Morse decoder thread error: {e}')
|
||||||
finally:
|
finally:
|
||||||
|
|||||||
Reference in New Issue
Block a user