Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

krisp VIVA: native filter is built on the event loop on the first audio frame (200-800 ms block)

Open
#7,924 1 comment 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
45/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
python

Research direction

Start with livekit/plugins/krisp_internal and livekit/rtc/audio_stream.py, then trace KrispVivaFilterFrameProcessor._process and the credential and stream info update paths. Confirm where native filter construction runs relative to the asyncio event loop, and compare its behavior before credentials arrive. Done means construction no longer blocks the loop and frames pass through unfiltered until the filter is ready.

Written by the indexing model from the issue text.

Description

Versions: livekit-agents 1.8.8, livekit-plugins-krisp 0.4.8, livekit-plugins-krisp-internal 0.2.0, Python 3.13, Linux (t3.small).

What happens

krisp.voice_isolation() (Cloud auth) returns a processor whose backend, krisp_internal.plugin.KrispVivaFilterFrameProcessor, constructs the native KrispVivaFilter inside _process on the first frame after _on_credentials_updated. Its docstring says this keeps the blocking init "on the audio thread, not on the room task". But _process is called from rtc.AudioStream's async iterator (livekit/rtc/audio_stream.py, frame = self._processor._process(frame)), so construction runs on the job's asyncio event loop.

The agents loop monitor reports it in nearly every session, right before the first reply:

event loop blocked for 830ms at ".../livekit/plugins/krisp_internal/_ffi.py", line 293, in _uniffi_rust_call_with_error

Across ~20 sessions it ranged from 205 to 830 ms, sometimes as two blocks in one session. Timing the native call directly: KrispVivaFilter(KrispVivaFilterSettings(...)) takes 114-250 ms on an M-series Mac and longer on a small cloud VM. With credentials and stream info set, the first process() afterwards takes ~0.1 ms, so construction is essentially the whole cost.

Expected

Filter construction off the event loop, with frames passed through unfiltered until it is ready. That is the processor's existing behaviour before credentials arrive.

Workaround we ship

We subclass the processor: when a frame needs a filter, _process starts one worker thread that constructs the native filter, returns the frame unfiltered, and adopts the finished filter on the next frame (on the loop thread, applying any stream info, credentials or level that changed during the build). After that, frames go through the unchanged _process. With this, the loop-monitor warning is gone, and the build (327-502 ms on staging) happens on the worker thread. Happy to share the code if useful.

Possible upstream fixes: construct the filter in a thread from _on_credentials_updated / _on_stream_info_updated, or have AudioStream call blocking processors via an executor.

Dominant language
Python
Stars
14.6k
Forks
3.9k
Avg merge
3d 18h
Merged PRs (30d)
193

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from livekit/agents

All issues in livekit/agents

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.