livekit-plugins-facemode
FaceMode avatar output for LiveKit Agents Python applications.
Install
pip install livekit-plugins-facemode
From this repository:
pip install .
Requires Python 3.13 or later, LiveKit 1.x, and LiveKit Agents 1.7 or later.
Usage
The host application supplies a server-side LiveKit room object. The room token must grant the FaceMode worker permission to join, publish, and subscribe in the customer room. Keep the token on the server and never log it or expose it to a browser client.
import os
from livekit.agents import Agent, AgentSession, room_io
from livekit_plugins_facemode import AvatarSession
avatar = AvatarSession(
api_key=os.environ["FACEMODE_API_KEY"],
avatar_id=os.environ.get("FACEMODE_AVATAR_ID", ""),
)
await ctx.connect()
await avatar.start(
agent_session,
ctx.room,
room={
"type": "livekit",
"url": os.environ["LIVEKIT_URL"],
"token": os.environ["LIVEKIT_TOKEN"],
},
)
await agent_session.start(
agent=Agent(instructions="You are a helpful assistant."),
room=ctx.room,
room_options=room_io.RoomOptions(audio_output=False),
)
await avatar.wait_for_join()
AvatarSession.start() creates a FaceMode session with the room object. The create response normally returns ready: true with the ingestion url and a one-time wsToken (about 15 minute expiry), so no polling happens in the common path. If worker assignment is still pending, the plugin polls the session endpoint with bounded backoff for up to 240 seconds and stops immediately on FAILED/ENDED worker states. The initial response's room credentials remain in memory and are not expected in the polling response.
The ingestion WebSocket handshake uses the Sec-WebSocket-Protocol subprotocol facemode.<wsToken> with a 240 second open timeout. When the backend returns optional ingestion.headers, the plugin forwards them during the handshake. It disables compression and native WebSocket keepalives in favor of the canonical application ping/pong messages after negotiation.
Pass input_provider (one of deepgram, gemini, gnani, elevenlabs, openai, cartesia, sarvam, custom) to AvatarSession when the session should pin a specific upstream input provider; it is omitted from the request otherwise.
If the WebSocket transport drops after the protocol has started, the plugin auto-reconnects in the background: it POSTs the session reconnect endpoint for a fresh one-time wsToken (a consumed token is never reused), opens a new socket with facemode.<newToken>, re-sends the canonical start message, and waits for started before resuming. Outgoing control seq numbers stay monotonic across the reconnect and buffered audio is not replayed. Reconnect is bounded to 2 attempts with backoff and is single-flight; exhaustion surfaces a typed FaceModeNotReadyError/FaceModeAPIError. Intentional stop(), a canonical ended, fatal protocol errors, and drops before the first negotiation do not reconnect.
Every TTS frame is sent as canonical PCM audio. The plugin locks sample rate and channel count at protocol negotiation and rejects a format change or unaligned 16-bit PCM afterward. cancel_utterance is sent when LiveKit interrupts the audio output. Graceful close sends end_session and waits briefly for canonical ended; ended is a protocol acknowledgement, not backend cleanup confirmation.
Token grants
The room.token value must allow the worker to join the customer room and
publish its avatar audio/video tracks. If the token uses a fixed participant
identity, use avatar_participant_identity and make the room policy allow that
identity. The worker does not create or replace the customer LiveKit room.
API URL
The default API URL is https://api.facemode.io/api. Set api_url for a
self-hosted or local backend.
License
Apache-2.0 - see LICENSE. Part of the facemode-integrations monorepo.
Metadata
Release files for livekit-plugins-facemode 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| livekit_plugins_facemode-0.2.0.tar.gz | 24.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| livekit_plugins_facemode-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 43.9 kB
Release files / livekit_plugins_facemode-0.2.0.tar.gz
| Download URL | livekit_plugins_facemode-0.2.0.tar.gz |
|---|---|
| Size | 24.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
82c8b179e8b3f9ab95cf93f5c289a6405c37072eaafc4041f48260b44c1b86e5
|
|
BLAKE2b-256 checksum How to use checksums |
2e4dd9e708b2b8adc0d10da4d9f3d60a9c6bc6b6f6d8b1119b1bf04c2729207f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|
Release files / livekit_plugins_facemode-0.2.0-py3-none-any.whl
| Download URL | livekit_plugins_facemode-0.2.0-py3-none-any.whl |
|---|---|
| Size | 19.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bb969ed09187b3016d53adfcf1b91685391fb504e4369f358fef5cec8aef207e
|
|
BLAKE2b-256 checksum How to use checksums |
239c91358a1ae5b7e7bd5cd6d99cd036de715b9d36bf9e5b3d99277c0ff30b00
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|