cuddly-cartoon-47334
12/27/2025, 10:52 PMtall-airline-16756
12/27/2025, 10:52 PMtall-airline-16756
12/27/2025, 10:52 PMegress_id. Store that ID for later use.
Example (Python):
info = await lkapi.egress.start_room_composite(RoomCompositeEgressRequest(room_name="my-room", layout="speaker-dark"))
print("Egress ID:", info.egress_id)
• Associate egress to the agent via metadata
◦ When creating an agent dispatch, include room or purpose metadata so the agent can correlate actions to that room.
◦ In the agent, use the dispatch/context (e.g., ctx.room.name) to match the egress started by the server to the agent’s work.
• List active egress sessions and filter by room
◦ Use the server SDK to list ongoing egress (e.g., list_egress(room_name="my-room")) and read each egress_id to find the session you need.
If you want, tell me:
• Which SDK/language you’re using (Python, JS, Go, etc.)
• Whether you start egress from your server or trigger it from the agent
I’ll provide exact code/snippets or the best pattern to pass/store the egress_id for your flow.
Sources: Python SDKs | livekit/livekit_composite | DeepWiki | server-sdk-js | livekit/livekit_composite | DeepWiki | Agent dispatch | LiveKit docs | Outbound Calling Script | LiveKit docscuddly-cartoon-47334
12/27/2025, 10:53 PMtall-airline-16756
12/27/2025, 10:54 PMcuddly-cartoon-47334
12/27/2025, 10:54 PMtall-airline-16756
12/27/2025, 10:54 PMfilepath when starting egress, that is the output file name — tell me if you need to retrieve the final generated name from EgressInfo after completion or list active egresses, and I’ll provide the exact snippet for your SDK.cuddly-cartoon-47334
12/27/2025, 10:54 PMtall-airline-16756
12/27/2025, 10:55 PMfilepath
• capture the returned egress_id
• poll/list the egress info to read the final output filepath/name
Adjust to your SDK client instance and error handling as needed.
# Example (Python) — requires LiveKit server SDK client with egress methods
from livekit.api import LiveKitAPI, RoomCompositeEgressRequest
import asyncio
import time
async def start_and_get_output_file(lkapi: LiveKitAPI, room_name: str):
# 1) Start room composite egress and capture egress_id
req = RoomCompositeEgressRequest(
room_name=room_name,
layout="speaker-dark",
# Specify the desired output filepath. This determines the file name.
# Example for local or cloud path depending on your egress sink:
filepath="recordings/my-room-{room_name}-{time}.mp4"
)
info = await lkapi.egress.start_room_composite(req)
egress_id = info.egress_id
print("Started egress_id:", egress_id)
# 2) Poll for completion (or you can use webhook/events instead)
while True:
# list_egress or get_egress depending on SDK; using list_egress filtered by room
egress_list = await lkapi.egress.list_egress(room_name=room_name)
target = next((e for e in egress_list if e.egress_id == egress_id), None)
if not target:
print("Egress not found yet; retrying...")
time.sleep(2)
continue
print("Egress status:", target.status) # e.g., STARTED, COMPLETED, FAILED
if target.status == "COMPLETED":
# The API response includes metadata about outputs. Check fields like `output` or `filepath`
# Print whichever field holds the final file path/name
print("Final output filepath:", getattr(target, "filepath", None) or getattr(target, "output", None))
return getattr(target, "filepath", None) or getattr(target, "output", None)
if target.status == "FAILED":
raise RuntimeError(f"Egress failed: {target.error}")
time.sleep(2)
# Usage example
async def main():
lkapi = LiveKitAPI() # initialize with your config/auth
filepath = await start_and_get_output_file(lkapi, "my-room")
print("Resolved output file:", filepath)
await lkapi.aclose()
asyncio.run(main())
Notes:
• If you explicitly set filepath when starting egress, that is the expected output name/location.
• You can also inspect the egress info returned by list_egress or get_egress for the final output filepath/name once status is COMPLETED.
• Using webhooks/events to receive the completion payload is more efficient than polling — the completion event typically contains the final output info.
Tell me if you want the same example in JavaScript, Go, or using REST/webhook handling.cuddly-cartoon-47334
12/27/2025, 10:57 PMtall-airline-16756
12/27/2025, 10:57 PMstop_egress. Short answer: no — but sometimes.
When you don't need to call stop_egress
• If the room ends (last participant leaves) or you delete the room, egress will automatically stop and finalize the output. Deleting the room at call end is a recommended pattern to avoid extra silence/extra audio in recordings.
When you should call stop_egress
• You want to end recording/streaming before the room ends.
• You only want to record specific segments in a long-running room.
• You need precise lifecycle control (manual pause/resume, immediate stop on an event).
If you want, tell me which SDK/language you use and your desired lifecycle (e.g., delete room on hangup vs. keep room open), and I’ll give the exact code example for stopping egress or for deleting the room to trigger automatic stop.
Sources: server-sdk-js | livekit/livekit_composite | DeepWikicuddly-cartoon-47334
12/27/2025, 10:59 PMtall-airline-16756
12/27/2025, 10:59 PMegress_ended webhook) — it contains the final file info.
Quick examples:
Python
info = await lkapi.egress.stop_egress(api.StopEgressRequest(egress_id="EGRESS_ID"))
if info.file_info:
print("File path:", info.file_info.location)
print("Download URL:", info.file_info.download_url)
Go
info, err := egressClient.StopEgress(ctx, &livekit.StopEgressRequest{EgressId: "EGRESS_ID"})
if err != nil { return err }
if info.FileInfo != nil {
fmt.Println("File path:", info.FileInfo.Location)
fmt.Println("Download URL:", info.FileInfo.DownloadUrl)
}
Notes:
• If you set filepath when starting egress, that is the expected output name.
• You can also receive the final EgressInfo via the egress_ended webhook instead of calling stop_egress. Sources: server-sdk-ruby | livekit/livekit_composite | DeepWiki | Python SDKs | livekit/livekit_composite | DeepWikicuddly-cartoon-47334
12/27/2025, 11:02 PMtall-airline-16756
12/27/2025, 11:02 PMstop_egress call.
Two reliable ways:
• Use the egress_ended webhook (recommended)
◦ LiveKit sends an egress_ended event when the egress finishes. The event payload contains the EgressInfo including file_info.location and file_info.download_url.
◦ Implement a webhook endpoint that receives that event and reads the final filename/path from file_info.
• Query the server SDK after completion
◦ Poll or call get_egress / list_egress filtered by room or egress_id. Once status is COMPLETED, read file_info.location (and download_url).
◦ This is useful if you cannot use webhooks, but webhooks are more efficient.
Example webhook handling (conceptual):
# On your webhook route receiving egress_ended payload
payload = request.json
egress_info = payload.get("egress_info") or payload.get("data") # depends on webhook format
file_info = egress_info.get("file_info")
if file_info:
print("Final file path:", file_info.get("location"))
print("Download URL:", file_info.get("download_url"))
If you want, tell me whether you prefer a webhook or SDK example and which SDK/language you use (Python, JS, Go, REST) and I’ll provide a concrete snippet.cuddly-cartoon-47334
12/27/2025, 11:02 PMtall-airline-16756
12/27/2025, 11:02 PMegress_ended event, verifies the request signature (optional but recommended), and extracts the final file info (file_info.location and file_info.download_url). This uses FastAPI and assumes LiveKit sends JSON with an event type and egress_info payload.
1) Install requirements:
• fastapi
• uvicorn
• python-dotenv (optional, for loading a secret)
2) Example:
# webhook_egress.py
from fastapi import FastAPI, Request, HTTPException
from pydantic import BaseModel
import hmac
import hashlib
import os
import json
app = FastAPI()
# Set LIVEKIT_WEBHOOK_SECRET in env if you want to verify signatures
WEBHOOK_SECRET = os.getenv("LIVEKIT_WEBHOOK_SECRET", None)
class EgressEndedPayload(BaseModel):
event: str
egress_info: dict | None = None
def verify_signature(body: bytes, signature: str, secret: str) -> bool:
# LiveKit webhook signature is HMAC-SHA256 of the raw body using the webhook secret.
expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)
@app.post("/webhook")
async def handle_webhook(request: Request):
body = await request.body()
# Optional signature header name; replace if your setup differs
signature = request.headers.get("x-livekit-signature", "")
if WEBHOOK_SECRET:
if not signature:
raise HTTPException(status_code=400, detail="Missing signature")
if not verify_signature(body, signature, WEBHOOK_SECRET):
raise HTTPException(status_code=401, detail="Invalid signature")
try:
payload = json.loads(body)
except json.JSONDecodeError:
raise HTTPException(status_code=400, detail="Invalid JSON")
event_type = payload.get("event") or payload.get("type") # depends on your LiveKit setup
if event_type not in ("egress_ended", "EGRESS_ENDED"):
return {"status": "ignored", "event": event_type}
# Egress info may be under `egress_info` or `data.egress_info` depending on your webhook format
egress_info = payload.get("egress_info") or payload.get("data", {}).get("egress_info")
if not egress_info:
return {"status": "no_egress_info"}
# Extract file info
file_info = egress_info.get("file_info") or egress_info.get("FileInfo")
if not file_info:
return {"status": "no_file_info"}
location = file_info.get("location") or file_info.get("Location")
download_url = file_info.get("download_url") or file_info.get("DownloadUrl")
# Do something with the filename/path (store in DB, notify user, start post-processing, etc.)
print("Egress completed. File location:", location)
print("Download URL:", download_url)
return {"status": "ok", "location": location}
# Run with: uvicorn webhook_egress:app --reload --port 8000
Notes:
• If you set filepath when starting egress, the file_info.location will normally contain that path. For cloud sinks you may get an S3/GCS URI; for local sinks it may be a filesystem path.
• Confirm your LiveKit webhook payload shape — adjust keys (event, egress_info, data) accordingly.
• Use the webhook secret and signature verification in production for security.