add refresh topic for camera maintainer recycle action

The maintainer's recycle branch is doing an action (recycle the camera)
in response to a section-level signal. Introduce a
CameraConfigUpdateEnum.refresh case as an explicit action signal — the
maintainer subscribes to refresh instead of detect, parallel with add
and remove. Publishers fire refresh alongside detect when a recycle is
needed; section-level subscribers keep their existing topic.

Since no main-process subscriber listens for detect anymore, the
refresh handler calls recreate_ffmpeg_cmds() explicitly so the shared
CameraConfig's ffmpeg_cmds is rebuilt before the new subprocesses
spawn.
This commit is contained in:
Josh Hawkins 2026-05-22 09:11:43 -05:00
parent 03cb07ab68
commit eb1709fa49
3 changed files with 16 additions and 4 deletions

View File

@ -751,7 +751,9 @@ def _config_set_in_memory(request: Request, body: AppConfigSetBody) -> JSONRespo
)
# detect resize also republishes motion + objects so other
# processes pick up the rebuilt masks
# processes pick up the rebuilt masks, and fires refresh so
# the camera maintainer recycles the camera process to pick
# up the new ffmpeg cmd / SHM sizing
if field == "detect":
cam_cfg = config.cameras.get(camera)
if cam_cfg is not None:
@ -768,6 +770,12 @@ def _config_set_in_memory(request: Request, body: AppConfigSetBody) -> JSONRespo
),
cam_cfg.objects,
)
request.app.config_publisher.publish_update(
CameraConfigUpdateTopic(
CameraConfigUpdateEnum.refresh, camera
),
cam_cfg,
)
return JSONResponse(
content={"success": True, "message": "Config applied in-memory"},

View File

@ -51,7 +51,7 @@ class CameraMaintainer(threading.Thread):
[
CameraConfigUpdateEnum.add,
CameraConfigUpdateEnum.remove,
CameraConfigUpdateEnum.detect,
CameraConfigUpdateEnum.refresh,
],
)
self.shm_count = self.__calculate_shm_frame_count()
@ -281,7 +281,7 @@ class CameraMaintainer(threading.Thread):
self.region_grids.pop(camera, None)
self.camera_metrics.pop(camera, None)
self.ptz_metrics.pop(camera, None)
elif update_type == CameraConfigUpdateEnum.detect.name:
elif update_type == CameraConfigUpdateEnum.refresh.name:
# Recycle replay cameras so detect width/height/fps
# propagate through ffmpeg args, SHM sizing, and the
# region grid. Regular cameras detect change still
@ -301,6 +301,10 @@ class CameraMaintainer(threading.Thread):
):
continue
# rebuild ffmpeg cmds on the shared config so the
# new subprocesses spawn with current args
new_config.recreate_ffmpeg_cmds()
self.__stop_camera_capture_process(camera)
self.__stop_camera_process(camera)
self.__unlink_camera_frame_slots(camera)

View File

@ -26,6 +26,7 @@ class CameraConfigUpdateEnum(str, Enum):
object_genai = "object_genai"
onvif = "onvif"
record = "record"
refresh = "refresh" # signals the camera maintainer to recycle the camera process
remove = "remove" # for removing a camera
review = "review"
review_genai = "review_genai"
@ -108,7 +109,6 @@ class CameraConfigUpdateSubscriber:
config.birdseye = updated_config
elif update_type == CameraConfigUpdateEnum.detect:
config.detect = updated_config
config.recreate_ffmpeg_cmds()
elif update_type == CameraConfigUpdateEnum.enabled:
config.enabled = updated_config
elif update_type == CameraConfigUpdateEnum.object_genai: