Spaces:
Running
Running
File size: 4,631 Bytes
9d3c32a |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
import React, { useState, useEffect, useRef } from 'react';
import { useNavigate } from 'react-router-dom';
import { useToast } from '@/hooks/use-toast';
import { generateSensorData, generateMotorData } from '@/lib/mockData';
import VisualizerPanel from '@/components/control/VisualizerPanel';
import MetricsPanel from '@/components/control/MetricsPanel';
import CommandBar from '@/components/control/CommandBar';
const Index = () => {
const [command, setCommand] = useState('');
const [activeTab, setActiveTab] = useState<'SENSORS' | 'MOTORS'>('SENSORS');
const [isVoiceActive, setIsVoiceActive] = useState(true);
const [showCamera, setShowCamera] = useState(false);
const [hasPermissions, setHasPermissions] = useState(false);
const [micLevel, setMicLevel] = useState(0);
const [sensorData, setSensorData] = useState<any[]>([]);
const [motorData, setMotorData] = useState<any[]>([]);
const { toast } = useToast();
const navigate = useNavigate();
const videoRef = useRef<HTMLVideoElement>(null);
const streamRef = useRef<MediaStream | null>(null);
useEffect(() => {
let audioContext: AudioContext | null = null;
const getPermissions = async () => {
try {
const stream = await navigator.mediaDevices.getUserMedia({
video: true,
audio: true
});
streamRef.current = stream;
if (videoRef.current) {
videoRef.current.srcObject = stream;
}
setHasPermissions(true);
const AudioContextClass = window.AudioContext || (window as any).webkitAudioContext;
if (AudioContextClass) {
audioContext = new AudioContextClass();
const analyser = audioContext.createAnalyser();
const source = audioContext.createMediaStreamSource(stream);
source.connect(analyser);
let animationFrameId: number;
const dataArray = new Uint8Array(analyser.frequencyBinCount);
const updateMicLevel = () => {
if (audioContext?.state === 'closed') return;
analyser.getByteFrequencyData(dataArray);
const average = dataArray.reduce((a, b) => a + b) / dataArray.length;
setMicLevel(average);
animationFrameId = requestAnimationFrame(updateMicLevel);
};
updateMicLevel();
return () => {
cancelAnimationFrame(animationFrameId);
audioContext?.close();
};
}
} catch (error) {
console.error("Permission to access media devices was denied.", error);
}
};
let cleanup: (() => void) | undefined;
getPermissions().then(returnedCleanup => {
cleanup = returnedCleanup;
});
return () => {
if (streamRef.current) {
streamRef.current.getTracks().forEach(track => track.stop());
}
cleanup?.();
};
}, []);
useEffect(() => {
const interval = setInterval(() => {
setSensorData(prev => [...prev, generateSensorData()].slice(-50));
setMotorData(prev => [...prev, generateMotorData()].slice(-50));
}, 100);
return () => clearInterval(interval);
}, []);
const handleSendCommand = () => {
if (command.trim()) {
toast({
title: "Command Sent",
description: `Robot command: "${command}"`,
});
setCommand('');
}
};
const handleGoBack = () => {
navigate('/');
};
const handleEndSession = () => {
if (streamRef.current) {
streamRef.current.getTracks().forEach(track => track.stop());
}
toast({
title: "Session Ended",
description: "Robot control session terminated safely.",
variant: "destructive",
});
navigate('/');
};
return (
<div className="min-h-screen bg-black text-white flex flex-col">
<div className="flex-1 flex flex-col lg:flex-row">
<VisualizerPanel onGoBack={handleGoBack} />
<MetricsPanel
activeTab={activeTab}
setActiveTab={setActiveTab}
sensorData={sensorData}
motorData={motorData}
hasPermissions={hasPermissions}
streamRef={streamRef}
isVoiceActive={isVoiceActive}
micLevel={micLevel}
/>
</div>
<CommandBar
command={command}
setCommand={setCommand}
handleSendCommand={handleSendCommand}
isVoiceActive={isVoiceActive}
setIsVoiceActive={setIsVoiceActive}
showCamera={showCamera}
setShowCamera={setShowCamera}
handleEndSession={handleEndSession}
/>
</div>
);
};
export default Index;
|