This message was deleted.
# ask-ai
s
This message was deleted.
t
Thanks for reaching out, Anigilaje. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
To implement a reconnection mechanism with a new token after a participant disconnects, you can utilize LiveKit's token refresh and reconnection features. Here are some key points: • LiveKit server proactively issues refreshed tokens to connected clients, ensuring they can reconnect if disconnected. These refreshed tokens have a 10-minute expiration. • Tokens are refreshed when there are changes to a participant's name, permissions, or metadata, and the client receives these through an
OnTokenRefresh
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.1
Here is the modified code for your frontend to handle reconnection with a new token after a participant disconnects:
Copy code
import { 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!