Skip to content

Commit 38edf1e

Browse files
committed
fixes
1 parent 28eb926 commit 38edf1e

File tree

1 file changed

+31
-22
lines changed

1 file changed

+31
-22
lines changed

src/arduino/app_peripherals/camera/websocket_camera.py

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@ async def _start_server(self) -> None:
125125
ping_interval=20,
126126
)
127127

128+
# Get the actual port if OS assigned one (e.g., when port=0)
129+
if self.port == 0:
130+
server_socket = list(self._server.sockets)[0]
131+
self.port = server_socket.getsockname()[1]
132+
128133
logger.info(f"WebSocket camera server started on {self.host}:{self.port}")
129134

130135
await self._stop_event.wait()
@@ -171,7 +176,7 @@ async def _ws_handler(self, conn: websockets.ServerConnection) -> None:
171176
logger.warning(f"Could not send welcome message to {client_addr}: {e}")
172177

173178
async for message in conn:
174-
frame = await self._parse_message(message)
179+
frame = self._parse_message(message)
175180
if frame is not None:
176181
# Drop old frames until there's room for the new one
177182
while True:
@@ -195,28 +200,29 @@ async def _ws_handler(self, conn: websockets.ServerConnection) -> None:
195200
self._client = None
196201
logger.info(f"Client removed: {client_addr}")
197202

198-
async def _parse_message(self, message) -> np.ndarray | None:
203+
def _parse_message(self, message: str | bytes) -> np.ndarray | None:
199204
"""Parse WebSocket message to extract frame."""
200205
try:
201-
if self.frame_format == "base64":
202-
# Expect base64 encoded image
206+
if self.frame_format == "binary":
207+
# Expect raw binary image data
203208
if isinstance(message, str):
204-
image_data = base64.b64decode(message)
209+
# Use latin-1 encoding to preserve binary data
210+
image_data = message.encode("latin-1")
205211
else:
206-
image_data = base64.b64decode(message.decode())
212+
image_data = message
207213

208-
# Decode image
209214
nparr = np.frombuffer(image_data, np.uint8)
210215
frame = cv2.imdecode(nparr, cv2.IMREAD_UNCHANGED)
211216
return frame
212217

213-
elif self.frame_format == "binary":
214-
# Expect raw binary image data
218+
elif self.frame_format == "base64":
219+
# Expect base64 encoded image
215220
if isinstance(message, str):
216-
image_data = message.encode()
221+
image_data = base64.b64decode(message)
217222
else:
218-
image_data = message
223+
image_data = base64.b64decode(message.decode())
219224

225+
# Decode image
220226
nparr = np.frombuffer(image_data, np.uint8)
221227
frame = cv2.imdecode(nparr, cv2.IMREAD_UNCHANGED)
222228
return frame
@@ -251,10 +257,11 @@ async def _parse_message(self, message) -> np.ndarray | None:
251257

252258
def _close_camera(self):
253259
"""Stop the WebSocket server."""
254-
if self._loop and not self._loop.is_closed():
260+
# Only attempt async cleanup if the event loop is running
261+
if self._loop and not self._loop.is_closed() and self._loop.is_running():
255262
try:
256263
future = asyncio.run_coroutine_threadsafe(self._stop_and_disconnect_client(), self._loop)
257-
future.result(timeout=1.0)
264+
future.result(1.0)
258265
except CancelledError:
259266
logger.debug(f"Error stopping WebSocket server: CancelledError")
260267
except TimeoutError:
@@ -293,7 +300,8 @@ async def _stop_and_disconnect_client(self):
293300
except Exception as e:
294301
logger.warning(f"Error closing client in stop event: {e}")
295302
finally:
296-
await self._client.close()
303+
if self._client:
304+
await self._client.close()
297305

298306
self._stop_event.set()
299307

@@ -308,14 +316,15 @@ def _read_frame(self) -> np.ndarray | None:
308316

309317
async def _send_to_client(self, message: str | bytes | dict) -> None:
310318
"""Send a message to the connected client."""
311-
if self._client is None:
312-
raise ConnectionError("No client connected to send message to")
313-
314319
if isinstance(message, dict):
315320
message = json.dumps(message)
316321

317-
try:
318-
await self._client.send(message)
319-
except Exception as e:
320-
logger.warning(f"Error sending to client: {e}")
321-
raise
322+
async with self._client_lock:
323+
if self._client is None:
324+
raise ConnectionError("No client connected to send message to")
325+
326+
try:
327+
await self._client.send(message)
328+
except Exception as e:
329+
logger.warning(f"Error sending to client: {e}")
330+
raise

0 commit comments

Comments
 (0)