BVCTelephony: AudioStream.from_track blocks the job event loop for ~260 ms at session start, and the filter cannot be prewarmed
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 5/5
- Tempo stimato
- Più di una settimana
- Idoneità per principianti
- 20/100
- Tipo di issue
- Bug
- Chiarezza
- Abbastanza chiara
- Stato di attività
- Attiva
- Ambito
- audio-video-rtc, performance
Direzione di ricerca
Start with the linked livekit-ffi/src/room_apis/server/audio_stream.rs lines 64-70 and 119-137, then follow the Python path through voice/room_io/_input.py:422, rtc/audio_stream.py:268 and rtc/_ffi_client.py:307. Reproduce the event_loop_blocked span on a SIP call and confirm the native new_session() call runs on the caller thread. Done means NewAudioStream no longer blocks the job loop, or a supported preload API lets the model load in setup_fnc, with the monitor no longer reporting the block.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Bug Description
This is a follow-up to #7441. It adds production data for BVCTelephony(), shows where the time goes in livekit-ffi, and describes a second problem: there is no way to prewarm the filter.
In a production telephony voice agent (SIP participant, RoomInputOptions(noise_cancellation=noise_cancellation.BVCTelephony())), the built-in loop monitor reports event_loop_blocked during AgentSession.start() in about 98% of calls:
| metric (7 days, 1,593 spans) | p50 | p95 |
|---|---|---|
| wall time | 263 ms | 342 ms |
lk.blocking.cpu_time |
224 ms | – |
The loop thread is busy in native code (CPU time is close to wall time). The block is 2–3 times longer than the 106–119 ms that #7441 reports for BVC() on a different machine.
Sampled stack (same in almost all spans):
voice/room_io/room_io.py:384 _init_task
voice/room_io/_input.py:422 _create_stream
rtc/audio_stream.py:268 _create_owned_stream
rtc/_ffi_client.py:307 request
The NewAudioStreamRequest carries audio_filter_options with the BVC telephony model path (inb.bvc.hs.c6.w.s.23cdb3.kef, about 28 MB).
Where the time goes. In livekit-ffi, FfiAudioStream::from_track calls the audio filter plugin's new_session() (plugin create / create_v2) synchronously inside the request handler, before it spawns the stream task:
https://github.com/livekit/rust-sdks/blob/71219b95e402b720b5c2682496c50b6cc80b0888/livekit-ffi/src/room_apis/server/audio_stream.rs#L119-L137
Because NewAudioStream is a synchronous FFI request, this runs on the thread that calls livekit_ffi_request. In an agent job, that is the job's asyncio event loop thread. The application cannot move this call off the loop.
Prewarm is not possible. We tried to create the filter or the stream in setup_fnc (prewarm), so the model loads before the job starts. This fails:
from livekit import rtc
from livekit.plugins import noise_cancellation
src = rtc.AudioSource(48000, 1)
track = rtc.LocalAudioTrack.create_audio_track("probe", src)
rtc.AudioStream.from_track(
track=track, sample_rate=48000, num_channels=1,
noise_cancellation=noise_cancellation.BVCTelephony(),
)
# -> InvalidRequest("this track has no room information")
The FFI requires a track with a room handle before it creates the filter session (same file, L64-L70). Thus the model can only load inside a live job, on the event loop.
We do not know if the native plugin caches the model per process. In our setup each job runs in its own process, so a per-process cache alone does not help unless the model can be loaded in setup_fnc.
Expected Behavior
- Audio stream creation with noise cancellation does not block the job event loop for hundreds of milliseconds.
- There is a supported way to load the noise cancellation model before the job starts (for example in
setup_fnc).
Reproduction Steps
from livekit.agents import Agent, AgentSession, JobContext, RoomInputOptions
from livekit.plugins import noise_cancellation
async def entrypoint(ctx: JobContext):
await ctx.connect()
session = AgentSession(...) # any STT/LLM/TTS or realtime model
await session.start(
room=ctx.room,
agent=Agent(instructions="..."),
room_input_options=RoomInputOptions(
noise_cancellation=noise_cancellation.BVCTelephony(),
),
)
- Run the worker with the process job executor (forkserver) on a Linux x86_64 container with 2 vCPU.
- Join the room as a SIP participant (an inbound call).
- Read the
event_loop_blockedwarnings and spans. The block starts when RoomIO creates the audio stream for the SIP track.
#7441 reports that the same stream creation without noise cancellation does not trip the monitor.
Operating System
Linux x86_64 (container, 2 vCPU)
Models Used
Not relevant. The block happens before any model is used.
Package Versions
python==3.11
livekit-agents==1.8.9
livekit==1.1.21
livekit-plugins-noise-cancellation==0.3.2
I checked livekit 1.2.0 and the current main of agents, python-sdks and rust-sdks. The code path is unchanged.
Session/Room/Call IDs
No response
Proposed Solution
Any one of these removes the block from the call path:
- Create the filter session off the caller's thread. In livekit-ffi, call
new_session()inside the spawned stream task (or on a blocking thread) and pass frames through until the session is ready. This is the same pattern as the fix for the Krisp VIVA filter in #7924. Alternatively, makeNewAudioStreaman async FFI request with a callback, soAudioStreamcan await it. - Add a preload or prewarm API for the noise cancellation plugin, for example
noise_cancellation.preload(BVCTelephony()), that loads the model in the process without a room. Agents can then call it insetup_fnc. - Cache the loaded model per process in the native plugin (if it does not do this already), together with option 2.
Impact: the block happens right before the first greeting. It delays the first audio of nearly every call by about 250 ms. It also stops all other coroutines of the job (STT/LLM connection setup, telemetry, timers) during that time.
Additional Context
Related:
- #7441: same stack with
BVC(), 106–119 ms, open without a reply. - #7924: Krisp VIVA filter built on the event loop on the first frame (200–800 ms); confirmed and fixed.
- livekit/rust-sdks#1163: audio filter
on_load()blocksFfiRoom::connectwith no timeout (another synchronous native filter call).
If you prefer one issue, feel free to close this one as a duplicate of #7441. The data here can move there.
- Lingua principale
- Python
- Stelle
- 14.6k
- Fork
- 3.9k
- Merge medio
- 2g 7h
- PR unite (30g)
- 228
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
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 74/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 21 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
livekit/agents#7647 · 1 commento ·
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 61 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
-
Support CPython 3.15 in livekit-local-inferenceForse già presa Una pull request collegata a questa issue è aperta o già unita. Aperta
Difficoltà 5/5 Più di una settimana Idoneità per principianti 32/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 4/5 1-2 giorni Idoneità per principianti 55/100
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di livekit/agents
Issue simili
-
enhancement help wanted
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
Git-Hospital/githealthcheck#61 ·
I maintainer di solito rispondono entro 1 giorno
-
changelog investigate
Difficoltà 2/5 1-3 ore Idoneità per principianti 67/100
ramnes/notion-sdk-py#433 ·
-
Partial method descriptors raise on class accessForse già presa @Gambit-Checkmate l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
I maintainer di solito rispondono entro 19 giorni
-
docs pkg:core
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 84/100
pydantic/pydantic-ai#11929 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
intake/intake-esm#789 ·