Ezmary commited on
Commit
efe5b15
·
verified ·
1 Parent(s): 0362c08

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 } 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,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: aiVolume } = useLiveAPIContext();
27
  const audioRecorderRef = useRef<AudioRecorder | null>(null);
28
  const [activeLocalVideoStream, setActiveLocalVideoStream] = useState<MediaStream | null>(null);
29
  const [isSwitchingCamera, setIsSwitchingCamera] = useState(false);
@@ -32,43 +32,37 @@ const ControlTray: React.FC<ControlTrayProps> = ({ videoRef, onVideoStreamChange
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,10 +193,13 @@ const ControlTray: React.FC<ControlTrayProps> = ({ videoRef, onVideoStreamChange
199
  }
200
  };
201
 
 
 
202
  return (
203
  <footer id="footer-controls" className="footer-controls-html-like">
204
  <canvas style={{ display: "none" }} ref={renderCanvasRef} />
205
  <div id="mic-button" className="control-button mic-button-color" onClick={handleMicToggle}>
 
206
  {isAppMicActive ? <PauseIconWithSurroundPulse userVolume={userVolume} /> : microphoneIcon}
207
  </div>
208
 
@@ -212,8 +209,8 @@ const ControlTray: React.FC<ControlTrayProps> = ({ videoRef, onVideoStreamChange
212
  isMini={true}
213
  isActive={true}
214
  isAi={false}
215
- speakingVolume={aiVolume}
216
- isUserSpeaking={userVolume > 0.01}
217
  />
218
  </div>
219
  )}
 
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, pauseIcon } 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 } = 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
+ // --- 👇 تغییر اصلی اینجاست: دریافت ولوم از رویداد data 👇 ---
40
+ const onData = (base64: string, volume: number) => {
41
  if (client && connected && isAppMicActive) {
42
  client.sendRealtimeInput([{ mimeType: "audio/pcm;rate=16000", data: base64 }]);
43
+ setUserVolume(volume);
44
+ onUserSpeakingChange(volume > 0.01);
45
  }
46
  };
47
 
48
+ const onStop = () => {
49
+ setUserVolume(0);
50
+ onUserSpeakingChange(false);
51
+ }
 
 
 
 
 
52
 
53
+ if (connected && isAppMicActive) {
54
+ audioRecorder.on("data", onData).on("stop", onStop).start();
55
+ } else {
56
+ if (audioRecorder.recording) audioRecorder.stop();
 
 
 
57
  }
 
58
  return () => {
59
+ if (audioRecorder) {
60
+ audioRecorder.off("data", onData).off("stop", onStop);
61
+ if (audioRecorder.recording) audioRecorder.stop();
62
+ }
63
  };
64
+ }, [connected, client, isAppMicActive, onUserSpeakingChange]);
65
 
 
66
  useEffect(() => {
67
  if (videoRef.current) {
68
  if (videoRef.current.srcObject !== activeLocalVideoStream) {
 
193
  }
194
  };
195
 
196
+ const isSpeaking = onUserSpeakingChange.length > 0 && userVolume > 0.01;
197
+
198
  return (
199
  <footer id="footer-controls" className="footer-controls-html-like">
200
  <canvas style={{ display: "none" }} ref={renderCanvasRef} />
201
  <div id="mic-button" className="control-button mic-button-color" onClick={handleMicToggle}>
202
+ {/* استفاده از آیکون جدید با انیمیشن */}
203
  {isAppMicActive ? <PauseIconWithSurroundPulse userVolume={userVolume} /> : microphoneIcon}
204
  </div>
205
 
 
209
  isMini={true}
210
  isActive={true}
211
  isAi={false}
212
+ speakingVolume={volume}
213
+ isUserSpeaking={isSpeaking}
214
  />
215
  </div>
216
  )}