Unexpected Audio Degradation After Enabling BVC Noise Cancellation in LiveKit Voice Agent

Hi LiveKit Team,

We are currently using BVC noise cancellation in our LiveKit voice agent, and we are noticing an unexpected issue with the audio quality after enabling noise cancellation.

To help explain the problem, I am attaching two recordings:

  1. Before noise cancellation enabled

  2. After noise cancellation enabled

The issue is that after applying BVC noise cancellation, the processed audio quality seems to degrade / behave unexpectedly compared to the original recording. We would like to understand:

  • Why this behavior is happening

  • Whether this is an expected limitation of BVC noise cancellation

  • If there are any recommended configuration changes or best practices to improve the output quality

  • Whether additional preprocessing/postprocessing settings are required on the LiveKit voice agent side

Our goal is to reduce background noise without affecting the speaker’s voice clarity, but currently the “after noise cancellation” recording sounds noticeably different.

Could you please help us understand what might be causing this?

Thanks in advance.

A few things come to mind:

  • Those recordings sound more like echo rather than noise, did you look at the client settings to disable echo cancellation?
  • I’m not sure where you are getting your audio from, but you might look at agent observability, Agent insights in LiveKit Cloud | LiveKit Documentation, to give you an indication of what the agent heard, rather than an end-to-end test.
  • Did you try different noise cancellation models such as NC or ai-coustics: Noise & echo cancellation | LiveKit Documentation ?
  • You should only apply noise cancellation once in the audio pathway, so make sure you disable any noise cancellation on the client or SIP trunk (I don’t believe the latter applies to you)

I would also add to what @darryncampbell said above. If these are SIP calls make sure you do not have noise cancelation enabled in both the trunk and the agent. You should only use one or the other. In your usecase I think it is best to use the agent noise cancelation.

1 Like

The first audio file, with a duration of 3:12, is the original recording received from Egress before being sent to the agent, meaning it is without any noise cancellation applied.

The second audio file, with a duration of 1:05, was downloaded from the agent observability screen. After reviewing the code, I confirmed that Krisp Noise Cancellation is currently enabled(noise_cancellation.NC()), and I also noticed that you have introduced the ai-coustics option.

What would you suggest here? Do you think this setup is suitable for our voice agent use case?

Also, regarding QUAIL_VF_L:

Voice Focus variant that elevates the foreground speaker while suppressing interfering speech and background noise.
It offers higher quality for agent use cases, but comes with additional cost.

Could you please let me know where we can check the pricing/cost details for this model?

Thanks,
Rajan

Apart from this, I also tried the new ai_coustics noise cancellation option from the LiveKit documentation using the following setup:

await session.start(
    agent=agent,
    room=ctx.room,
    room_options=room_io.RoomOptions(
        audio_input=room_io.AudioInputOptions(
            noise_cancellation=lambda params: noise_cancellation.BVCTelephony()
            if (
                params.participant.kind
                == rtc.ParticipantKind.PARTICIPANT_KIND_SIP
                or merged_data.get("kind") == "phone_call"
            )
            else ai_coustics.audio_enhancement(
                model=ai_coustics.EnhancerModel.QUAIL_VF_L
            )
        ),
        text_input=room_io.TextInputOptions(
            text_input_cb=make_text_input_cb(agent)
        ),
        # Keep room open after warm transfer so caller and supervisor can continue
        delete_room_on_close=False,
    ),
)

However, when I run the agent, I get the following error:

2026-04-06 11:27:26,735 - livekit.plugins.ai_coustics - ERROR - Missing configuration
2026-04-06 11:27:26,735 - livekit.plugins.ai_coustics - ERROR - Missing configuration

I could not find any additional setup details in the LiveKit documentation beyond what I have already followed.

Could you please let me know what configuration I might be missing here?

Could you please let me know where we can check the pricing/cost details for this model?

This is listed on the pricing page under speaker isolation: Pricing | LiveKit (only applies to the VF model)

2026-04-06 11:27:26,735 - livekit.plugins.ai_coustics - ERROR - Missing configuration
2026-04-06 11:27:26,735 - livekit.plugins.ai_coustics - ERROR - Missing configuration

I thought this might be because you had not specified model_parameters, but I can’t reproduce this error. In addition to our docs, I find this video on the subject is also very good: https://www.youtube.com/watch?v=5KGo5R7En9Y

Thanks for the guidance.

I also tried AI Coustics enhancement with explicit model_parameters as suggested in the video, but I’m still seeing the same “Missing configuration” error from the plugin.

Current setup

await session.start(
    agent=agent,
    room=ctx.room,
    room_options=room_io.RoomOptions(
        audio_input=room_io.AudioInputOptions(
            noise_cancellation=lambda params: ai_coustics.audio_enhancement(
                model=ai_coustics.EnhancerModel.QUAIL_VF_L,
                model_parameters=ai_coustics.ModelParameters(
                    enhancement_level=0.8
                ),
            )
        ),
        text_input=room_io.TextInputOptions(
            text_input_cb=make_text_input_cb(agent)
        ),
        delete_room_on_close=False,
    ),
)

Error

2026-04-07 19:07:44,311 - livekit.plugins.ai_coustics - ERROR - Missing configuration

Even after explicitly passing the model and model_parameters, the plugin still reports the same issue.

I wanted to confirm whether this plugin requires any additional LiveKit Cloud-side enablement, API key, environment variable, or account-level configuration, apart from passing the model and model_parameters.

Would appreciate any clarification on what exact configuration is considered missing here.

You should not need anything special. You are using the Voice isolation feature there, Pricing | LiveKit , but you get included minutes on the Build plan (and that error sounds like something else)

Let me share the basic sample which is based on GitHub - livekit-examples/agent-starter-python: A complete voice AI starter for LiveKit Agents with Python. · GitHub , this is what I created yesterday when I said I couldn’t reproduce the error:

import logging

from dotenv import load_dotenv
from livekit import rtc
from livekit.agents import (
    Agent,
    AgentServer,
    AgentSession,
    JobContext,
    JobProcess,
    cli,
    inference,
    room_io,
)
from livekit.plugins import noise_cancellation, silero
from livekit.plugins.turn_detector.multilingual import MultilingualModel
from livekit.plugins import ai_coustics

logger = logging.getLogger("agent")

load_dotenv(".env.local")


class Assistant(Agent):
    def __init__(self) -> None:
        super().__init__(
            instructions="""You are a helpful voice AI assistant. The user is interacting with you via voice, even if you perceive the conversation as text.
            You eagerly assist users with their questions by providing information from your extensive knowledge.
            Your responses are concise, to the point, and without any complex formatting or punctuation including emojis, asterisks, or other symbols.
            You are curious, friendly, and have a sense of humor.""",
        )

    # To add tools, use the @function_tool decorator.
    # Here's an example that adds a simple weather tool.
    # You also have to add `from livekit.agents import function_tool, RunContext` to the top of this file
    # @function_tool
    # async def lookup_weather(self, context: RunContext, location: str):
    #     """Use this tool to look up current weather information in the given location.
    #
    #     If the location is not supported by the weather service, the tool will indicate this. You must tell the user the location's weather is unavailable.
    #
    #     Args:
    #         location: The location to look up weather information for (e.g. city name)
    #     """
    #
    #     logger.info(f"Looking up weather for {location}")
    #
    #     return "sunny with a temperature of 70 degrees."


server = AgentServer()


@server.rtc_session(agent_name="my-agent")
async def my_agent(ctx: JobContext):
    # Logging setup
    # Add any other context you want in all log entries here
    ctx.log_context_fields = {
        "room": ctx.room.name,
    }

    # Set up a voice AI pipeline using OpenAI, Cartesia, Deepgram, and the LiveKit turn detector
    session = AgentSession(
        # Speech-to-text (STT) is your agent's ears, turning the user's speech into text that the LLM can understand
        # See all available models at https://docs.livekit.io/agents/models/stt/
        stt=inference.STT(model="deepgram/nova-3", language="multi"),
        # A Large Language Model (LLM) is your agent's brain, processing user input and generating a response
        # See all available models at https://docs.livekit.io/agents/models/llm/
        llm=inference.LLM(model="openai/gpt-4.1-mini"),
        # Text-to-speech (TTS) is your agent's voice, turning the LLM's text into speech that the user can hear
        # See all available models as well as voice selections at https://docs.livekit.io/agents/models/tts/
        tts=inference.TTS(
            model="cartesia/sonic-3", voice="9626c31c-bec5-4cca-baa8-f8ba9e84c8bc"
        ),
        # VAD and turn detection are used to determine when the user is speaking and when the agent should respond
        # See more at https://docs.livekit.io/agents/build/turns
        turn_detection=MultilingualModel(),
        vad=ai_coustics.VAD(),
        # allow the LLM to generate a response while waiting for the end of turn
        # See more at https://docs.livekit.io/agents/build/audio/#preemptive-generation
        preemptive_generation=True,
    )

    # To use a realtime model instead of a voice pipeline, use the following session setup instead.
    # (Note: This is for the OpenAI Realtime API. For other providers, see https://docs.livekit.io/agents/models/realtime/))
    # 1. Install livekit-agents[openai]
    # 2. Set OPENAI_API_KEY in .env.local
    # 3. Add `from livekit.plugins import openai` to the top of this file
    # 4. Use the following session setup instead of the version above
    # session = AgentSession(
    #     llm=openai.realtime.RealtimeModel(voice="marin")
    # )

    # # Add a virtual avatar to the session, if desired
    # # For other providers, see https://docs.livekit.io/agents/models/avatar/
    # avatar = hedra.AvatarSession(
    #   avatar_id="...",  # See https://docs.livekit.io/agents/models/avatar/plugins/hedra
    # )
    # # Start the avatar and wait for it to join
    # await avatar.start(session, room=ctx.room)

    # Start the session, which initializes the voice pipeline and warms up the models
    await session.start(
        agent=Assistant(),
        room=ctx.room,
        room_options=room_io.RoomOptions(
            audio_input=room_io.AudioInputOptions(
                noise_cancellation=ai_coustics.audio_enhancement(model=ai_coustics.EnhancerModel.QUAIL_VF_L),
            ),
        ),
    )

    # Join the room and connect to the user
    await ctx.connect()


if __name__ == "__main__":
    cli.run_app(server)