-
Notifications
You must be signed in to change notification settings - Fork 142
Update examples with useSession/useAgent hooks #1242
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 13 commits
f514318
b5b3cde
de906a0
55854f7
6a3a037
0745049
8629563
d9dd885
bfc77d5
6de8642
f8375f0
dc0e3a6
f35d5a1
63d3da7
e5573e5
95bad4f
29d13fd
238b090
1383d77
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| --- | ||
| '@livekit/component-example-next': patch | ||
| '@livekit/components-react': patch | ||
| --- | ||
|
|
||
| Update nextjs examples with useSession/useAgent hooks |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,32 +1,75 @@ | ||
| 'use client'; | ||
|
|
||
| import { AudioConference, LiveKitRoom, useToken } from '@livekit/components-react'; | ||
| import { | ||
| AudioConference, | ||
| SessionProvider, | ||
| useSession, | ||
| SessionEvent, | ||
| } from '@livekit/components-react'; | ||
| import type { NextPage } from 'next'; | ||
| import { generateRandomUserId } from '../lib/helper'; | ||
| import { useState } from 'react'; | ||
| import { useMemo, useState, useEffect } from 'react'; | ||
| import { TokenSource, MediaDeviceFailure } from 'livekit-client'; | ||
|
|
||
| const AudioExample: NextPage = () => { | ||
| const params = typeof window !== 'undefined' ? new URLSearchParams(location.search) : null; | ||
| const params = useMemo( | ||
| () => (typeof window !== 'undefined' ? new URLSearchParams(location.search) : null), | ||
| [], | ||
| ); | ||
| const roomName = params?.get('room') ?? 'test-room'; | ||
| const [userIdentity] = useState(params?.get('user') ?? generateRandomUserId()); | ||
| const [userIdentity] = useState(() => params?.get('user') ?? generateRandomUserId()); | ||
|
||
|
|
||
| const tokenSource = useMemo(() => { | ||
| return TokenSource.endpoint(process.env.NEXT_PUBLIC_LK_TOKEN_ENDPOINT!); | ||
| }, []); | ||
|
||
|
|
||
| const token = useToken(process.env.NEXT_PUBLIC_LK_TOKEN_ENDPOINT, roomName, { | ||
| userInfo: { | ||
| identity: userIdentity, | ||
| name: userIdentity, | ||
| }, | ||
| const session = useSession(tokenSource, { | ||
| roomName, | ||
| participantIdentity: userIdentity, | ||
| participantName: userIdentity, | ||
| }); | ||
|
|
||
| useEffect(() => { | ||
| session | ||
| .start({ | ||
| tracks: { | ||
| microphone: { enabled: true }, | ||
| }, | ||
| roomConnectOptions: { | ||
| autoSubscribe: true, | ||
| }, | ||
| }) | ||
| .catch((err) => { | ||
| console.error('Failed to start session:', err); | ||
| }); | ||
| return () => { | ||
| session.end().catch((err) => { | ||
| console.error('Failed to end session:', err); | ||
| }); | ||
| }; | ||
| // eslint-disable-next-line react-hooks/exhaustive-deps | ||
| }, [session.start, session.end]); | ||
|
|
||
| useEffect(() => { | ||
| const handleMediaDevicesError = (error: Error) => { | ||
| const failure = MediaDeviceFailure.getFailure(error); | ||
| console.error(failure); | ||
| alert( | ||
| 'Error acquiring camera or microphone permissions. Please make sure you grant the necessary permissions in your browser and reload the tab', | ||
| ); | ||
| }; | ||
|
|
||
| session.internal.emitter.on(SessionEvent.MediaDevicesError, handleMediaDevicesError); | ||
| return () => { | ||
| session.internal.emitter.off(SessionEvent.MediaDevicesError, handleMediaDevicesError); | ||
| }; | ||
| }, [session]); | ||
|
|
||
| return ( | ||
| <div data-lk-theme="default"> | ||
| <LiveKitRoom | ||
| video={false} | ||
| audio={true} | ||
| token={token} | ||
| serverUrl={process.env.NEXT_PUBLIC_LK_SERVER_URL} | ||
| > | ||
| <SessionProvider session={session}> | ||
| <AudioConference /> | ||
| </LiveKitRoom> | ||
| </SessionProvider> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,52 +2,87 @@ | |
|
|
||
| import { | ||
| ControlBar, | ||
| LiveKitRoom, | ||
| SessionProvider, | ||
| useSession, | ||
| RoomAudioRenderer, | ||
| RoomName, | ||
| TrackLoop, | ||
| TrackMutedIndicator, | ||
| useIsMuted, | ||
| useIsSpeaking, | ||
| useToken, | ||
| useTrackRefContext, | ||
| useTracks, | ||
| SessionEvent, | ||
| } from '@livekit/components-react'; | ||
| import styles from '../styles/Clubhouse.module.scss'; | ||
| import { Track } from 'livekit-client'; | ||
| import { useMemo, useState } from 'react'; | ||
| import { Track, TokenSource, MediaDeviceFailure } from 'livekit-client'; | ||
| import { useMemo, useState, useEffect } from 'react'; | ||
| import { generateRandomUserId } from '../lib/helper'; | ||
| import type { NextPage } from 'next'; | ||
|
|
||
| const Clubhouse = () => { | ||
| const params = typeof window !== 'undefined' ? new URLSearchParams(location.search) : null; | ||
| const Clubhouse: NextPage = () => { | ||
| const params = useMemo( | ||
| () => (typeof window !== 'undefined' ? new URLSearchParams(location.search) : null), | ||
| [], | ||
| ); | ||
| const roomName = params?.get('room') ?? 'test-room'; | ||
| const userIdentity = params?.get('user') ?? generateRandomUserId(); | ||
| const [userIdentity] = useState(() => params?.get('user') ?? generateRandomUserId()); | ||
|
||
|
|
||
| const tokenSource = useMemo(() => { | ||
| return TokenSource.endpoint(process.env.NEXT_PUBLIC_LK_TOKEN_ENDPOINT!); | ||
| }, []); | ||
|
|
||
| const token = useToken(process.env.NEXT_PUBLIC_LK_TOKEN_ENDPOINT, roomName, { | ||
| userInfo: { | ||
| identity: userIdentity, | ||
| name: userIdentity, | ||
| }, | ||
| const session = useSession(tokenSource, { | ||
| roomName, | ||
| participantIdentity: userIdentity, | ||
| participantName: userIdentity, | ||
| }); | ||
|
|
||
| const [tryToConnect, setTryToConnect] = useState(false); | ||
| const [connected, setConnected] = useState(false); | ||
|
|
||
| useEffect(() => { | ||
| if (tryToConnect) { | ||
| session | ||
| .start({ | ||
| tracks: { | ||
| microphone: { enabled: true }, | ||
| }, | ||
| }) | ||
| .catch((err) => { | ||
| console.error('Failed to start session:', err); | ||
| }); | ||
| } else { | ||
| session.end().catch((err) => { | ||
| console.error('Failed to end session:', err); | ||
| }); | ||
| } | ||
| // eslint-disable-next-line react-hooks/exhaustive-deps | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thought(non-blocking): 😢
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also a |
||
| }, [tryToConnect, session.start, session.end]); | ||
|
|
||
| useEffect(() => { | ||
| if (session.connectionState === 'disconnected') { | ||
| setTryToConnect(false); | ||
| } | ||
| }, [session.connectionState]); | ||
|
|
||
| useEffect(() => { | ||
| const handleMediaDevicesError = (error: Error) => { | ||
| const failure = MediaDeviceFailure.getFailure(error); | ||
| console.error(failure); | ||
| alert( | ||
| 'Error acquiring camera or microphone permissions. Please make sure you grant the necessary permissions in your browser and reload the tab', | ||
| ); | ||
| }; | ||
|
|
||
| session.internal.emitter.on(SessionEvent.MediaDevicesError, handleMediaDevicesError); | ||
|
||
| return () => { | ||
| session.internal.emitter.off(SessionEvent.MediaDevicesError, handleMediaDevicesError); | ||
| }; | ||
| }, [session]); | ||
|
|
||
| return ( | ||
| <div data-lk-theme="default" className={styles.container}> | ||
| <LiveKitRoom | ||
| token={token} | ||
| serverUrl={process.env.NEXT_PUBLIC_LK_SERVER_URL} | ||
| connect={tryToConnect} | ||
| video={false} | ||
| audio={true} | ||
| // simulateParticipants={15} | ||
| onConnected={() => setConnected(true)} | ||
| onDisconnected={() => { | ||
| setTryToConnect(false); | ||
| setConnected(false); | ||
| }} | ||
| > | ||
| <SessionProvider session={session}> | ||
| <div style={{ display: 'grid', placeContent: 'center', height: '100%' }}> | ||
| <button | ||
| className="lk-button" | ||
|
|
@@ -59,7 +94,7 @@ | |
| </button> | ||
| </div> | ||
|
|
||
| <div className={styles.slider} style={{ bottom: connected ? '0px' : '-100%' }}> | ||
| <div className={styles.slider} style={{ bottom: session.isConnected ? '0px' : '-100%' }}> | ||
| <h1> | ||
| <RoomName /> | ||
| </h1> | ||
|
|
@@ -70,15 +105,15 @@ | |
| /> | ||
| <RoomAudioRenderer /> | ||
| </div> | ||
| </LiveKitRoom> | ||
| </SessionProvider> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| const Stage = () => { | ||
| const tracksReferences = useTracks([Track.Source.Microphone]); | ||
| return ( | ||
| <div className=""> | ||
| <div> | ||
| <div className={styles.stageGrid}> | ||
| <TrackLoop tracks={tracksReferences}> | ||
| <CustomParticipantTile></CustomParticipantTile> | ||
|
|
@@ -98,14 +133,10 @@ | |
| return ( | ||
| <section className={styles['participant-tile']} title={trackRef.participant.name}> | ||
| <div | ||
| // className={`rounded-full border-2 p-0.5 transition-colors duration-1000 ${ | ||
| className={styles['avatar-container']} | ||
| style={{ borderColor: isSpeaking ? 'greenyellow' : 'transparent' }} | ||
| > | ||
| <div | ||
| className={styles.avatar} | ||
| // className="z-10 grid aspect-square items-center overflow-hidden rounded-full bg-beige transition-all will-change-transform" | ||
| > | ||
| <div className={styles.avatar}> | ||
| <img | ||
| src={`https://avatars.dicebear.com/api/avataaars/${id}.svg?mouth=default,smile,tongue&eyes=default,happy,hearts&eyebrows=default,defaultNatural,flatNatural`} | ||
| className="fade-in" | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.