diff --git a/web_viewer/app.py b/web_viewer/app.py index 891b970..a9e0ee7 100644 --- a/web_viewer/app.py +++ b/web_viewer/app.py @@ -29,7 +29,8 @@ frame_lock = asyncio.Lock() active_websocket_clients: Set[WebSocket] = set() streaming_task = None streaming_active = False -PIPE_PATH = '/tmp/beacon_video_stream' +TCP_HOST = '127.0.0.1' +TCP_PORT = 8888 async def init_reader(): @@ -206,55 +207,36 @@ async def latest_frame(): return Response(content="No frame available", status_code=404) -async def stream_video_from_pipe(): +async def stream_video_from_tcp(): """ - Read MPEG-TS video stream from named pipe and broadcast via WebSocket. + Read MPEG-TS video stream from TCP socket and broadcast via WebSocket. This runs as a background task. """ global streaming_active - print(f"Starting video stream reader from: {PIPE_PATH}") + print(f"Starting video stream reader from TCP: {TCP_HOST}:{TCP_PORT}") - # Wait for pipe to be created by C++ application - max_wait_time = 30 # seconds - start_time = time.time() - - while not os.path.exists(PIPE_PATH): - if time.time() - start_time > max_wait_time: - print(f"ERROR: Pipe {PIPE_PATH} not found after {max_wait_time}s") - return - print(f"Waiting for pipe {PIPE_PATH}...") - await asyncio.sleep(1) - - print(f"Pipe found: {PIPE_PATH}") + # Wait a bit for C++ application to start TCP server + await asyncio.sleep(2) try: - # Open the named pipe in binary read mode - print("Opening pipe for reading...") + # Connect to TCP server + print(f"Connecting to TCP server {TCP_HOST}:{TCP_PORT}...") + + reader, writer = await asyncio.open_connection(TCP_HOST, TCP_PORT) + + print("Connected to TCP server, starting stream...") - # Use asyncio to read from pipe streaming_active = True - - # Open pipe in non-blocking mode - import fcntl - pipe_fd = os.open(PIPE_PATH, os.O_RDONLY | os.O_NONBLOCK) - - print("Pipe opened successfully, starting stream...") - chunk_size = 32768 # 32KB chunks for MPEG-TS while streaming_active and active_websocket_clients: try: - # Read chunk from pipe - try: - data = os.read(pipe_fd, chunk_size) - except BlockingIOError: - # No data available, wait a bit - await asyncio.sleep(0.001) - continue + # Read chunk from TCP + data = await asyncio.wait_for(reader.read(chunk_size), timeout=5.0) if not data: - print("No data from pipe, stream may have ended") + print("No data from TCP, stream may have ended") break # Broadcast binary data to all connected WebSocket clients @@ -269,17 +251,19 @@ async def stream_video_from_pipe(): # Remove disconnected clients active_websocket_clients.difference_update(disconnected_clients) - # Small delay to prevent overwhelming clients - await asyncio.sleep(0.001) - + except asyncio.TimeoutError: + # No data in 5 seconds, continue waiting + continue except Exception as e: - print(f"Error reading from pipe: {e}") + print(f"Error reading from TCP: {e}") break - os.close(pipe_fd) + writer.close() + await writer.wait_closed() - except FileNotFoundError: - print(f"ERROR: Pipe {PIPE_PATH} not found") + except ConnectionRefusedError: + print(f"ERROR: Could not connect to TCP server {TCP_HOST}:{TCP_PORT}") + print("Make sure C++ application is running first") except Exception as e: print(f"ERROR in video streaming: {e}") import traceback @@ -302,7 +286,7 @@ async def websocket_video_endpoint(websocket: WebSocket): # Start streaming task if not already running if not streaming_active: - streaming_task = asyncio.create_task(stream_video_from_pipe()) + streaming_task = asyncio.create_task(stream_video_from_tcp()) print("Started video streaming task") try: @@ -339,7 +323,7 @@ async def health(): "status": "healthy", "active_websocket_clients": len(active_websocket_clients), "streaming_active": streaming_active, - "pipe_exists": os.path.exists(PIPE_PATH) + "tcp_endpoint": f"{TCP_HOST}:{TCP_PORT}" } @@ -348,6 +332,7 @@ if __name__ == '__main__': print("Starting FastAPI server on http://0.0.0.0:5000") print(f"Video stream will be available at ws://0.0.0.0:5000/ws/video") + print(f"Expecting C++ TCP stream at {TCP_HOST}:{TCP_PORT}") uvicorn.run( app,