# Node Identity NODE_ID=node-001 NODE_NAME="My Radio Node" NODE_LAT=0.0 NODE_LON=0.0 # MQTT — point to your C2 server MQTT_BROKER=localhost MQTT_PORT=1883 # Must match MQTT_NODE_USER/MQTT_NODE_PASS in the server's top-level .env MQTT_USER=drb-node MQTT_PASS=change-me-node # C2 server for audio upload (leave blank to disable upload) C2_URL=http://localhost:8888 # API key is provisioned automatically via MQTT after admin approves the node # Icecast (local container — usually no need to change) # Live listening only. Call recording and Discord voice use PulseAudio instead. ICECAST_SOURCE_PASSWORD=hackme ICECAST_ADMIN_PASSWORD=admin ICECAST_HOST=localhost ICECAST_PORT=8000 ICECAST_MOUNT=/radio # PulseAudio capture (usually no need to change) # Monitor of the drb_sink null sink that Liquidsoap writes into. PULSE_SOURCE=drb_sink.monitor # Seconds to wait for the shared PulseAudio socket before giving up and retrying. PULSE_WAIT_TIMEOUT=30 # --- Call segmentation ------------------------------------------------------- # Recording boundaries come from the AUDIO, not the control channel: a recording # starts at voice onset and ends after this many seconds of silence actually # heard in the stream. Transmissions on the same talkgroup separated by less # than this stay in ONE recording, so back-and-forth traffic is one file. # Tune from the "measured trailing silence" line logged on every close. CALL_SILENCE_TIMEOUT=3.0 # dBFS (RMS over one ~46ms chunk) below which audio counts as silence and the # recording is allowed to close. # # This does NOT need calibrating against your radio's noise floor. Between # transmissions the capture is the monitor of a PulseAudio *null sink*, which # emits DIGITAL silence: measured on a live node it sits at about -91 dBFS — # one least-significant bit of a 16-bit sample — while speech averages about # -18 dBFS. Anything from roughly -70 to -40 behaves identically. Only change # this if you have replaced the audio path with something that has a real # analog noise floor. CALL_SILENCE_THRESHOLD_DB=-50 # DEPRECATED as a primary control. Used ONLY when PulseAudio capture is not # producing audio, where the old control-channel state machine takes over so # the node still reports radio activity (with no recordings) while its audio # path is broken. CALL_IDLE_TIMEOUT=3 # Seconds of audio kept past a CONTROL-CHANNEL-derived boundary — a talkgroup # change, or a close in the fallback mode above. Buffered audio lags the # control channel by ~1.5s (grant-to-speech offset measured 0.84-1.62s), so # cutting at the exact control-channel timestamp clipped the last words of the # outgoing call. Does NOT apply to the normal end of a call any more; that # boundary comes from the audio and needs no pad. Safe to be generous — the # extra is trimmed off again before upload. CALL_TAIL_PAD_SECONDS=3.0 # Strip leading/trailing dead air before upload. Recordings deliberately # over-capture at both ends, and silence costs Whisper spend and makes it # hallucinate text that was never spoken. Trimming is a sample-offset slice of # the buffered PCM (no re-encode) and only ever touches the head and tail, with # a guard margin so no syllable is clipped. Set to false to upload raw audio. TRIM_SILENCE=true # dBFS (RMS) below which audio counts as silence when trimming the ends. Kept # stricter than CALL_SILENCE_THRESHOLD_DB on purpose. TRIM_SILENCE_THRESHOLD_DB=-40 # Seconds of audio kept either side of detected speech. TRIM_SILENCE_GUARD_SECONDS=0.25 # OP25 container (usually no need to change) OP25_API_URL=http://localhost:8001 OP25_TERMINAL_URL=http://localhost:8081 # Container registry — set these to pull pre-built images instead of building locally. # Must match the DOCKER_ORG variable and repo name configured in Gitea. # Leave blank to always build locally. IMAGE_REGISTRY=git.vpn.cusano.net DOCKER_ORG= DOCKER_REPO=