2424
2525import os
2626
27+ import numpy as np
28+
2729from arduino .app_peripherals .camera import Camera
30+ from arduino .app_utils .image .image_editor import ImageEditor
2831
2932sys .path .insert (0 , os .path .join (os .path .dirname (__file__ ), '..' , '..' , '..' , '..' ))
3033
@@ -53,48 +56,37 @@ async def connect_output_tcp(output_host: str, output_port: int):
5356 """Connect to the output TCP server."""
5457 global output_writer , output_reader
5558
56- logger .info (f"Connecting to TCP server at { output_host } :{ output_port } ..." )
59+ logger .info (f"Connecting to output server at { output_host } :{ output_port } ..." )
5760
5861 try :
5962 output_reader , output_writer = await asyncio .open_connection (
6063 output_host , output_port
6164 )
62- logger .info ("TCP connection established successfully" )
63-
64- return True
65+ logger .info ("Connected successfully to output server" )
6566
6667 except Exception as e :
67- logger .error (f"Failed to connect to TCP server: { e } " )
68- return False
68+ raise Exception (f"Failed to connect to output server: { e } " )
6969
7070
71- async def forward_frame (frame , quality : int ):
71+ async def forward_frame (frame : np . ndarray ):
7272 """Forward a frame to the output TCP server as raw JPEG."""
7373 global output_writer
7474
7575 if not output_writer or output_writer .is_closing ():
7676 return
7777
7878 try :
79- # Frame is already a PIL.Image.Image in JPEG format
80- # Convert PIL image to bytes
81- import io
82- img_bytes = io .BytesIO ()
83- frame .save (img_bytes , format = 'JPEG' , quality = quality )
84- frame_data = img_bytes .getvalue ()
85-
86- # Send raw JPEG binary data
87- output_writer .write (frame_data )
79+ output_writer .write (frame .tobytes ())
8880 await output_writer .drain ()
8981
9082 except ConnectionResetError :
91- logger .warning ("TCP connection reset while forwarding frame" )
83+ logger .warning ("Output connection reset while forwarding frame" )
9284 output_writer = None
9385 except Exception as e :
9486 logger .error (f"Error forwarding frame: { e } " )
9587
9688
97- async def camera_loop (fps : int , quality : int ):
89+ async def camera_loop (fps : int ):
9890 """Main camera capture and forwarding loop."""
9991 global running , camera
10092
@@ -111,21 +103,26 @@ async def camera_loop(fps: int, quality: int):
111103 try :
112104 # Read frame from WebSocketCamera
113105 frame = camera .capture ()
114-
115- if frame is not None :
116- # Rate limiting
117- current_time = time .time ()
118- time_since_last = current_time - last_frame_time
119- if time_since_last < frame_interval :
120- await asyncio .sleep (frame_interval - time_since_last )
121-
122- last_frame_time = time .time ()
123-
124- # Forward frame if output TCP connection is available
125- await forward_frame (frame , quality )
126- else :
106+ # frame = ImageEditor.compress_to_jpeg(frame, 80.1)
107+ if frame is None :
127108 # No frame available, small delay to avoid busy waiting
128109 await asyncio .sleep (0.01 )
110+ continue
111+
112+ # Rate limiting
113+ current_time = time .time ()
114+ time_since_last = current_time - last_frame_time
115+ if time_since_last < frame_interval :
116+ await asyncio .sleep (frame_interval - time_since_last )
117+
118+ last_frame_time = time .time ()
119+
120+ if output_writer is None or output_writer .is_closing ():
121+ # Output connection is not available, give room to the other tasks
122+ await asyncio .sleep (0.01 )
123+ else :
124+ # Forward frame if output connection is available
125+ await forward_frame (frame )
129126
130127 except Exception as e :
131128 logger .error (f"Error in camera loop: { e } " )
@@ -138,18 +135,16 @@ async def maintain_output_connection(output_host: str, output_port: int, reconne
138135
139136 while running :
140137 try :
141- # Establish connection
142- if await connect_output_tcp (output_host , output_port ):
143- logger .info ("TCP connection established, maintaining..." )
138+ await connect_output_tcp (output_host , output_port )
139+
140+ # Keep monitoring
141+ while running and output_writer and not output_writer .is_closing ():
142+ await asyncio .sleep (1.0 )
144143
145- # Keep connection alive
146- while running and output_writer and not output_writer .is_closing ():
147- await asyncio .sleep (1.0 )
148-
149- logger .info ("TCP connection lost" )
144+ logger .info ("Lost connection to output server" )
150145
151146 except Exception as e :
152- logger .error (f"TCP connection error: { e } " )
147+ logger .error (e )
153148 finally :
154149 # Clean up connection
155150 if output_writer :
@@ -163,7 +158,7 @@ async def maintain_output_connection(output_host: str, output_port: int, reconne
163158
164159 # Wait before reconnecting
165160 if running :
166- logger .info (f"Reconnecting to TCP server in { reconnect_delay } seconds..." )
161+ logger .info (f"Reconnecting to output server in { reconnect_delay } seconds..." )
167162 await asyncio .sleep (reconnect_delay )
168163
169164
@@ -172,10 +167,12 @@ async def main():
172167 global running , camera
173168
174169 parser = argparse .ArgumentParser (description = "WebSocket Camera Proxy" )
170+ parser .add_argument ("--input-host" , default = "localhost" ,
171+ help = "WebSocketCamera input host (default: localhost)" )
175172 parser .add_argument ("--input-port" , type = int , default = 8080 ,
176173 help = "WebSocketCamera input port (default: 8080)" )
177- parser .add_argument ("--output-host" , default = "0.0.0.0 " ,
178- help = "Output TCP server host (default: 0.0.0.0 )" )
174+ parser .add_argument ("--output-host" , default = "localhost " ,
175+ help = "Output TCP server host (default: localhost )" )
179176 parser .add_argument ("--output-port" , type = int , default = 5000 ,
180177 help = "Output TCP server port (default: 5000)" )
181178 parser .add_argument ("--fps" , type = int , default = 30 ,
@@ -204,11 +201,12 @@ async def main():
204201 logger .info (f"Target FPS: { args .fps } " )
205202
206203 from arduino .app_utils .image .image_editor import compressed_to_jpeg
207- camera = Camera ("ws://0.0.0.0:5000" , transformer = compressed_to_jpeg (80 ))
204+ camera = Camera (f"ws://{ args .input_host } :{ args .input_port } " , adjuster = compressed_to_jpeg (80 ))
205+ # camera = Camera(f"ws://{args.input_host}:{args.input_port}")
208206
209207 try :
210208 # Start camera input and output connection tasks
211- camera_task = asyncio .create_task (camera_loop (args .fps , args . quality ))
209+ camera_task = asyncio .create_task (camera_loop (args .fps ))
212210 connection_task = asyncio .create_task (maintain_output_connection (args .output_host , args .output_port , reconnect_delay ))
213211
214212 # Run both tasks concurrently
0 commit comments