import { useEffect, useState } from "react"; import { MdVolumeOff, MdVolumeUp, MdGraphicEq } from "react-icons/md"; import { LuActivity, LuSettings, LuSignal } from "react-icons/lu"; import { Button } from "@components/Button"; import { cx } from "@/cva.config"; import { useUiStore } from "@/hooks/stores"; import api from "@/api"; interface AudioConfig { Quality: number; Bitrate: number; SampleRate: number; Channels: number; FrameSize: string; } interface AudioMetrics { frames_received: number; frames_dropped: number; bytes_processed: number; last_frame_time: string; connection_drops: number; average_latency: string; } const qualityLabels = { 0: "Low (32kbps)", 1: "Medium (64kbps)", 2: "High (128kbps)", 3: "Ultra (256kbps)" }; export default function AudioControlPopover() { const [isMuted, setIsMuted] = useState(false); const [currentConfig, setCurrentConfig] = useState(null); const [metrics, setMetrics] = useState(null); const [showAdvanced, setShowAdvanced] = useState(false); const [isLoading, setIsLoading] = useState(false); const [isConnected, setIsConnected] = useState(false); const { toggleSidebarView } = useUiStore(); // Load initial audio state useEffect(() => { loadAudioState(); loadAudioMetrics(); // Set up metrics refresh interval const metricsInterval = setInterval(loadAudioMetrics, 2000); return () => clearInterval(metricsInterval); }, []); const loadAudioState = async () => { try { // Load mute state const muteResp = await api.GET("/audio/mute"); if (muteResp.ok) { const muteData = await muteResp.json(); setIsMuted(!!muteData.muted); } // Load quality config const qualityResp = await api.GET("/audio/quality"); if (qualityResp.ok) { const qualityData = await qualityResp.json(); setCurrentConfig(qualityData.current); } } catch (error) { console.error("Failed to load audio state:", error); } }; const loadAudioMetrics = async () => { try { const resp = await api.GET("/audio/metrics"); if (resp.ok) { const data = await resp.json(); setMetrics(data); // Consider connected if API call succeeds, regardless of frame count setIsConnected(true); } else { setIsConnected(false); } } catch (error) { console.error("Failed to load audio metrics:", error); setIsConnected(false); } }; const handleToggleMute = async () => { setIsLoading(true); try { const resp = await api.POST("/audio/mute", { muted: !isMuted }); if (resp.ok) { setIsMuted(!isMuted); } } catch (error) { console.error("Failed to toggle mute:", error); } finally { setIsLoading(false); } }; const handleQualityChange = async (quality: number) => { setIsLoading(true); try { const resp = await api.POST("/audio/quality", { quality }); if (resp.ok) { const data = await resp.json(); setCurrentConfig(data.config); } } catch (error) { console.error("Failed to change audio quality:", error); } finally { setIsLoading(false); } }; const formatBytes = (bytes: number) => { if (bytes === 0) return "0 B"; const k = 1024; const sizes = ["B", "KB", "MB", "GB"]; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i]; }; const formatNumber = (num: number) => { return new Intl.NumberFormat().format(num); }; return (
{/* Header */}

Audio Controls

{isConnected ? "Connected" : "Disconnected"}
{/* Mute Control */}
{isMuted ? ( ) : ( )} {isMuted ? "Muted" : "Unmuted"}
{/* Quality Settings */}
Audio Quality
{Object.entries(qualityLabels).map(([quality, label]) => ( ))}
{currentConfig && (
Sample Rate: {currentConfig.SampleRate}Hz Channels: {currentConfig.Channels} Bitrate: {currentConfig.Bitrate}kbps Frame: {currentConfig.FrameSize}
)}
{/* Advanced Controls Toggle */} {/* Advanced Metrics */} {showAdvanced && (
Performance Metrics
{metrics ? ( <>
Frames Received
{formatNumber(metrics.frames_received)}
Frames Dropped
0 ? "text-red-600 dark:text-red-400" : "text-green-600 dark:text-green-400" )}> {formatNumber(metrics.frames_dropped)}
Data Processed
{formatBytes(metrics.bytes_processed)}
Connection Drops
0 ? "text-red-600 dark:text-red-400" : "text-green-600 dark:text-green-400" )}> {formatNumber(metrics.connection_drops)}
{metrics.frames_received > 0 && (
Drop Rate
5 ? "text-red-600 dark:text-red-400" : ((metrics.frames_dropped / metrics.frames_received) * 100) > 1 ? "text-yellow-600 dark:text-yellow-400" : "text-green-600 dark:text-green-400" )}> {((metrics.frames_dropped / metrics.frames_received) * 100).toFixed(2)}%
)}
Last updated: {new Date().toLocaleTimeString()}
) : (
Loading metrics...
)}
)} {/* Audio Metrics Dashboard Button */}
); }