#!/bin/bash # ambient-record.sh — continuous ambient audio recorder. # # Records RTSP audio in AMBIENT_CHUNK_SECS chunks, saves to: # AMBIENT_DIR//YYYY-MM-DD/HH-MM-SS.m4a # # Files are named by the recording start time so the collection is easy to # browse and pick from for white-noise / nature sound playback. # # Runs as a permanent systemd service (Type=simple) alongside capture.sh. # Reconnects automatically if the camera stream drops. # Applies rolling retention (AMBIENT_RETENTION_DAYS). # # Camera audio is typically 8 kHz mono (phone quality) — suitable for bird # song, rain, wind, and ambient nature sounds; check your camera's web # interface for a higher sample rate setting if available. set -euo pipefail SCRIPT_DIR="$(dirname "$(realpath "$0")")" source "$SCRIPT_DIR/sky-cam.conf" source "$SCRIPT_DIR/.env" 2>/dev/null || true export TZ="$TIMEZONE" CAM="${1:-}" if [ -z "$CAM" ]; then echo "Usage: $0 " exit 1 fi rtsp_var="CAM_RTSP_${CAM}" RTSP_URL="${!rtsp_var:-}" if [ -z "$RTSP_URL" ]; then echo "ERROR: CAM_RTSP_${CAM} not set in .env" exit 1 fi CHUNK="${AMBIENT_CHUNK_SECS:-1800}" BITRATE="${AMBIENT_BITRATE:-96k}" retain_var="AMBIENT_RETENTION_DAYS_${CAM}" RETAIN="${!retain_var:-${AMBIENT_RETENTION_DAYS:-30}}" SAVE_DIR="${AUDIO_DIR:-$BASE_DIR/audio}" echo "Ambient recorder started: cam=$CAM chunk=${CHUNK}s bitrate=$BITRATE retain=${RETAIN}d" echo "Saving to: $SAVE_DIR/$CAM/" while true; do today=$(date +%Y-%m-%d) dir="$SAVE_DIR/$CAM/$today" mkdir -p "$dir" timestamp=$(date +%H-%M-%S) # Weather tag for THIS chunk — queried right before recording so the # filename reflects conditions at the time of capture, not earlier in the # day. weather-tag.sh prints empty on disabled / missing key / API error, # so the un-tagged filename is the safe fallback. weather_tag=$("$SCRIPT_DIR/weather-tag.sh" 2>/dev/null || true) if [ -n "$weather_tag" ]; then outfile="$dir/${CAM}-${timestamp}-${weather_tag}.m4a" else outfile="$dir/${CAM}-${timestamp}.m4a" fi echo "[$(date '+%Y-%m-%d %H:%M:%S')] Recording → $outfile (${CHUNK}s)" ffmpeg -loglevel warning \ -rtsp_transport tcp \ -i "$RTSP_URL" \ -t "$CHUNK" \ -vn \ -c:a aac -b:a "$BITRATE" \ -y "$outfile" || true if [ ! -s "$outfile" ]; then echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$CAM] recording failed or empty — retrying in 30s" rm -f "$outfile" sleep 30 continue fi actual=$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$outfile" 2>/dev/null || echo "?") echo "[$(date '+%Y-%m-%d %H:%M:%S')] Saved: $(basename "$outfile") (${actual}s)" # Rolling retention if [ "${RETAIN}" -gt 0 ]; then deleted=$(find "$SAVE_DIR/$CAM" -name "*.m4a" -mtime +"$RETAIN" -print -delete 2>/dev/null | wc -l) [ "$deleted" -gt 0 ] && echo "Retention: deleted $deleted file(s) older than ${RETAIN}d" fi done