Skip to content

AvatarSession.aclose() doesn't unbind the audio output start() installed, so a failed avatar start silently mutes the agent #7276

Description

@joearasin

Bug Description

AvatarSession.start() points the agent session's audio output at the avatar's datastream. AvatarSession.aclose() never puts it back. That asymmetry is invisible on the happy path, but if the avatar fails to start, the agent is then silent (and doesn't degrade to just audio).

Expected Behavior

AvatarSession.aclose() sets audio output back to what it was before.

Reproduction Steps

import asyncio
from livekit import rtc
from livekit.agents.voice import AgentSession
from livekit.agents.voice.avatar import AvatarSession, DataStreamAudioOutput


class FakeAvatarSession(AvatarSession):
    """Mimics what an avatar plugin's start() does."""

    @property
    def avatar_identity(self) -> str:
        return "avatar-worker"

    async def start(self, agent_session, room):
        await super().start(agent_session, room)
        agent_session.output.replace_audio_tail(
            DataStreamAudioOutput(room=room, destination_identity=self.avatar_identity)
        )


async def main():
    session = AgentSession()
    room = rtc.Room()
    print("before start:       ", session.output.audio)

    avatar = FakeAvatarSession()
    await avatar.start(session, room=room)
    print("after plugin start: ", type(session.output.audio).__name__)

    # the avatar never joins: wait_for_join(timeout=...) raises, the app gives up
    await avatar.aclose()
    print("after aclose:       ", type(session.output.audio).__name__)


asyncio.run(main())


Output:


before start:        None
after plugin start:  DataStreamAudioOutput
after aclose:        DataStreamAudioOutput

Operating System

All

Models Used

No response

Package Versions

livekit-agents==1.8.0

Session/Room/Call IDs

No response

Proposed Solution

Have AvatarSession remember what it replaced in start() and restore it in aclose() — symmetric with how it already unregisters its own event handlers and cancels its own join task. (Or provide a parameter to close to do this)

Additional Context

No response

Screenshots and Recordings

No response

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions