fix: build PipeWire capture chain on demand instead of permanently
The null sink and its two loopbacks were loaded at startup and stayed loaded forever. While loaded they link the microphone and the speaker device into a single PipeWire driver group: the microphone drives the graph and the speaker device runs as a clock follower, so every playback stream pays for continuous cross-device resampling. Nothing needs the chain while idle — recording is triggered manually. Build it in toggle_recording() and drop it as soon as the audio is captured, before transcription runs for minutes. Module ids are now derived from pactl instead of tracked in a state file, so a crashed process cannot leave stale ids behind. The state file only holds the device selection. Startup tears down any leftover chain. Loopbacks get latency_msec=200; transcription is offline, and a small buffer would put these nodes on the graph's realtime deadline.
This commit is contained in:
+8
-1
@@ -5,6 +5,7 @@ import tempfile
|
||||
import traceback
|
||||
from datetime import datetime
|
||||
|
||||
import pipewire
|
||||
from api.state import state, Status
|
||||
from api.router import broadcast
|
||||
from config import load as load_config
|
||||
@@ -26,7 +27,13 @@ async def run_pipeline():
|
||||
diar_cfg = cfg.get("diarization", {})
|
||||
use_diarization = diar_cfg.get("enabled") and diar_cfg.get("hf_token")
|
||||
|
||||
recorder.stop()
|
||||
# Drop the capture chain as soon as the audio is captured — transcription
|
||||
# runs for minutes and must not keep the PipeWire clock domains coupled.
|
||||
try:
|
||||
recorder.stop()
|
||||
finally:
|
||||
pipewire.teardown()
|
||||
|
||||
await state.set_status(Status.PROCESSING)
|
||||
await broadcast({"event": "processing"})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user