SpeakingRateStream blocks the event loop: per-frame Python STFT loop in `_stft` / `_spectral_flux`
I maintainer di solito rispondono entro 1 giorno
Valutazione
- Difficoltà
- 3/5
- Tempo stimato
- 1-2 giorni
- Idoneità per principianti
- 35/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Ferma
- Stack tecnologico
- python
- Ambito
- audio-video-rtc, performance
Direzione di ricerca
Locate SpeakingRateStream._stft and _spectral_flux, then trace audio draining through _main_task. Run the existing speaking-rate tests and event-loop timing checks, comparing spectral-flux output and loop-blocking measurements before and after the change. Done means the calculation is vectorized without changing results and queued TTS audio no longer causes the measured stalls.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
TranscriptSynchronizer always runs SpeakingRateDetector on the agent's TTS audio, on the job's event loop. SpeakingRateStream._stft computes the STFT one frame at a time in a Python loop (about 80 np.fft.rfft calls per 1 s window at 24 kHz), and _spectral_flux loops over the frames again. Because RoomIO's _ParticipantAudioOutput.capture_frame queues TTS audio without pacing, _main_task drains a whole lump of a reply (10 windows per second of audio) without yielding.
Measured on livekit-agents 1.8.2, numpy 2.5.2, Apple M3 (the code is unchanged in 1.8.8, 2.0.0b1 and main):
- 0.61 ms per window;
_main_taskdraining 20 s of queued 24 kHz audio holds the loop ~123 ms (2 s: 7.6 ms, 5 s: 26 ms, 10 s: 58 ms). - In a local test conversation driven by synthetic speech, with
LIVEKIT_AGENTS_LOOP_BLOCK_WARN_MS=50: 4-5 loop blocks of 59-131 ms per run, a few seconds into each agent turn. With the 200 ms output buffer, stalls that size can be audible, and on smaller cloud machines they'd be roughly twice as long.
The same computation vectorized gives a bit-identical result (480 random cases across 6 sample rates and 4 lengths) and is ~3.8x faster (0.16 ms per window; 20 s of queued audio holds the loop ~38 ms). It replaces _stft + _spectral_flux:
def _spectral_flux(
self, audio: np.ndarray[tuple[int], np.dtype[np.float32]], sample_rate: int
) -> float:
frame_length = int(sample_rate * 0.025) # 25ms
hop_length = frame_length // 2 # 50% overlap
num_frames = (len(audio) - frame_length) // hop_length + 1
if num_frames < 2:
return 0.0
window = np.hanning(frame_length)
scale_factor = 1.0 / np.sqrt(np.sum(window**2))
frames = np.lib.stride_tricks.sliding_window_view(audio, frame_length)[::hop_length]
magnitudes = np.abs(np.fft.rfft(frames * window, axis=1) * scale_factor)
return float(np.mean(np.sum(np.abs(np.diff(magnitudes, axis=0)), axis=1)))
It might also be worth yielding (await asyncio.sleep(0)) between windows in _main_task, so a long lump never holds the loop, whatever the per-window cost.
Happy to open a PR with this if it's useful.
- Lingua principale
- Python
- Stelle
- 14.6k
- Fork
- 3.9k
- Merge medio
- 3g 9h
- PR unite (30g)
- 159
Preparare l'ambiente
Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di livekit/agents
-
Gemini Live: agent stays "speaking" without audio outputForse già presa @Luke-salinero l’ha presa 3 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
I maintainer di solito rispondono entro 1 giorno
-
Assistant markup is stripped from chat history when expressive mode is offForse già presa @ShivamSharma43 l’ha presa 11 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
I maintainer di solito rispondono entro 1 giorno
-
docs: openai.LLM vs openai.responses.LLM for HTTP OpenAI-compat hostsForse di nuovo libera @AbarnaaSree l’ha presa 51 giorni fa e non c’è nessuna pull request aperta. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
livekit/agents#7022 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
krisp VIVA: native filter is built on the event loop on the first audio frame (200-800 ms block)Aperta
Difficoltà 4/5 3-5 giorni Idoneità per principianti 45/100
I maintainer di solito rispondono entro 1 giorno
-
SpeakingRateStream blocks event loop 100–200ms on TTS audio bursts (TranscriptSynchronizer)Forse già presa @ninglinLiu l’ha presa 1 giorno fa. Aperta
Difficoltà 4/5 3-5 giorni Idoneità per principianti 20/100
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di livekit/agents
Issue simili
-
good first issue tools
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
I maintainer di solito rispondono entro 1 giorno
-
bug deferred domain:ci P1
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
I maintainer di solito rispondono entro 1 giorno
-
get_page_thumbnail modifies cached page images, affecting later thumbnails and picture exportsAperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
docling-project/docling-mcp#147 ·
-
issue: A pipe model's Valves button ignores the Allow Chat Valves permissionForse già presa Una pull request collegata a questa issue è aperta o già unita. Apertabug confirmed issue
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
open-webui/open-webui#32771 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Scheduled Security Scan is failing on mainForse già presa @pkupt l’ha presa oggi. Apertasecurity-scan-failure
Difficoltà 1/5 1-3 ore Idoneità per principianti 74/100
semantica-agi/semantica#2045 ·
I maintainer di solito rispondono entro 2 giorni