Ezmary commited on
Commit
a9228b4
·
verified ·
1 Parent(s): e8a19cb

Update src/components/control-tray/ControlTray.tsx

Browse files
src/components/control-tray/ControlTray.tsx CHANGED
@@ -36,8 +36,8 @@ const ControlTray: React.FC<ControlTrayProps> = ({
36
  isAppCamActive,
37
  onAppCamToggle,
38
  ReferenceMicrophoneIcon,
39
- currentFacingMode,
40
- setCurrentFacingMode,
41
  }) => {
42
  const { client, connected, connect } = useLiveAPIContext();
43
  const [audioRecorder] = useState(() => new AudioRecorder());
@@ -45,14 +45,48 @@ const ControlTray: React.FC<ControlTrayProps> = ({
45
  const [isSwitchingCamera, setIsSwitchingCamera] = useState(false);
46
  const renderCanvasRef = React.useRef<HTMLCanvasElement>(null);
47
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  useEffect(() => {
49
- if (isAppCamActive && !activeLocalVideoStream && !isSwitchingCamera) {
50
- startWebcam(currentFacingMode); // استفاده از currentFacingMode از پراپ
51
- } else if (!isAppCamActive && activeLocalVideoStream) {
52
- stopWebcam();
 
 
 
 
53
  }
54
  }, [isAppCamActive, activeLocalVideoStream, isSwitchingCamera, currentFacingMode]);
55
 
 
56
  useEffect(() => { /* ... audioRecorder ... */ }, [connected, client, isAppMicActive, audioRecorder]);
57
  useEffect(() => { /* ... sendVideoFrame ... */ }, [connected, activeLocalVideoStream, client, videoRef, renderCanvasRef]);
58
  useEffect(() => { /* ... videoRef.srcObject ... */ }, [activeLocalVideoStream, videoRef]);
@@ -60,56 +94,42 @@ const ControlTray: React.FC<ControlTrayProps> = ({
60
  const ensureConnectedAndReady = async (): Promise<boolean> => { if (!connected) { try { await connect(); return true; } catch (err) { console.error('❌ CT Connect err:', err); return false; } } return true; };
61
  const handleMicToggle = async () => { if (isSwitchingCamera) return; const newMicState = !isAppMicActive; if (newMicState && !(await ensureConnectedAndReady())) { onAppMicToggle(false); return; } onAppMicToggle(newMicState); };
62
 
63
- const startWebcam = async (facingModeToTry: 'user' | 'environment') => {
64
- if (isSwitchingCamera) return;
65
- setIsSwitchingCamera(true);
66
- try {
67
- const mediaStream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: facingModeToTry }, audio: false });
68
- setActiveLocalVideoStream(mediaStream);
69
- onVideoStreamChange(mediaStream);
70
- // setCurrentFacingMode در اینجا نباید مستقیما ست شود، چون از پراپ می آید و در handleSwitchCamera و handleCamToggle مدیریت می شود
71
- } catch (error) {
72
- console.error(`❌ Start WC err ${facingModeToTry}:`, error);
73
- setActiveLocalVideoStream(null); onVideoStreamChange(null); onAppCamToggle(false);
74
- } finally { setIsSwitchingCamera(false); }
75
- };
76
-
77
- const stopWebcam = () => { if (activeLocalVideoStream) activeLocalVideoStream.getTracks().forEach(track => track.stop()); setActiveLocalVideoStream(null); onVideoStreamChange(null); };
78
-
79
  const handleCamToggle = async () => {
80
  if (isSwitchingCamera) return;
81
  const newCamState = !isAppCamActive;
82
- if (newCamState) {
83
- if (!(await ensureConnectedAndReady())) { onAppCamToggle(false); return; }
84
- if (!isAppMicActive) { onAppMicToggle(true); }
85
- onAppCamToggle(true); // این باعث اجرای useEffect برای startWebcam با currentFacingMode فعلی می شود
86
- } else {
87
- onAppCamToggle(false);
 
 
 
 
 
 
 
88
  }
89
  };
90
 
91
  const handleSwitchCamera = async () => {
92
  if (!isAppCamActive || !activeLocalVideoStream || isSwitchingCamera) return;
93
- setIsSwitchingCamera(true);
94
  const targetFacingMode = currentFacingMode === 'user' ? 'environment' : 'user';
95
- activeLocalVideoStream.getTracks().forEach(track => track.stop());
96
- try {
97
- const newStream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: { exact: targetFacingMode } }, audio: false });
98
- setActiveLocalVideoStream(newStream);
99
- onVideoStreamChange(newStream);
100
- setCurrentFacingMode(targetFacingMode); // آپدیت state در App.tsx
101
- } catch (error) {
102
- console.error(`❌ Switch Cam err ${targetFacingMode}:`, error);
103
- try {
104
- const restoredStream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: currentFacingMode }, audio: false }); // بازگشت به دوربین قبلی
105
- setActiveLocalVideoStream(restoredStream);
106
- onVideoStreamChange(restoredStream);
107
- // setCurrentFacingMode تغییر نمی کند
108
- } catch (restoreError) {
109
- console.error('❌ Restore Cam err:', restoreError);
110
- setActiveLocalVideoStream(null); onVideoStreamChange(null); onAppCamToggle(false);
111
- }
112
- } finally { setIsSwitchingCamera(false); }
113
  };
114
 
115
  return (
 
36
  isAppCamActive,
37
  onAppCamToggle,
38
  ReferenceMicrophoneIcon,
39
+ currentFacingMode, // دریافت از AppCore
40
+ setCurrentFacingMode, // دریافت از AppCore
41
  }) => {
42
  const { client, connected, connect } = useLiveAPIContext();
43
  const [audioRecorder] = useState(() => new AudioRecorder());
 
45
  const [isSwitchingCamera, setIsSwitchingCamera] = useState(false);
46
  const renderCanvasRef = React.useRef<HTMLCanvasElement>(null);
47
 
48
+ const _startWebcam = async (facingModeToTry: 'user' | 'environment') => {
49
+ if (isSwitchingCamera) return null; // برگرداندن null اگر در حال تعویض دوربین هستیم
50
+ setIsSwitchingCamera(true);
51
+ try {
52
+ const mediaStream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: facingModeToTry }, audio: false });
53
+ setActiveLocalVideoStream(mediaStream);
54
+ onVideoStreamChange(mediaStream);
55
+ // setCurrentFacingMode در اینجا ست نمی‌شود، چون توسط handleSwitchCamera یا handleCamToggle مدیریت می‌شود
56
+ return mediaStream; // برگرداندن استریم برای استفاده در توابع دیگر
57
+ } catch (error) {
58
+ console.error(`❌ Start WC err ${facingModeToTry}:`, error);
59
+ setActiveLocalVideoStream(null);
60
+ onVideoStreamChange(null);
61
+ onAppCamToggle(false); // خاموش کردن دوربین در App.tsx اگر خطا رخ داد
62
+ return null;
63
+ } finally {
64
+ setIsSwitchingCamera(false);
65
+ }
66
+ };
67
+
68
+ const _stopWebcam = () => {
69
+ if (activeLocalVideoStream) {
70
+ activeLocalVideoStream.getTracks().forEach(track => track.stop());
71
+ }
72
+ setActiveLocalVideoStream(null);
73
+ onVideoStreamChange(null);
74
+ };
75
+
76
+ // useEffect برای مدیریت روشن/خاموش شدن دوربین بر اساس isAppCamActive
77
  useEffect(() => {
78
+ if (isAppCamActive) {
79
+ if (!activeLocalVideoStream && !isSwitchingCamera) {
80
+ _startWebcam(currentFacingMode); // استفاده از currentFacingMode از state والد
81
+ }
82
+ } else {
83
+ if (activeLocalVideoStream) {
84
+ _stopWebcam();
85
+ }
86
  }
87
  }, [isAppCamActive, activeLocalVideoStream, isSwitchingCamera, currentFacingMode]);
88
 
89
+
90
  useEffect(() => { /* ... audioRecorder ... */ }, [connected, client, isAppMicActive, audioRecorder]);
91
  useEffect(() => { /* ... sendVideoFrame ... */ }, [connected, activeLocalVideoStream, client, videoRef, renderCanvasRef]);
92
  useEffect(() => { /* ... videoRef.srcObject ... */ }, [activeLocalVideoStream, videoRef]);
 
94
  const ensureConnectedAndReady = async (): Promise<boolean> => { if (!connected) { try { await connect(); return true; } catch (err) { console.error('❌ CT Connect err:', err); return false; } } return true; };
95
  const handleMicToggle = async () => { if (isSwitchingCamera) return; const newMicState = !isAppMicActive; if (newMicState && !(await ensureConnectedAndReady())) { onAppMicToggle(false); return; } onAppMicToggle(newMicState); };
96
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  const handleCamToggle = async () => {
98
  if (isSwitchingCamera) return;
99
  const newCamState = !isAppCamActive;
100
+
101
+ if (newCamState) { // روشن کردن دوربین
102
+ if (!(await ensureConnectedAndReady())) {
103
+ onAppCamToggle(false); // آپدیت state در App.tsx
104
+ return;
105
+ }
106
+ if (!isAppMicActive) {
107
+ onAppMicToggle(true); // فعال کردن میکروفون اگر خاموش است
108
+ }
109
+ onAppCamToggle(true); // این باعث می‌شود useEffect بالا _startWebcam را فراخوانی کند
110
+ // با currentFacingMode فعلی که از App.tsx می‌آید.
111
+ } else { // خاموش کردن دوربین
112
+ onAppCamToggle(false); // این باعث می‌شود useEffect بالا _stopWebcam را فراخوانی کند
113
  }
114
  };
115
 
116
  const handleSwitchCamera = async () => {
117
  if (!isAppCamActive || !activeLocalVideoStream || isSwitchingCamera) return;
118
+
119
  const targetFacingMode = currentFacingMode === 'user' ? 'environment' : 'user';
120
+ _stopWebcam(); // ابتدا استریم فعلی را متوقف کن
121
+
122
+ // کمی تاخیر برای اطمینان از آزاد شدن دوربین قبل از درخواست جدید
123
+ await new Promise(resolve => setTimeout(resolve, 100));
124
+
125
+ const newStream = await _startWebcam(targetFacingMode); // تلاش برای شروع با دوربین جدید
126
+ if (newStream) {
127
+ setCurrentFacingMode(targetFacingMode); // آپدیت state در App.tsx فقط در صورت موفقیت
128
+ } else {
129
+ // اگر شروع با دوربین جدید ناموفق بود، سعی کن به دوربین قبلی برگردی
130
+ // (currentFacingMode هنوز مقدار قبلی را دارد)
131
+ await _startWebcam(currentFacingMode);
132
+ }
 
 
 
 
 
133
  };
134
 
135
  return (