mammoth-branch-90408
05/20/2026, 7:56 AMtall-airline-16756
05/20/2026, 7:56 AMtall-airline-16756
05/20/2026, 7:57 AMuse_tts_aligned_transcript=True on the AgentSession) so you receive per-word TimedString objects with start_time and end_time (seconds) for the agent’s utterance.
1. Ensure timestamps align to audio:
◦ Use sync_transcription=True in TextOutputOptions so transcript timing is aligned to audio playout.
1. Track playback on the client:
◦ Play the agent audio in a regular HTMLMediaElement or Web Audio API buffer and use its currentTime (or an AudioContext clock) to know how many seconds of audio have played.
◦ Map currentTime to the transcript timestamps: highlight the word where start_time <= currentTime <= end_time.
1. Use playback start/stop events for robustness:
◦ When audio starts, note the client playback start time (Date.now() or AudioContext.currentTime) and use that as the timebase so you can compute current playback position if the media element’s currentTime is insufficient.
◦ Listen for `ended`/`pause` or LiveKit agent events (agent_state_changed to `speaking`/`listening`) or playback_finished hooks to stop highlighting or handle interruptions.
Notes and tips
• If audio can be interrupted or resumed, keep a single timebase (e.g., cumulative played seconds) or adjust the mapping on seek/resume so timestamps remain accurate.
• If you need sub-word precision, ensure your TTS provider supplies sufficiently fine-grained timestamps (Cartesia, ElevenLabs, and LiveKit Inference support aligned timestamps).
• If you want the UI to be resilient to network jitter, prefer the client audio clock (Web Audio API) as the authoritative source and treat transcript timestamps as the mapping reference.
If you’d like, tell me which client platform you’re using (web with HTMLAudio/Web Audio, React Native, or native mobile) and I’ll give concise, platform-specific code samples to wire up currentTime → word highlighting.
Sources: Text and transcriptions | LiveKit Documentation | Agent session | LiveKit Documentation | How to detect when an agent has finished speaking, with interactive elementsmammoth-branch-90408
05/20/2026, 8:02 AMtall-airline-16756
05/20/2026, 8:02 AMuse_tts_aligned_transcript=True and sync_transcription=True on the AgentSession/TextOutputOptions) and keep the full response text in the UI while highlighting words as audio plays.
Recommended approach (React Native)
1. Receive the response:
◦ Get the full response text plus per-word timestamps as TimedString objects (start_time / end_time in seconds).
1. Play audio and track playback time:
◦ Use a React Native audio player that exposes playback position:
▪︎ Example libraries: expo-av (Audio.Sound, getStatusAsync().positionMillis) or react-native-video (onProgress with currentTime).
◦ Start playback and poll or subscribe to the player’s time updates (onProgress or setInterval reading positionMillis) to get current playback time in seconds.
1. Map playback time → highlight:
◦ Keep the words and their timestamps in an array [{text, start_time, end_time}, ...].
◦ On each time update compute currentTime = playerPositionSeconds and find the active word: word.start_time <= currentTime && currentTime <= word.end_time.
◦ Update UI to highlight that word; render full text but style the active word differently.
1. Handle edge cases:
◦ On pause/seek/interruption: read the player’s currentTime and recompute active word.
◦ If audio starts slightly delayed vs timestamp base, record playbackStartClock (Date.now()) when you call play and use either player.currentTime or (Date.now()-playbackStartClock) to compute position; prefer player’s reported position when available.
◦ If the agent speech can be interrupted, listen for agent playback events (playback_finished or agent_state_changed) to clear highlighting.
Minimal code sketch (conceptual)
• Use expo-av example flow:
// load audio
const sound = new Audio.Sound();
await sound.loadAsync({ uri: audioUrl });
// start playback
await sound.playAsync();
// poll position
const interval = setInterval(async () => {
const status = await sound.getStatusAsync();
const currentTime = status.positionMillis / 1000;
// find active word by timestamps and set state for UI highlight
}, 50);
• Render full response text as words (split by tokens) and apply highlight style to the active index from state.
If you want, I can provide:
• A complete React Native + expo-av code example that converts LiveKit TimedString objects into highlighted text,
• Or a react-native-video version with onProgress usage.
Which one would you like?
, with interactive elementsmammoth-branch-90408
05/20/2026, 8:03 AMtall-airline-16756
05/20/2026, 8:03 AMuse_tts_aligned_transcript=True and sync_transcription=True so you receive TimedString objects with `start_time`/`end_time` for the whole utterance.
1. Detect when agent audio starts in the call:
◦ Use LiveKit’s agent playback events (agent_state_changed to speaking or playback_finished) or detect the remote audio track becoming audible on the client. When audio becomes audible, record a playback start time (see options below).
1. Use the client audio clock as authoritative:
◦ In the live call, use the actual audio playback position reported by your RN audio player (preferred) or compute elapsed time from the recorded playback start time (fallback).
◦ Map playback time (seconds) to the word timestamps and highlight the word where start_time <= playbackTime <= end_time.
1. Handle interruptions/seeks:
◦ On pause/interrupt/resume or when agent playback ends, read the player position and recompute the active word; clear highlights when finished.
Client-side options (React Native)
• If you use a player that exposes position updates:
◦ expo-av: Audio.Sound.getStatusAsync().positionMillis polled via interval or setOnPlaybackStatusUpdate.
◦ react-native-track-player: TrackPlayer.getPosition() or progress events.
◦ react-native-video: onProgress with currentTime.
• If you can’t get a reliable position, record Date.now() when the remote audio becomes audible and compute elapsed = (Date.now() - startTimestamp)/1000.
Timing tips
• Prefer the player’s reported currentTime or AudioContext clock for accuracy.
• Use small polling interval (e.g., 30–100ms) or the player’s callback to update highlight.
• Use the transcript timestamps only as the mapping reference; rely on the audio clock for real playback timing.
• If audio start has non-zero latency, align by recording the exact moment the user hears audio (or use the player’s first-play event).
Next step Which audio playback component are you using in React Native (expo-av, react-native-track-player, react-native-video, or something else)? I’ll provide a concise, runnable example for that library showing how to load remote agent audio, poll position, and highlight words using the TimedString timestamps.
, with interactive elements