Spaces:
Running
Running
Update src/components/control-tray/ControlTray.tsx
Browse files
src/components/control-tray/ControlTray.tsx
CHANGED
@@ -5,7 +5,7 @@ import React, { memo, RefObject, useEffect, useState, useCallback, useRef } from
|
|
5 |
import { useLiveAPIContext } from "../../contexts/LiveAPIContext";
|
6 |
import { AudioRecorder } from "../../lib/audio-recorder";
|
7 |
import Logo from '../logo/Logo';
|
8 |
-
import { PauseIconWithSurroundPulse, microphoneIcon, cameraIcon, stopCamIcon
|
9 |
|
10 |
const SvgSwitchCameraIcon = () => <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="w-[22px] h-[22px]"><path d="M11 19H4a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2h5"/><path d="M13 5h7a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2h-5"/><path d="m17 12-3-3 3-3"/><path d="m7 12 3 3-3 3"/></svg>;
|
11 |
|
@@ -23,7 +23,7 @@ export type ControlTrayProps = {
|
|
23 |
};
|
24 |
|
25 |
const ControlTray: React.FC<ControlTrayProps> = ({ videoRef, onVideoStreamChange, supportsVideo, isAppMicActive, onAppMicToggle, isAppCamActive, onAppCamToggle, currentFacingMode, onFacingModeChange, onUserSpeakingChange }) => {
|
26 |
-
const { client, connected, connect, volume } = useLiveAPIContext();
|
27 |
const audioRecorderRef = useRef<AudioRecorder | null>(null);
|
28 |
const [activeLocalVideoStream, setActiveLocalVideoStream] = useState<MediaStream | null>(null);
|
29 |
const [isSwitchingCamera, setIsSwitchingCamera] = useState(false);
|
@@ -32,35 +32,43 @@ const ControlTray: React.FC<ControlTrayProps> = ({ videoRef, onVideoStreamChange
|
|
32 |
|
33 |
useEffect(() => {
|
34 |
if (!audioRecorderRef.current) {
|
35 |
-
|
36 |
}
|
37 |
const audioRecorder = audioRecorderRef.current;
|
38 |
-
|
39 |
-
const
|
40 |
if (client && connected && isAppMicActive) {
|
41 |
client.sendRealtimeInput([{ mimeType: "audio/pcm;rate=16000", data: base64 }]);
|
42 |
-
setUserVolume(volume);
|
43 |
-
onUserSpeakingChange(volume > 0.01);
|
44 |
}
|
45 |
};
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
|
|
50 |
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
}
|
|
|
56 |
return () => {
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
}
|
61 |
};
|
62 |
-
}, [connected, client,
|
63 |
|
|
|
64 |
useEffect(() => {
|
65 |
if (videoRef.current) {
|
66 |
if (videoRef.current.srcObject !== activeLocalVideoStream) {
|
@@ -191,8 +199,6 @@ const ControlTray: React.FC<ControlTrayProps> = ({ videoRef, onVideoStreamChange
|
|
191 |
}
|
192 |
};
|
193 |
|
194 |
-
const isSpeaking = onUserSpeakingChange.length > 0 && userVolume > 0.01;
|
195 |
-
|
196 |
return (
|
197 |
<footer id="footer-controls" className="footer-controls-html-like">
|
198 |
<canvas style={{ display: "none" }} ref={renderCanvasRef} />
|
@@ -206,8 +212,8 @@ const ControlTray: React.FC<ControlTrayProps> = ({ videoRef, onVideoStreamChange
|
|
206 |
isMini={true}
|
207 |
isActive={true}
|
208 |
isAi={false}
|
209 |
-
speakingVolume={
|
210 |
-
isUserSpeaking={
|
211 |
/>
|
212 |
</div>
|
213 |
)}
|
|
|
5 |
import { useLiveAPIContext } from "../../contexts/LiveAPIContext";
|
6 |
import { AudioRecorder } from "../../lib/audio-recorder";
|
7 |
import Logo from '../logo/Logo';
|
8 |
+
import { PauseIconWithSurroundPulse, microphoneIcon, cameraIcon, stopCamIcon } from '../icons';
|
9 |
|
10 |
const SvgSwitchCameraIcon = () => <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="w-[22px] h-[22px]"><path d="M11 19H4a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2h5"/><path d="M13 5h7a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2h-5"/><path d="m17 12-3-3 3-3"/><path d="m7 12 3 3-3 3"/></svg>;
|
11 |
|
|
|
23 |
};
|
24 |
|
25 |
const ControlTray: React.FC<ControlTrayProps> = ({ videoRef, onVideoStreamChange, supportsVideo, isAppMicActive, onAppMicToggle, isAppCamActive, onAppCamToggle, currentFacingMode, onFacingModeChange, onUserSpeakingChange }) => {
|
26 |
+
const { client, connected, connect, volume: aiVolume } = useLiveAPIContext();
|
27 |
const audioRecorderRef = useRef<AudioRecorder | null>(null);
|
28 |
const [activeLocalVideoStream, setActiveLocalVideoStream] = useState<MediaStream | null>(null);
|
29 |
const [isSwitchingCamera, setIsSwitchingCamera] = useState(false);
|
|
|
32 |
|
33 |
useEffect(() => {
|
34 |
if (!audioRecorderRef.current) {
|
35 |
+
audioRecorderRef.current = new AudioRecorder();
|
36 |
}
|
37 |
const audioRecorder = audioRecorderRef.current;
|
38 |
+
|
39 |
+
const handleData = (base64: string) => {
|
40 |
if (client && connected && isAppMicActive) {
|
41 |
client.sendRealtimeInput([{ mimeType: "audio/pcm;rate=16000", data: base64 }]);
|
|
|
|
|
42 |
}
|
43 |
};
|
44 |
+
|
45 |
+
const handleVolume = (volume: number) => {
|
46 |
+
setUserVolume(volume);
|
47 |
+
onUserSpeakingChange(volume > 0.01);
|
48 |
+
};
|
49 |
|
50 |
+
const handleStop = () => {
|
51 |
+
setUserVolume(0);
|
52 |
+
onUserSpeakingChange(false);
|
53 |
+
};
|
54 |
+
|
55 |
+
if (isAppMicActive && !audioRecorder.recording) {
|
56 |
+
audioRecorder.on('data', handleData);
|
57 |
+
audioRecorder.on('volume', handleVolume);
|
58 |
+
audioRecorder.on('stop', handleStop);
|
59 |
+
audioRecorder.start();
|
60 |
+
} else if (!isAppMicActive && audioRecorder.recording) {
|
61 |
+
audioRecorder.stop();
|
62 |
}
|
63 |
+
|
64 |
return () => {
|
65 |
+
audioRecorder.off('data', handleData);
|
66 |
+
audioRecorder.off('volume', handleVolume);
|
67 |
+
audioRecorder.off('stop', handleStop);
|
|
|
68 |
};
|
69 |
+
}, [isAppMicActive, connected, client, onUserSpeakingChange]);
|
70 |
|
71 |
+
// ... (بقیه useEffect ها و توابع بدون تغییر باقی میمانند)
|
72 |
useEffect(() => {
|
73 |
if (videoRef.current) {
|
74 |
if (videoRef.current.srcObject !== activeLocalVideoStream) {
|
|
|
199 |
}
|
200 |
};
|
201 |
|
|
|
|
|
202 |
return (
|
203 |
<footer id="footer-controls" className="footer-controls-html-like">
|
204 |
<canvas style={{ display: "none" }} ref={renderCanvasRef} />
|
|
|
212 |
isMini={true}
|
213 |
isActive={true}
|
214 |
isAi={false}
|
215 |
+
speakingVolume={aiVolume}
|
216 |
+
isUserSpeaking={userVolume > 0.01}
|
217 |
/>
|
218 |
</div>
|
219 |
)}
|