File size: 3,635 Bytes
9a9d18a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import React, { useEffect, useRef, useState } from "react";
import { Smartphone, WifiOff } from "lucide-react";
import { useApi } from "@/contexts/ApiContext";

interface PhoneCameraFeedProps {
  sessionId: string;
}

const PhoneCameraFeed: React.FC<PhoneCameraFeedProps> = ({ sessionId }) => {
  const { wsBaseUrl } = useApi();
  const videoRef = useRef<HTMLVideoElement>(null);
  const [isConnected, setIsConnected] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const wsRef = useRef<WebSocket | null>(null);
  const mediaSourceRef = useRef<MediaSource | null>(null);

  useEffect(() => {
    if (!sessionId) return;

    const connectWebSocket = () => {
      try {
        const ws = new WebSocket(`${wsBaseUrl}/ws/camera/${sessionId}`);
        wsRef.current = ws;

        ws.onopen = () => {
          console.log("Camera feed WebSocket connected");
          setIsConnected(true);
          setError(null);
        };

        ws.onmessage = (event) => {
          // Handle incoming video chunks
          if (event.data instanceof Blob) {
            handleVideoChunk(event.data);
          } else if (event.data === "camera_connected") {
            setIsConnected(true);
          }
        };

        ws.onclose = () => {
          console.log("Camera feed WebSocket disconnected");
          setIsConnected(false);
        };

        ws.onerror = (error) => {
          console.error("Camera feed WebSocket error:", error);
          setError("Failed to connect to camera feed");
          setIsConnected(false);
        };
      } catch (error) {
        console.error("Failed to create WebSocket:", error);
        setError("Failed to establish connection");
      }
    };

    const handleVideoChunk = (chunk: Blob) => {
      // For now, we'll just log that we received a chunk
      // In a full implementation, this would use MediaSource API
      console.log("Received video chunk:", chunk.size, "bytes");
    };

    connectWebSocket();

    return () => {
      if (wsRef.current) {
        wsRef.current.close();
      }
      if (mediaSourceRef.current) {
        mediaSourceRef.current.endOfStream();
      }
    };
  }, [sessionId]);

  if (error) {
    return (
      <div className="w-full h-32 bg-gray-800 rounded-lg flex flex-col items-center justify-center">
        <WifiOff className="w-6 h-6 text-red-400 mb-2" />
        <p className="text-xs text-red-400 text-center">{error}</p>
      </div>
    );
  }

  if (!isConnected) {
    return (
      <div className="w-full h-32 bg-gray-800 rounded-lg flex flex-col items-center justify-center">
        <Smartphone className="w-6 h-6 text-gray-500 mb-2" />
        <p className="text-xs text-gray-500 text-center">
          Waiting for phone camera...
        </p>
        <div className="w-4 h-4 border-2 border-gray-600 border-t-blue-500 rounded-full animate-spin mt-2"></div>
      </div>
    );
  }

  return (
    <div className="w-full h-32 bg-gray-800 rounded-lg overflow-hidden relative">
      <video
        ref={videoRef}
        className="w-full h-full object-cover"
        autoPlay
        muted
        playsInline
      />
      <div className="absolute top-2 left-2">
        <div className="flex items-center gap-1 bg-black/50 px-2 py-1 rounded text-xs">
          <div className="w-1.5 h-1.5 bg-green-400 rounded-full animate-pulse"></div>
          <span className="text-green-400">LIVE</span>
        </div>
      </div>
      <div className="absolute bottom-2 right-2">
        <Smartphone className="w-4 h-4 text-white/70" />
      </div>
    </div>
  );
};

export default PhoneCameraFeed;