Fix DDP streaming and capture thread safety

- Fix WLED DDP config: use lor=0 (live overrides effects), remove
  live flag (read-only, causes issues on 0.15.x), disable PUSH flag
  which broke rendering on WLED 0.15.x
- Use dedicated single-thread executor for capture engine calls to
  fix thread-local state issues with BetterCam/MSS/DXcam
- Sync processor state on stream/template change even when stopped,
  preventing stale engine references on next start
- Add diagnostic logging for frame sends and DDP packets

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-12 01:27:01 +03:00
parent 4c21ae5178
commit a4991c884a
4 changed files with 75 additions and 28 deletions

View File

@@ -427,14 +427,29 @@ async def update_device(
picture_stream_id=update_data.picture_stream_id,
)
# Hot-swap: If stream/template changed and device was processing, restart it
if (stream_changed or template_changed) and was_processing:
logger.info(f"Hot-swapping stream/template for device {device_id}")
try:
# Stop current processing
await manager.stop_processing(device_id)
# Update processor with new settings
# Sync processor state when stream/template changed
if stream_changed or template_changed:
if was_processing:
# Hot-swap: restart with new settings
logger.info(f"Hot-swapping stream/template for device {device_id}")
try:
await manager.stop_processing(device_id)
manager.remove_device(device_id)
manager.add_device(
device_id=device.id,
device_url=device.url,
led_count=device.led_count,
settings=device.settings,
calibration=device.calibration,
capture_template_id=device.capture_template_id,
picture_stream_id=device.picture_stream_id,
)
await manager.start_processing(device_id)
logger.info(f"Successfully hot-swapped stream/template for device {device_id}")
except Exception as e:
logger.error(f"Error during template hot-swap: {e}")
else:
# Not processing — update processor state so next start uses new values
manager.remove_device(device_id)
manager.add_device(
device_id=device.id,
@@ -446,14 +461,6 @@ async def update_device(
picture_stream_id=device.picture_stream_id,
)
# Restart processing
await manager.start_processing(device_id)
logger.info(f"Successfully hot-swapped stream/template for device {device_id}")
except Exception as e:
logger.error(f"Error during template hot-swap: {e}")
# Device is stopped but updated - user can manually restart
return DeviceResponse(
id=device.id,
name=device.name,