delightful-hamburger-90968
12/20/2025, 9:54 PMtall-airline-16756
12/20/2025, 9:54 PMtall-airline-16756
12/20/2025, 9:55 PMaudio_enabled=False in RoomOutputOptions). If audio is disabled the agent will respond in text only.
• Ensure TTS is configured for the session or that you explicitly call session.say() to produce audio.
2) Verify the agent actually published an audio track
• Check agent logs / traces for a TTS node run and confirm it published an output track to the room.
• Use Agent Observability (Agent Insights / Trace) to confirm TTS audio was generated and published.
3) Make sure the frontend subscribes and renders the audio track
• Add the automatic renderer: include <RoomAudioRenderer/> (or roomaudiorenderer in your frontend) so room audio is played.
• If using hooks, get the agent audio audioTrack (e.g., from useVoiceAssistant) and attach it to an <audio> element or visualizer so it actually plays.
4) Test full WebRTC flow (console vs cloud)
• Console mode doesn’t exercise WebRTC publishing/subscription. Reproduce the issue with a frontend connected to LiveKit Cloud to validate publishing/subscription and playback.
5) Check for client-side audio issues
• Ensure the browser has audio unmuted and permission to play media.
• Confirm no other audio source or background audio player is overriding/muting the agent audio.
6) If you still see TTS generated but no playback, collect these diagnostics
• Agent Observability trace showing the TTS node and publish event.
• Frontend: whether an audio track is present on remote participant(s) and whether your renderer logs show subscription.
• Browser console logs and any errors about autoplay, media, or WebRTC.
If you want, share:
• A short snippet of how you start the session (agent TTS config / session.start / session.say calls)
• What frontend rendering you use (RoomAudioRenderer, custom <audio>, or hook)
I’ll point out exactly what to change based on those snippets.
Sources: How to Set Up Speech-to-Text Input with Text-Only Output in LiveKit Agents | OpenAI and LiveKit partner to turn Advanced Voice into an API | Playing Audio | LiveKit docs | https://blog.livekit.io/streamline-troubleshooting-with-agent-observability/#/portal/signup| | Agent speech and audio | LiveKit docsdelightful-hamburger-90968
12/20/2025, 9:58 PMFailed to fetch token: ${response.statusText});
}
const data = await response.json();
if (!data.success) {
throw new Error(data.error || "Failed to get token");
}
console.log("✅ Token received");
console.log("📍 LiveKit URL:", data.url);
console.log("🏠 Room:", data.room);
console.log("👤 User:", data.user);
// Connect to LiveKit
status.innerText = "Connecting...";
room = new Room({ adaptiveStream: true, dynacast: true });
await room.connect(data.url, data.token, { autoSubscribe: true });
status.innerText = "Connected";
console.log("✅ Connected to room");
// Hide Join button, show Disconnect button
toggleButtons(true);
await room.localParticipant.setMicrophoneEnabled(true);
console.log("🎤 Mic enabled");
room.on(RoomEvent.TrackSubscribed, (track, pub, participant) => {
attachAudioTrack(track, participant);
});
// Handle disconnection events
room.on(RoomEvent.Disconnected, () => {
status.innerText = "Disconnected";
console.log("❌ Disconnected from room");
toggleButtons(false);
stopAudioDetection();
});
} catch (e) {
console.error(e);
status.innerText = "Connection failed";
}
};
document.getElementById("disconnectBtn").onclick = async () => {
const status = document.getElementById("status");
if (room) {
status.innerText = "Disconnecting...";
console.log("🔌 Disconnecting from room");
await room.disconnect();
status.innerText = "Disconnected";
console.log("✅ Disconnected successfully");
// Show Join button, hide Disconnect button
toggleButtons(false);
// Stop audio detection
stopAudioDetection();
room = null;
}
};tall-airline-16756
12/20/2025, 9:58 PM# await ctx.connect(
# # url=LIVEKIT_URL,
# # api_key=LIVEKIT_API_KEY,
# # api_secret=LIVEKIT_API_SECRET,
# )
• Fix: call it with your env vars:
await ctx.connect(
url=LIVEKIT_URL,
api_key=LIVEKIT_API_KEY,
api_secret=LIVEKIT_API_SECRET,
)
Reason: the worker must connect to LiveKit to be dispatched to rooms and publish audio.
2) Confirm RoomIO and audio output after session.start
• Right after await session.start(...) ensure these printouts show audio attached:
print("RoomIO created:", session._room_io is not None) # should be True
print("Audio output attached:", session.output.audio is not None) # should be True
If audio is None, TTS or session init failed.
3) Ensure TTS is actually emitted
• Either explicitly call await session.say("...") to force TTS during testing, or confirm your agent logic emits speech events and the session has tts=DeepgramTTS(...) (you already do). Confirm a TTS node appears in Agent Observability / traces.
4) Frontend subscription & rendering checks (your JS is mostly correct)
• Add participant and track logs to confirm agent joined and published:
room.on(RoomEvent.ParticipantConnected, p => console.log("Participant:", p.identity));
room.on(RoomEvent.TrackSubscribed, (track, pub, participant) => {
console.log("TrackSubscribed:", { kind: track.kind, source: pub.source, participant: participant.identity });
});
• Your attachAudioTrack creating an <audio> element is fine. Confirm the console shows an agent participant and an audio track from that participant.
5) Browser autoplay / audio permissions
• Ensure microphone/camera permissions, that tab is not muted, and no autoplay policy blocks audio. You set autoplay and playsInline correctly.
6) Useful diagnostics to collect if still silent
• Backend: output of the prints from step (2) and any speech_created / track_published logs from your session handlers.
• Frontend: console logs from the added Participant & TrackSubscribed listeners and any autoplay/media errors.
If you want, paste:
• the console output after uncommenting ctx.connect() and starting the agent
• the frontend console logs for ParticipantConnected and TrackSubscribed
I’ll review those and point out the exact next step.delightful-hamburger-90968
12/20/2025, 10:05 PMtall-airline-16756
12/20/2025, 10:05 PMctx.connect(), but JobContext.connect() does not accept url, api_key, or api_secret. The JobContext already contains the connection details when the job is dispatched, so calling ctx.connect() with those keywords raises the error you saw.
What to do:
1. Replace your call with a no-arg (or only optional) call:
await ctx.connect()
or include only supported options such as `auto_subscribe`:
from livekit.agents import AutoSubscribe
await ctx.connect(auto_subscribe=AutoSubscribe.AUDIO_ONLY)
1. Keep credentials in your environment (you already have env vars). Do not pass them into ctx.connect().
2. If you need to run the agent locally outside of dispatch (for testing), run the worker/CLI so the JobContext is created correctly (agents.cli.run_app) — then use await ctx.connect() as above.
If you want, paste your updated entrypoint and I’ll confirm it or suggest the exact auto_subscribe setting to use.
Sources: Job lifecycle | LiveKit docs | OpenAI and LiveKit partner to turn Advanced Voice into an API | Agent server options | LiveKit docs | An open source stack for real-time multimodal AI