steep-balloon-41261
05/08/2025, 3:03 PMtall-airline-16756
05/08/2025, 3:03 PMtall-airline-16756
05/08/2025, 3:03 PMOnTokenRefresh
callback function.
• For reconnection, LiveKit attempts to automatically resume the connection by reconnecting to the signaling WebSocket and initiating an ICE restart for the WebRTC connection. If this fails, a full reconnection is executed.
In your code, you can use the fetchToken
function to retrieve a new token and set it for reconnection. Ensure that the onDisconnected
handler fetches a new token and triggers the reconnection process. Let me know if you need further assistance!
Sources: Authentication | LiveKit Docs | lksdk package - github.com/livekit/server-sdk-go/v2 - Go Packages | Connecting to LiveKit | LiveKit Docs | DefaultReconnectPolicy | LiveKit JS Client SDK - v2.8.1tall-airline-16756
05/08/2025, 3:05 PMimport { useState, useEffect, useRef } from 'react';
import {
LiveKitRoom,
RoomAudioRenderer,
useConnectionState
} from '@livekit/components-react';
import '@livekit/components-styles';
import SimpleVoiceAssistant from './SimpleVoiceAssistant';
import "./LiveKitModal.css";
// Persistent storage outside component
let persistentToken = null;
let persistentRoom = null;
let isFirstConnection = true; // Track first connection globally
const LiveKitModal = ({ onClose, question, onRoomReady = () => {} }) => {
const [showAssistant, setShowAssistant] = useState(false);
const [connectionError, setConnectionError] = useState(null);
const [token, setToken] = useState(persistentToken);
const [shouldConnect, setShouldConnect] = useState(false);
const [agentReady, setAgentReady] = useState(false); // Added for initial delay
const roomRef = useRef(persistentRoom);
const fetchToken = async () => {
try {
const response = await fetch('<http://localhost:8000/api/livekit-token>');
if (!response.ok) throw new Error('Failed to get LiveKit token');
const data = await response.json();
persistentToken = data.token;
setToken(data.token);
return data.token;
} catch (err) {
console.error("Error fetching token:", err);
setConnectionError("Failed to connect to voice service. Please try again.");
throw err;
}
};
const handleConnected = (room) => {
persistentRoom = room;
roomRef.current = room;
onRoomReady(room);
setConnectionError(null);
if (isFirstConnection) {
setTimeout(() => {
setAgentReady(true);
isFirstConnection = false;
}, 6000);
} else {
setAgentReady(true);
}
};
const handleDisconnected = async () => {
try {
const newToken = await fetchToken();
setToken(newToken);
setShouldConnect(true);
} catch (err) {
console.error("Failed to refresh token after disconnect:", err);
}
};
useEffect(() => {
if (!persistentToken) {
fetchToken().then(() => setShouldConnect(true));
} else if (!persistentRoom) {
setShouldConnect(true);
}
return () => {
roomRef.current = null;
};
}, []);
if (!token) {
return (
<div className="modal-overlay">
<div className="modal">
<button className="close-btn" onClick={onClose}>×</button>
<div className="connecting-state">
<div className="spinner"></div>
<p>Connecting to AI Tutor...</p>
</div>
</div>
</div>
);
}
return (
<div className="modal-overlay">
<div className="modal">
<button className="close-btn" onClick={onClose}>×</button>
<LiveKitRoom
serverUrl={import.meta.env.VITE_LIVEKIT_URL}
token={token}
video={false}
audio={true}
onConnected={handleConnected}
onDisconnected={handleDisconnected}
connectOptions={{
autoSubscribe: true,
maxRetries: 3,
retryInterval: 1000,
}}
connect={shouldConnect}
>
<RoomContent
showAssistant={showAssistant}
question={question}
onClose={onClose}
onStartConversation={() => setShowAssistant(true)}
roomRef={roomRef}
agentReady={agentReady}
isFirstConnection={isFirstConnection}
/>
</LiveKitRoom>
</div>
</div>
);
};
export default LiveKitModal;
This code ensures that when a disconnection occurs, a new token is fetched and the connection is re-established using the new token. Let me know if you need further clarification or additional modifications!