A distributed urban acoustic monitoring system backend that processes real-time audio data from edge sensors, detects threats using machine learning, and provides spatial incident tracking with real-time WebSocket updates.
The Acoustic Guard Hub is built on an event-driven architecture designed for high-throughput real-time data processing:
- Event-Driven Messaging: RabbitMQ acts as the central message broker, ingesting audio frames and telemetry events from distributed edge sensors
- Spatial Data Handling: PostgreSQL with PostGIS extension enables geospatial queries for incident correlation and bounding box filtering
- Real-Time Updates: WebSocket broadcasting pushes live telemetry, sensor status changes, and incident updates to connected frontend clients
- Layered Architecture: Clean separation between controllers (REST API), services (business logic), repositories ( data access), and messaging consumers (event processing)
- Java 21: Modern Java with record types, pattern matching, and enhanced switch expressions
- Spring Boot 3.3: Framework for dependency injection, transaction management, and WebSocket support
- PostgreSQL 15 with PostGIS 3.3: Spatial database for storing sensor locations, incidents, and enabling geospatial queries
- RabbitMQ 4.3: Message broker for asynchronous audio frame and telemetry event processing
- Testcontainers 1.19.8: Integration testing with Docker containers for PostgreSQL and RabbitMQ
- MapStruct 1.6: Compile-time bean mapping for DTO/entity conversions
- JUnit 5 & Mockito 5.8: Enterprise-grade testing framework with BDD-style nested tests
- gRPC: Communication protocol for the threat classification microservice
- Liquibase: Database migration management
- Docker Desktop: Required for running PostgreSQL, PostGIS, and RabbitMQ containers
- JDK 21: Java Development Kit version 21 or higher
- Gradle 9.4: Build tool (wrapper included in project)
The project uses a Git submodule for protobuf files. After cloning the repository, initialize the submodule:
git submodule update --init --recursiveThis will download the proto files from https://github.com/Acoustic-Guard/proto.git into the proto/ directory.
Start the required Docker containers for PostgreSQL, PostGIS, and RabbitMQ:
docker-compose up -dThis will start:
- PostgreSQL 15 with PostGIS 3.3 extension on port 5432
- RabbitMQ 4.3 with management UI on port 5672 (AMQP) and 15672 (management)
The application uses environment variables or application.yml for configuration. Key configuration properties:
spring:
datasource:
url: jdbc:postgresql://localhost:5432/acoustic_guard
username: acoustic_guard
password: acoustic_guard
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
acoustic:
classifier:
confidence-threshold: 0.10
sensor:
heartbeat-timeout-seconds: 60
incident:
spatial-threshold-meters: 500
temporal-threshold-seconds: 300./gradlew bootRunThe application will start on http://localhost:8080
OpenAPI/Swagger documentation is available at:
http://localhost:8080/swagger-ui.html
The project uses Testcontainers for integration testing, which requires Docker to be running.
./gradlew test./gradlew test --tests "*IncidentServiceImplTest"
./gradlew test --tests "*TelemetryServiceImplTest"
./gradlew test --tests "*SensorMonitorServiceImplTest"Integration tests require Docker Desktop with proper daemon configuration for Testcontainers:
./gradlew test --tests "*IntegrationTest"Note: Integration tests are currently disabled due to Docker daemon configuration requirements. Remove @Disabled
annotations from integration test classes to enable them once Docker is properly configured.
Edge Sensor → RabbitMQ (q.frames) → AudioFrameConsumer
→ AudioFrameService → ClassifierGrpcClient (gRPC)
→ AlertService (if confidence threshold met)
→ AlertRepository → WebSocket (/topic/alerts)
- Edge sensors capture audio and publish
AudioFramemessages to RabbitMQ AudioFrameConsumerreceives messages and delegates toAudioFrameServiceAudioFrameServicecalls the classification microservice via gRPC- If classification confidence exceeds threshold (default 0.10), an alert is created
- Alert is persisted to PostgreSQL and broadcast via WebSocket
Edge Sensor → RabbitMQ (q.telemetry) → TelemetryConsumer
→ TelemetryService → In-Memory NodeState Map
→ SensorPersistenceService (throttled DB writes)
→ WebSocket (/topic/telemetry)
- Edge sensors publish telemetry events to RabbitMQ
TelemetryConsumerreceives messages and updates in-memory telemetry state- dBFS values are converted to dB SPL for frontend display
- Database persistence is throttled (5-minute intervals) to prevent write amplification
- Real-time telemetry is broadcast via WebSocket every 2 seconds
AlertService.createAlert() → IncidentService.aggregateAlerts()
→ Spatial Correlation (PostGIS ST_DWithin)
→ Temporal Correlation (300-second window)
→ IncidentRepository → WebSocket (/topic/incidents)
- New alerts trigger incident aggregation logic
- Alerts within 500 meters and 300 seconds are correlated into incidents
- PostGIS spatial queries enable efficient geospatial correlation
- Incidents are persisted and broadcast via WebSocket
@Scheduled (every 5 seconds) → SensorHealthMonitorService.checkOfflineSensors()
→ TelemetryService.getSensorStatus()
→ Status Transition (ONLINE ↔ OFFLINE)
→ SensorRepository → WebSocket (/topic/sensors)
- Background job runs every 5 seconds to check sensor health
- Sensors without recent heartbeats (60-second timeout) are marked OFFLINE
- Sensors that recover are marked ONLINE
- Status changes are persisted and broadcast via WebSocket
hub/
├── src/main/java/com/acousticguard/hub/
│ ├── alert/ # Alert management (CRUD, status updates)
│ ├── analytics/ # Analytics and reporting
│ ├── auth/ # Authentication and authorization
│ ├── classifier/ # gRPC client for threat classification
│ ├── common/ # Shared domain objects, enums, error handling
│ ├── incident/ # Incident aggregation and spatial queries
│ ├── messaging/ # RabbitMQ consumers and configuration
│ ├── sensor/ # Sensor registry and health monitoring
│ ├── telemetry/ # Real-time telemetry processing
│ └── websocket/ # WebSocket broadcasting
├── src/test/java/ # Unit and integration tests
└── src/main/resources/ # Configuration files
GET /api/v1/sensors- Retrieve all sensors with status and latencyGET /api/v1/sensors/{id}- Retrieve specific sensor details
GET /api/v1/incidents- Retrieve active incidents (optional bbox filtering)GET /api/v1/incidents/{id}- Retrieve specific incident by UUIDPATCH /api/v1/incidents/{id}/status- Update incident status
GET /api/v1/alerts- Retrieve all alertsGET /api/v1/alerts/{id}- Retrieve specific alertPATCH /api/v1/alerts/{id}- Update alert details
GET /api/v1/analytics/threat-distribution- Get threat type distributionGET /api/v1/analytics/incident-history- Get incident time series data
| Property | Default | Description |
|---|---|---|
acoustic.classifier.confidence-threshold |
0.10 | Minimum confidence for creating alerts |
acoustic.sensor.heartbeat-timeout-seconds |
60 | Seconds before sensor is marked offline |
acoustic.incident.spatial-threshold-meters |
500 | Maximum distance for alert correlation |
acoustic.incident.temporal-threshold-seconds |
300 | Maximum time window for alert correlation |
Proprietary - All rights reserved.