@@ -13,15 +13,20 @@ import { MicrophoneIcon } from '@phosphor-icons/react/dist/ssr';
1313import { useSession } from '@/components/app/session-provider' ;
1414import { AgentControlBar } from '@/components/livekit/agent-control-bar/agent-control-bar' ;
1515import { TrackControl } from '@/components/livekit/agent-control-bar/track-control' ;
16- import { TrackDeviceSelect } from '@/components/livekit/agent-control-bar/track-device-select' ;
17- import { TrackToggle } from '@/components/livekit/agent-control-bar/track-toggle' ;
16+ // import { TrackDeviceSelect } from '@/components/livekit/agent-control-bar/track-device-select';
17+ // import { TrackToggle } from '@/components/livekit/agent-control-bar/track-toggle';
1818import { Alert , AlertDescription , AlertTitle , alertVariants } from '@/components/livekit/alert' ;
1919import { AlertToast } from '@/components/livekit/alert-toast' ;
2020import { BarVisualizer } from '@/components/livekit/audio-visualizer/audio-bar-visualizer/_bar-visualizer' ;
2121import {
2222 AudioBarVisualizer ,
2323 audioBarVisualizerVariants ,
2424} from '@/components/livekit/audio-visualizer/audio-bar-visualizer/audio-bar-visualizer' ;
25+ import {
26+ AudioGridVisualizer ,
27+ type GridOptions ,
28+ } from '@/components/livekit/audio-visualizer/audio-grid-visualizer/audio-grid-visualizer' ;
29+ import { gridVariants } from '@/components/livekit/audio-visualizer/audio-grid-visualizer/demos' ;
2530import { Button , buttonVariants } from '@/components/livekit/button' ;
2631import { ChatEntry } from '@/components/livekit/chat-entry' ;
2732import {
@@ -191,8 +196,8 @@ export const COMPONENTS = {
191196 </ Container >
192197 ) ,
193198
194- // Audio visualizer
195- AudioVisualizer : ( ) => {
199+ // Audio bar visualizer
200+ AudioBarVisualizer : ( ) => {
196201 const barCounts = [ '0' , '3' , '5' , '7' , '9' ] ;
197202 const sizes = [ 'icon' , 'xs' , 'sm' , 'md' , 'lg' , 'xl' ] ;
198203 const states = [
@@ -309,6 +314,139 @@ export const COMPONENTS = {
309314 ) ;
310315 } ,
311316
317+ // Audio grid visualizer
318+ AudioGridVisualizer : ( ) => {
319+ const rowCounts = [ '3' , '5' , '7' , '9' , '11' , '13' , '15' ] ;
320+ const columnCounts = [ '3' , '5' , '7' , '9' , '11' , '13' , '15' ] ;
321+ const states = [
322+ 'disconnected' ,
323+ 'connecting' ,
324+ 'initializing' ,
325+ 'listening' ,
326+ 'thinking' ,
327+ 'speaking' ,
328+ ] as AgentState [ ] ;
329+
330+ const { microphoneTrack, localParticipant } = useLocalParticipant ( ) ;
331+ const [ rowCount , setRowCount ] = useState ( rowCounts [ 0 ] ) ;
332+ const [ columnCount , setColumnCount ] = useState ( columnCounts [ 0 ] ) ;
333+ const [ state , setState ] = useState < AgentState > ( states [ 0 ] ) ;
334+ const [ demoIndex , setDemoIndex ] = useState ( 0 ) ;
335+
336+ const micTrackRef = useMemo < TrackReferenceOrPlaceholder | undefined > ( ( ) => {
337+ return state === 'speaking'
338+ ? ( {
339+ participant : localParticipant ,
340+ source : Track . Source . Microphone ,
341+ publication : microphoneTrack ,
342+ } as TrackReference )
343+ : undefined ;
344+ } , [ state , localParticipant , microphoneTrack ] ) ;
345+
346+ useMicrophone ( ) ;
347+
348+ const demoOptions = {
349+ rowCount : parseInt ( rowCount ) ,
350+ columnCount : parseInt ( columnCount ) ,
351+ ...gridVariants [ demoIndex ] ,
352+ } ;
353+
354+ return (
355+ < Container componentName = "AudioVisualizer" >
356+ < div className = "flex items-center gap-2" >
357+ < div className = "flex-1" >
358+ < label className = "font-mono text-xs uppercase" htmlFor = "state" >
359+ State
360+ </ label >
361+ < Select value = { state } onValueChange = { ( value ) => setState ( value as AgentState ) } >
362+ < SelectTrigger id = "state" className = "w-full" >
363+ < SelectValue placeholder = "Select a state" />
364+ </ SelectTrigger >
365+ < SelectContent >
366+ { states . map ( ( state ) => (
367+ < SelectItem key = { state } value = { state } >
368+ { state }
369+ </ SelectItem >
370+ ) ) }
371+ </ SelectContent >
372+ </ Select >
373+ </ div >
374+
375+ < div className = "flex-1" >
376+ < label className = "font-mono text-xs uppercase" htmlFor = "rowCount" >
377+ Row count
378+ </ label >
379+ < Select value = { rowCount . toString ( ) } onValueChange = { ( value ) => setRowCount ( value ) } >
380+ < SelectTrigger id = "rowCount" className = "w-full" >
381+ < SelectValue placeholder = "Select a bar count" />
382+ </ SelectTrigger >
383+ < SelectContent >
384+ { rowCounts . map ( ( rowCount ) => (
385+ < SelectItem key = { rowCount } value = { rowCount . toString ( ) } >
386+ { parseInt ( rowCount ) || 'Default' }
387+ </ SelectItem >
388+ ) ) }
389+ </ SelectContent >
390+ </ Select >
391+ </ div >
392+
393+ < div className = "flex-1" >
394+ < label className = "font-mono text-xs uppercase" htmlFor = "columnCount" >
395+ Column count
396+ </ label >
397+ < Select value = { columnCount . toString ( ) } onValueChange = { ( value ) => setColumnCount ( value ) } >
398+ < SelectTrigger id = "columnCount" className = "w-full" >
399+ < SelectValue placeholder = "Select a column count" />
400+ </ SelectTrigger >
401+ < SelectContent >
402+ { columnCounts . map ( ( columnCount ) => (
403+ < SelectItem key = { columnCount } value = { columnCount . toString ( ) } >
404+ { parseInt ( columnCount ) || 'Default' }
405+ </ SelectItem >
406+ ) ) }
407+ </ SelectContent >
408+ </ Select >
409+ </ div >
410+
411+ < div className = "flex-1" >
412+ < label className = "font-mono text-xs uppercase" htmlFor = "demoIndex" >
413+ Demo
414+ </ label >
415+ < Select
416+ value = { demoIndex . toString ( ) }
417+ onValueChange = { ( value ) => setDemoIndex ( parseInt ( value ) ) }
418+ >
419+ < SelectTrigger id = "demoIndex" className = "w-full" >
420+ < SelectValue placeholder = "Select a demo" />
421+ </ SelectTrigger >
422+ < SelectContent >
423+ { gridVariants . map ( ( _ , idx ) => (
424+ < SelectItem key = { idx } value = { idx . toString ( ) } >
425+ Demo { String ( idx + 1 ) }
426+ </ SelectItem >
427+ ) ) }
428+ </ SelectContent >
429+ </ Select >
430+ </ div >
431+ </ div >
432+
433+ < div className = "grid place-items-center py-12" >
434+ < AudioGridVisualizer
435+ key = { `${ demoIndex } -${ rowCount } -${ columnCount } ` }
436+ state = { state }
437+ audioTrack = { micTrackRef ! }
438+ options = { demoOptions }
439+ />
440+ </ div >
441+ < div className = "border-border bg-muted overflow-x-auto rounded-xl border p-8" >
442+ < pre className = "text-muted-foreground text-sm" >
443+ < code > { JSON . stringify ( demoOptions , null , 2 ) } </ code >
444+ </ pre >
445+ </ div >
446+ </ Container >
447+ ) ;
448+ } ,
449+
312450 // Agent control bar
313451 AgentControlBar : ( ) => {
314452 useMicrophone ( ) ;
0 commit comments