proper tests

This commit is contained in:
2026-04-10 18:29:58 -03:00
parent e906b0a963
commit ea9dbf8772
16 changed files with 1077 additions and 15 deletions

View File

@@ -1,6 +1,7 @@
"""Stream lifecycle — manages recording, scene detection, audio extraction, and transcription buffering."""
import logging
import time
from threading import Thread
from gi.repository import GLib
@@ -66,6 +67,7 @@ class StreamLifecycle:
"""
self._streaming = True
self._gone_live = False
self._start_monotonic = time.monotonic()
self._rust_transport = rust_transport
if rust_transport:
@@ -177,13 +179,16 @@ class StreamLifecycle:
GLib.idle_add(self._go_live_once)
if self._stream_mgr:
self._stream_mgr.capture_now(on_new_frames=self._handle_new_scene_frames)
if self._stream_mgr:
self._stream_mgr.capture_now(on_new_frames=self._handle_new_scene_frames)
def _go_live_once(self):
if self._stream_mgr:
elapsed = time.monotonic() - self._start_monotonic
log.info("Going LIVE (startup delay elapsed)")
self._timeline.go_live()
if self._stream_mgr.telemetry:
self._stream_mgr.telemetry.metric("first_live", {
"elapsed_s": round(elapsed, 2),
})
return False
def _tick_live(self):

View File

@@ -58,7 +58,7 @@ class StreamManager:
self.agent_dir = self.session_dir / "agent"
self.readonly = False
self.telemetry = None
self._telemetry = None
self.recorder = StreamRecorder(self.session_dir)
self.processor = SessionProcessor(self.session_dir)
@@ -88,7 +88,7 @@ class StreamManager:
mgr.audio_dir = session_dir / "audio"
mgr.agent_dir = session_dir / "agent"
mgr.readonly = False
mgr.telemetry = None
mgr._telemetry = None
# No recorder — Rust server owns transport + recording.
mgr.recorder = None
@@ -121,6 +121,16 @@ class StreamManager:
session_id, len(mgr.recorder.recording_segments), mgr.frame_count)
return mgr
@property
def telemetry(self):
return self._telemetry
@telemetry.setter
def telemetry(self, val):
self._telemetry = val
if self.processor:
self.processor._telemetry = val
# -- Recorder delegation --
@property

View File

@@ -51,6 +51,7 @@ class SessionProcessor:
self._get_recording_path = None
self._get_current_global_offset = None
self._telemetry = None
def attach(self, get_recording_path, get_current_global_offset):
"""Wire up callbacks to query the recorder's current state."""
@@ -75,6 +76,11 @@ class SessionProcessor:
self._append_frame_index(entry)
log.info("Scene frame: %s at %.1fs", frame_id, global_ts)
if self._telemetry:
self._telemetry.metric("scene_frame", {
"id": frame_id, "global_ts": global_ts,
})
if self._on_new_frames:
self._on_new_frames([entry])
@@ -465,6 +471,15 @@ class SessionProcessor:
if safe_duration is None or safe_duration <= 0:
continue
# Raw AAC files (from Rust server) have no reliable duration metadata.
# ffprobe wildly overestimates (e.g. 1569s for a 50s session).
# Cap to wall-clock elapsed time as a sanity bound.
wall_elapsed = self._wall_clock_offset()
if wall_elapsed > 0 and safe_duration > wall_elapsed * 1.5:
log.debug("Audio: capping probed duration %.1fs to wall-clock %.1fs",
safe_duration, wall_elapsed)
safe_duration = wall_elapsed
# Fail-safe: processed_time can accumulate past the file if the
# source was recreated (e.g. server restarted same session).
if processed_time > safe_duration:
@@ -495,6 +510,11 @@ class SessionProcessor:
global_start = processed_time + offset
log.info("Audio chunk: %s (%.1fs → %.1fs, global %.1fs)",
wav_path.name, processed_time, process_to, global_start)
if self._telemetry:
self._telemetry.metric("audio_chunk", {
"chunk": chunk_num, "start": processed_time,
"end": process_to, "global_start": global_start,
})
if self._on_new_audio:
try:
self._on_new_audio(