Selaa lähdekoodia

further bridge updates

Benjamin Harris 1 kuukausi sitten
vanhempi
sitoutus
8d9d87db3d
3 muutettua tiedostoa jossa 40 lisäystä ja 39 poistoa
  1. BIN
      bridge/__pycache__/bridge.cpython-312.pyc
  2. 29 38
      bridge/admin.py
  3. 11 1
      bridge/bridge.py

BIN
bridge/__pycache__/bridge.cpython-312.pyc


+ 29 - 38
bridge/admin.py

@@ -151,63 +151,54 @@ _playback_status: dict = {
 async def _stream_file(filepath: Path, speed: float) -> None:
     global _playback_status
     try:
-        import miniaudio  # type: ignore
-    except ImportError:
-        _playback_status.update({
-            "state": "error",
-            "error": "miniaudio not installed — run: pip install miniaudio",
-        })
+        import miniaudio
+        import bridge  # import the running bridge module
+    except ImportError as e:
+        _playback_status.update({"state": "error", "error": str(e)})
         return
 
     try:
         _playback_status["state"] = "loading"
-
-        duration = 0.0
-        try:
-            info     = miniaudio.get_file_info(str(filepath))
-            duration = info.duration
-        except Exception:
-            pass
-
+        info     = miniaudio.get_file_info(str(filepath))
+        duration = info.duration
         _playback_status.update({
-            "state":    "playing",
-            "duration": round(duration, 1),
-            "elapsed":  0.0,
-            "progress": 0,
+            "state": "playing", "duration": round(duration, 1),
+            "elapsed": 0.0, "progress": 0,
         })
 
         chunk_frames = 4096
         chunk_secs   = chunk_frames / 16000
         elapsed      = 0.0
 
-        async with websockets.connect(WS_URL, max_size=2**23) as ws:
-            stream = miniaudio.stream_file(
-                str(filepath),
-                output_format=miniaudio.SampleFormat.SIGNED16,
-                nchannels=1,
-                sample_rate=16000,
-                frames_to_read=chunk_frames,
+        stream = miniaudio.stream_file(
+            str(filepath),
+            output_format=miniaudio.SampleFormat.FLOAT32,  # match bridge dtype
+            nchannels=1,
+            sample_rate=16000,
+            frames_to_read=chunk_frames,
+        )
+
+        for chunk in stream:
+            # Wait until bridge has initialised its injection queue
+            while bridge.test_audio_queue is None:
+                await asyncio.sleep(0.1)
+            
+            chunk_bytes = bytes(chunk)
+            await bridge.test_audio_queue.put(chunk_bytes)
+            elapsed += chunk_secs
+            _playback_status["elapsed"]  = round(elapsed, 1)
+            _playback_status["progress"] = (
+                min(99, round(elapsed / duration * 100)) if duration else 0
             )
-            for chunk in stream:
-                await ws.send(bytes(chunk))
-                elapsed += chunk_secs
-                _playback_status["elapsed"]  = round(elapsed, 1)
-                _playback_status["progress"] = (
-                    min(99, round(elapsed / duration * 100)) if duration else 0
-                )
-                await asyncio.sleep(chunk_secs / speed)
+            await asyncio.sleep(chunk_secs / speed)
 
         _playback_status.update({
-            "state":    "done",
-            "progress": 100,
-            "elapsed":  round(duration, 1),
+            "state": "done", "progress": 100, "elapsed": round(duration, 1),
         })
-
     except asyncio.CancelledError:
         _playback_status.update({
             "state": "idle", "file": None, "progress": 0, "elapsed": 0.0,
         })
-
     except Exception as exc:
         _playback_status.update({"state": "error", "error": str(exc), "progress": 0})
         print(f"[Playback] {exc}")

+ 11 - 1
bridge/bridge.py

@@ -57,6 +57,10 @@ DEFAULT_SPEAKERS: dict[str, str] = {
     "SPEAKER_03": "Choir",
 }
 
+# Shared queue for test audio injection from admin.py
+# Admin feeds decoded PCM float32 chunks here; bridge forwards to AudioProcessor
+test_audio_queue: asyncio.Queue[bytes] | None = None
+
 # ── Speaker persistence ───────────────────────────────────────────────────────
 
 def _load_speakers() -> dict[str, str]:
@@ -350,12 +354,18 @@ async def audio_processor_loop(state: BridgeState, mqtt_client: mqtt.Client, eng
                 state.push_final(text, speaker, mqtt_client)
 
     async def _send_audio():
+        global test_audio_queue
+        test_audio_queue = asyncio.Queue(maxsize=240)
         with sd.InputStream(
             device=device, samplerate=SAMPLE_RATE, channels=CHANNELS,
             dtype="float32", blocksize=BLOCKSIZE, callback=audio_callback,
         ):
             while True:
-                chunk = await audio_queue.get()
+                # Drain test audio injection first if available
+                try:
+                    chunk = test_audio_queue.get_nowait()
+                except asyncio.QueueEmpty:
+                    chunk = await audio_queue.get()
                 await audio_processor.process_audio(chunk)
 
     flusher  = asyncio.create_task(_flusher(state, mqtt_client))