From 8600cb635407430aaa159f5b0e3a638775e6572a Mon Sep 17 00:00:00 2001 From: Ryan Gaus Date: Mon, 4 Aug 2025 15:04:57 -0400 Subject: [PATCH 1/2] feat: add example use of useRoomConnection --- components/app.tsx | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/components/app.tsx b/components/app.tsx index 725170b2..4b833e90 100644 --- a/components/app.tsx +++ b/components/app.tsx @@ -1,9 +1,14 @@ '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 { + 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'; @@ -19,10 +24,24 @@ interface AppProps { } export function App({ appConfig }: AppProps) { - const room = useMemo(() => new Room(), []); const [sessionStarted, setSessionStarted] = useState(false); const { connectionDetails, refreshConnectionDetails } = useConnectionDetails(); + const { status, room } = useRoomConnection({ + getConnectionDetails: useCallback(async () => connectionDetails!, [connectionDetails]), + onConnectionError: useCallback((error: Error) => { + toastAlert({ + title: 'There was an error connecting to the agent', + description: `${error.name}: ${error.message}`, + }); + }, []), + + connected: connectionDetails !== null && sessionStarted, + trackPublishOptions: { + preConnectBuffer: appConfig.isPreConnectBufferEnabled, + }, + }); + useEffect(() => { const onDisconnected = () => { setSessionStarted(false); From 75830e64656a3d621b32733b983626e4a058a4fc Mon Sep 17 00:00:00 2001 From: Ryan Gaus Date: Tue, 5 Aug 2025 12:39:06 -0400 Subject: [PATCH 2/2] feat: update app to use pre-existing LiveKitRoom component --- components/app.tsx | 87 +++++++++++++--------------------------------- 1 file changed, 24 insertions(+), 63 deletions(-) diff --git a/components/app.tsx b/components/app.tsx index 4b833e90..1e76c88e 100644 --- a/components/app.tsx +++ b/components/app.tsx @@ -4,6 +4,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import { Room, RoomEvent } from 'livekit-client'; import { motion } from 'motion/react'; import { + LiveKitRoom, RoomAudioRenderer, RoomContext, StartAudio, @@ -27,69 +28,22 @@ export function App({ appConfig }: AppProps) { const [sessionStarted, setSessionStarted] = useState(false); const { connectionDetails, refreshConnectionDetails } = useConnectionDetails(); - const { status, room } = useRoomConnection({ - getConnectionDetails: useCallback(async () => connectionDetails!, [connectionDetails]), - onConnectionError: useCallback((error: Error) => { - toastAlert({ - title: 'There was an error connecting to the agent', - description: `${error.name}: ${error.message}`, - }); - }, []), - - connected: connectionDetails !== null && sessionStarted, - trackPublishOptions: { + const enableMicrophonePreConnectBuffer = useCallback(async (room: Room) => { + room.localParticipant.setMicrophoneEnabled(true, undefined, { preConnectBuffer: appConfig.isPreConnectBufferEnabled, - }, - }); - - 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]); - - 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; @@ -105,7 +59,14 @@ export function App({ appConfig }: AppProps) { transition={{ duration: 0.5, ease: 'linear', delay: sessionStarted ? 0 : 0.5 }} /> - + {/* --- */} @@ -122,7 +83,7 @@ export function App({ appConfig }: AppProps) { delay: sessionStarted ? 0.5 : 0, }} /> - +