From ad0e89e147de72f60569a5b005d7afad2032d361 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Wed, 5 Mar 2025 07:30:23 -0600 Subject: [PATCH] Ensure disabling a camera also disables audio detection (#16961) * Ensure disabling a camera also disables audio detection * fix enabled state * fix path --- frigate/events/audio.py | 56 ++++++++++++++++++++++++++++++++++++++++- frigate/video.py | 7 +++--- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/frigate/events/audio.py b/frigate/events/audio.py index 7675f821b..505802b8c 100644 --- a/frigate/events/audio.py +++ b/frigate/events/audio.py @@ -135,8 +135,13 @@ class AudioEventMaintainer(threading.Thread): # create communication for audio detections self.requestor = InterProcessRequestor() self.config_subscriber = ConfigSubscriber(f"config/audio/{camera.name}") + self.enabled_subscriber = ConfigSubscriber( + f"config/enabled/{camera.name}", True + ) self.detection_publisher = DetectionPublisher(DetectionTypeEnum.audio) + self.was_enabled = camera.enabled + def detect_audio(self, audio) -> None: if not self.config.audio.enabled or self.stop_event.is_set(): return @@ -248,6 +253,23 @@ class AudioEventMaintainer(threading.Thread): f"Failed to end audio event {detection['id']} with status code {resp.status_code}" ) + def expire_all_detections(self) -> None: + """Immediately end all current detections""" + now = datetime.datetime.now().timestamp() + for label, detection in list(self.detections.items()): + if detection: + self.requestor.send_data(f"{self.config.name}/audio/{label}", "OFF") + resp = requests.put( + f"{FRIGATE_LOCALHOST}/api/events/{detection['id']}/end", + json={"end_time": now}, + ) + if resp.status_code == 200: + self.detections[label] = None + else: + self.logger.warning( + f"Failed to end audio event {detection['id']} with status code {resp.status_code}" + ) + def start_or_restart_ffmpeg(self) -> None: self.audio_listener = start_or_restart_ffmpeg( self.ffmpeg_cmd, @@ -283,10 +305,41 @@ class AudioEventMaintainer(threading.Thread): self.logger.error(f"Error reading audio data from ffmpeg process: {e}") log_and_restart() + def _update_enabled_state(self) -> bool: + """Fetch the latest config and update enabled state.""" + _, config_data = self.enabled_subscriber.check_for_update() + if config_data: + self.config.enabled = config_data.enabled + return config_data.enabled + + return self.config.enabled + def run(self) -> None: - self.start_or_restart_ffmpeg() + if self._update_enabled_state(): + self.start_or_restart_ffmpeg() while not self.stop_event.is_set(): + enabled = self._update_enabled_state() + if enabled != self.was_enabled: + if enabled: + self.logger.debug( + f"Enabling audio detections for {self.config.name}" + ) + self.start_or_restart_ffmpeg() + else: + self.logger.debug( + f"Disabling audio detections for {self.config.name}, ending events" + ) + self.expire_all_detections() + stop_ffmpeg(self.audio_listener, self.logger) + self.audio_listener = None + self.was_enabled = enabled + continue + + if not enabled: + time.sleep(0.1) + continue + # check if there is an updated config ( updated_topic, @@ -302,6 +355,7 @@ class AudioEventMaintainer(threading.Thread): self.logpipe.close() self.requestor.stop() self.config_subscriber.stop() + self.enabled_subscriber.stop() self.detection_publisher.stop() diff --git a/frigate/video.py b/frigate/video.py index 69f6c1bfa..89543e21a 100755 --- a/frigate/video.py +++ b/frigate/video.py @@ -197,9 +197,10 @@ class CameraWatchdog(threading.Thread): """Fetch the latest config and update enabled state.""" _, config_data = self.config_subscriber.check_for_update() if config_data: - enabled = config_data.enabled - return enabled - return self.was_enabled if self.was_enabled is not None else self.config.enabled + self.config.enabled = config_data.enabled + return config_data.enabled + + return self.config.enabled def run(self): if self._update_enabled_state():