mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-05 10:45:21 +03:00
Use api instead of event queue to save audio events
This commit is contained in:
parent
f0a59da933
commit
cc0cb3a78d
@ -395,7 +395,7 @@ class FrigateApp:
|
||||
audio_process = mp.Process(
|
||||
target=listen_to_audio,
|
||||
name=f"audio_capture",
|
||||
args=(self.config, self.event_queue)
|
||||
args=(self.config)
|
||||
)
|
||||
audio_process.daemon = True
|
||||
audio_process.start()
|
||||
|
||||
@ -6,9 +6,9 @@ import multiprocessing as mp
|
||||
import numpy as np
|
||||
import os
|
||||
import random
|
||||
import requests
|
||||
import signal
|
||||
import string
|
||||
import subprocess as sp
|
||||
import threading
|
||||
from types import FrameType
|
||||
from typing import Optional
|
||||
@ -17,7 +17,6 @@ from setproctitle import setproctitle
|
||||
|
||||
from frigate.config import CameraConfig, FrigateConfig
|
||||
from frigate.const import (
|
||||
AUDIO_DETECTOR,
|
||||
AUDIO_DURATION,
|
||||
AUDIO_FORMAT,
|
||||
AUDIO_SAMPLE_RATE,
|
||||
@ -42,7 +41,7 @@ FFMPEG_COMMAND = (
|
||||
)
|
||||
|
||||
|
||||
def listen_to_audio(config: FrigateConfig, event_queue: mp.Queue) -> None:
|
||||
def listen_to_audio(config: FrigateConfig) -> None:
|
||||
stop_event = mp.Event()
|
||||
|
||||
def receiveSignal(signalNumber: int, frame: Optional[FrameType]) -> None:
|
||||
@ -57,7 +56,7 @@ def listen_to_audio(config: FrigateConfig, event_queue: mp.Queue) -> None:
|
||||
|
||||
for camera in config.cameras.values():
|
||||
if camera.enabled and camera.audio.enabled:
|
||||
AudioEventMaintainer(camera, event_queue, stop_event).start()
|
||||
AudioEventMaintainer(camera, stop_event).start()
|
||||
|
||||
|
||||
class AudioTfl:
|
||||
@ -116,13 +115,10 @@ class AudioTfl:
|
||||
|
||||
|
||||
class AudioEventMaintainer(threading.Thread):
|
||||
def __init__(
|
||||
self, camera: CameraConfig, event_queue: mp.Queue, stop_event: mp.Event
|
||||
) -> None:
|
||||
def __init__(self, camera: CameraConfig, stop_event: mp.Event) -> None:
|
||||
threading.Thread.__init__(self)
|
||||
self.name = f"{camera.name}_audio_event_processor"
|
||||
self.config = camera
|
||||
self.queue = event_queue
|
||||
self.detections: dict[dict[str, any]] = {}
|
||||
self.stop_event = stop_event
|
||||
self.detector = AudioTfl()
|
||||
@ -161,35 +157,31 @@ class AudioEventMaintainer(threading.Thread):
|
||||
"last_detection"
|
||||
] = datetime.datetime.now().timestamp()
|
||||
else:
|
||||
now = datetime.datetime.now().timestamp()
|
||||
rand_id = "".join(
|
||||
random.choices(string.ascii_lowercase + string.digits, k=6)
|
||||
)
|
||||
event_id = f"{now}-{rand_id}"
|
||||
self.detections[label] = {
|
||||
"id": event_id,
|
||||
"label": label,
|
||||
"camera": self.config.name,
|
||||
"score": score,
|
||||
"start_time": now - self.config.record.events.pre_capture,
|
||||
"last_detection": now,
|
||||
}
|
||||
self.queue.put(
|
||||
(EventTypeEnum.audio, "start", self.config.name, self.detections[label])
|
||||
resp = requests.post(
|
||||
f"http://127.0.0.1:5000/api/events/{self.config.name}/{label}/create",
|
||||
json={"duration": None},
|
||||
)
|
||||
|
||||
if resp.status_code == 200:
|
||||
event_id = resp.json["event_id"]
|
||||
self.detections[label] = {
|
||||
"id": event_id,
|
||||
"last_detection": datetime.datetime.now().timestamp(),
|
||||
}
|
||||
|
||||
def expire_detections(self) -> None:
|
||||
now = datetime.datetime.now().timestamp()
|
||||
|
||||
for detection in self.detections.values():
|
||||
if now - detection["last_detection"] > self.config.audio.max_not_heard:
|
||||
detection["end_time"] = (
|
||||
detection["last_detection"] + self.config.record.events.post_capture
|
||||
)
|
||||
self.queue.put(
|
||||
(EventTypeEnum.audio, "end", self.config.name, detection)
|
||||
)
|
||||
self.detections[detection["label"]] = None
|
||||
requests.put(
|
||||
f"http://127.0.0.1/api/events/{detection['event_id']}/end",
|
||||
json={
|
||||
"end_time": detection["last_detection"]
|
||||
+ self.config.record.events.post_capture
|
||||
},
|
||||
)
|
||||
|
||||
def restart_audio_pipe(self) -> None:
|
||||
try:
|
||||
|
||||
@ -67,11 +67,10 @@ class ExternalEventProcessor:
|
||||
|
||||
return event_id
|
||||
|
||||
def finish_manual_event(self, event_id: str) -> None:
|
||||
def finish_manual_event(self, event_id: str, end_time: float) -> None:
|
||||
"""Finish external event with indeterminate duration."""
|
||||
now = datetime.datetime.now().timestamp()
|
||||
self.queue.put(
|
||||
(EventTypeEnum.api, "end", None, {"id": event_id, "end_time": now})
|
||||
(EventTypeEnum.api, "end", None, {"id": event_id, "end_time": end_time})
|
||||
)
|
||||
|
||||
def _write_images(
|
||||
|
||||
@ -17,7 +17,6 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
class EventTypeEnum(str, Enum):
|
||||
api = "api"
|
||||
audio = "audio"
|
||||
tracked_object = "tracked_object"
|
||||
|
||||
|
||||
@ -92,8 +91,6 @@ class EventProcessor(threading.Thread):
|
||||
continue
|
||||
|
||||
self.handle_object_detection(event_type, camera, event_data)
|
||||
elif source_type == EventTypeEnum.audio:
|
||||
self.handle_audio_detection(event_type, event_data)
|
||||
elif source_type == EventTypeEnum.api:
|
||||
self.handle_external_detection(event_type, event_data)
|
||||
|
||||
@ -218,30 +215,6 @@ class EventProcessor(threading.Thread):
|
||||
del self.events_in_process[event_data["id"]]
|
||||
self.event_processed_queue.put((event_data["id"], camera))
|
||||
|
||||
def handle_audio_detection(self, type: str, event_data: Event) -> None:
|
||||
event = {
|
||||
Event.id: event_data["id"],
|
||||
Event.label: event_data["label"],
|
||||
Event.score: event_data["score"],
|
||||
Event.camera: event_data["camera"],
|
||||
Event.start_time: event_data["start_time"],
|
||||
Event.end_time: event_data.get("end_time"),
|
||||
Event.thumbnail: "",
|
||||
Event.has_clip: True,
|
||||
Event.has_snapshot: True,
|
||||
Event.zones: [],
|
||||
Event.data: {},
|
||||
}
|
||||
|
||||
(
|
||||
Event.insert(event)
|
||||
.on_conflict(
|
||||
conflict_target=[Event.id],
|
||||
update=event,
|
||||
)
|
||||
.execute()
|
||||
)
|
||||
|
||||
def handle_external_detection(self, type: str, event_data: Event) -> None:
|
||||
if type == "new":
|
||||
event = {
|
||||
@ -257,20 +230,14 @@ class EventProcessor(threading.Thread):
|
||||
Event.zones: [],
|
||||
Event.data: {},
|
||||
}
|
||||
Event.insert(event).execute()
|
||||
elif type == "end":
|
||||
event = {
|
||||
Event.id: event_data["id"],
|
||||
Event.end_time: event_data["end_time"],
|
||||
}
|
||||
|
||||
try:
|
||||
(
|
||||
Event.insert(event)
|
||||
.on_conflict(
|
||||
conflict_target=[Event.id],
|
||||
update=event,
|
||||
)
|
||||
.execute()
|
||||
)
|
||||
except Exception:
|
||||
logger.warning(f"Failed to update manual event: {event_data['id']}")
|
||||
try:
|
||||
Event.update(event).execute()
|
||||
except Exception:
|
||||
logger.warning(f"Failed to update manual event: {event_data['id']}")
|
||||
|
||||
@ -890,8 +890,11 @@ def create_event(camera_name, label):
|
||||
|
||||
@bp.route("/events/<event_id>/end", methods=["PUT"])
|
||||
def end_event(event_id):
|
||||
json: dict[str, any] = request.get_json(silent=True) or {}
|
||||
|
||||
try:
|
||||
current_app.external_processor.finish_manual_event(event_id)
|
||||
end_time = json.get("end_time", datetime.now().timestamp())
|
||||
current_app.external_processor.finish_manual_event(event_id, end_time)
|
||||
except Exception:
|
||||
return jsonify(
|
||||
{"success": False, "message": f"{event_id} must be set and valid."}, 404
|
||||
|
||||
Loading…
Reference in New Issue
Block a user