Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 32 additions & 52 deletions components/app.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
'use client';

import { useEffect, useMemo, useState } from 'react';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { Room, RoomEvent } from 'livekit-client';
import { motion } from 'motion/react';
import { RoomAudioRenderer, RoomContext, StartAudio } from '@livekit/components-react';
import {
LiveKitRoom,
RoomAudioRenderer,
RoomContext,
StartAudio,
useRoomConnection,
} from '@livekit/components-react';
import { toastAlert } from '@/components/alert-toast';
import { SessionView } from '@/components/session-view';
import { Toaster } from '@/components/ui/sonner';
Expand All @@ -19,58 +25,25 @@ interface AppProps {
}

export function App({ appConfig }: AppProps) {
const room = useMemo(() => new Room(), []);
const [sessionStarted, setSessionStarted] = useState(false);
const { connectionDetails, refreshConnectionDetails } = useConnectionDetails();

useEffect(() => {
const onDisconnected = () => {
setSessionStarted(false);
refreshConnectionDetails();
};
const onMediaDevicesError = (error: Error) => {
toastAlert({
title: 'Encountered an error with your media devices',
description: `${error.name}: ${error.message}`,
});
};
room.on(RoomEvent.MediaDevicesError, onMediaDevicesError);
room.on(RoomEvent.Disconnected, onDisconnected);
return () => {
room.off(RoomEvent.Disconnected, onDisconnected);
room.off(RoomEvent.MediaDevicesError, onMediaDevicesError);
};
}, [room, refreshConnectionDetails]);
const enableMicrophonePreConnectBuffer = useCallback(async (room: Room) => {
room.localParticipant.setMicrophoneEnabled(true, undefined, {
preConnectBuffer: appConfig.isPreConnectBufferEnabled,
});
}, []);

useEffect(() => {
let aborted = false;
if (sessionStarted && room.state === 'disconnected' && connectionDetails) {
Promise.all([
room.localParticipant.setMicrophoneEnabled(true, undefined, {
preConnectBuffer: appConfig.isPreConnectBufferEnabled,
}),
room.connect(connectionDetails.serverUrl, connectionDetails.participantToken),
]).catch((error) => {
if (aborted) {
// Once the effect has cleaned up after itself, drop any errors
//
// These errors are likely caused by this effect rerunning rapidly,
// resulting in a previous run `disconnect` running in parallel with
// a current run `connect`
return;
}

toastAlert({
title: 'There was an error connecting to the agent',
description: `${error.name}: ${error.message}`,
});
});
}
return () => {
aborted = true;
room.disconnect();
};
}, [room, sessionStarted, connectionDetails, appConfig.isPreConnectBufferEnabled]);
const onDisconnected = useCallback(() => {
setSessionStarted(false);
refreshConnectionDetails();
}, [refreshConnectionDetails]);
const onMediaDeviceFailure = useCallback((error: Error) => {
toastAlert({
title: 'Encountered an error with your media devices',
description: `${error.name}: ${error.message}`,
});
}, []);

const { startButtonText } = appConfig;

Expand All @@ -86,7 +59,14 @@ export function App({ appConfig }: AppProps) {
transition={{ duration: 0.5, ease: 'linear', delay: sessionStarted ? 0 : 0.5 }}
/>

<RoomContext.Provider value={room}>
<LiveKitRoom
connect={sessionStarted && connectionDetails !== null}
token={connectionDetails?.participantToken!}
serverUrl={connectionDetails?.serverUrl!}
connectionSideEffect={enableMicrophonePreConnectBuffer}
onDisconnected={onDisconnected}
onMediaDeviceFailure={onMediaDeviceFailure}
>
<RoomAudioRenderer />
<StartAudio label="Start Audio" />
{/* --- */}
Expand All @@ -103,7 +83,7 @@ export function App({ appConfig }: AppProps) {
delay: sessionStarted ? 0.5 : 0,
}}
/>
</RoomContext.Provider>
</LiveKitRoom>

<Toaster />
</>
Expand Down
Loading