Drive call boundaries from audio, use the console only for the label
The control channel was wrong in both directions. Grants fire 0.84-1.62s
before anyone speaks, and srcaddr can drop to 0 while someone is still
talking - one recording came back "-1.61s lead, -0.00s tail", the trim
finding nothing to remove because the window had closed on live speech.
Confirmed by ear: the cut lands at a word boundary on an unfinished word.
Audio is ground truth for WHEN. The console remains the only source of
WHO, so it still supplies talkgroup, alias and rid.
START voice onset in the captured audio, with a 0.25s pre-roll that
now covers only chunk quantisation and threshold ramp-up rather
than a variable control-channel offset.
STOP call_silence_timeout seconds of silence heard in the audio.
LABEL resolved AT CLOSE from a bounded rolling history of console
observations overlapping the window, +4s/-2s, because there is
no guaranteed ordering between a grant and its audio.
SPLIT a console talkgroup change still forces a cut, since two calls
with no silence between them would otherwise merge into one.
Capture now emits raw PCM instead of MP3. Silence detection becomes
integer arithmetic per chunk with no decode, trimming becomes a byte
offset slice rather than a second ffmpeg pass, and MP3 encoding happens
exactly once at save - uploads are no longer double-encoded.
Audio with no talkgroup anywhere in its window is discarded rather than
uploaded: an untagged call silently poisons incident correlation, which
is worse than losing the audio. Logged at ERROR and counted on
/api/status.
When capture produces no audio at all the old console state machine
still runs, so a node with a broken audio path keeps reporting radio
activity. That is now the only consumer of call_idle_timeout.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+38
-18
@@ -29,29 +29,49 @@ PULSE_SOURCE=drb_sink.monitor
|
||||
# Seconds to wait for the shared PulseAudio socket before giving up and retrying.
|
||||
PULSE_WAIT_TIMEOUT=30
|
||||
|
||||
# Call segmentation: seconds of radio silence before the current recording is
|
||||
# closed. Grants on the same talkgroup within this window stay in ONE recording.
|
||||
# Tune ONLY from the "measured control-channel idle" line the edge node logs on
|
||||
# every idle-timeout close — silence measured in the audio is a different clock
|
||||
# (it also contains the ~1.9s P25 grant-to-speech delay).
|
||||
# --- 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 after the last transmission ends. This is the only
|
||||
# headroom protecting the final word of a transmission — usually the disposition
|
||||
# or the address. Raised 1.0 -> 3.0 after field measurement showed the
|
||||
# grant-to-speech offset is ~0.84-1.62s (typically ~1.5s): at 1.0s pad, short
|
||||
# calls had their recording window close before the voice even started,
|
||||
# clipping speech mid-word. Safe to be generous — trim_silence already strips
|
||||
# the extra back off long calls before upload, so only short transmissions
|
||||
# actually benefit from the larger window.
|
||||
# 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. ~63% of an untrimmed recording
|
||||
# is silence, which costs Whisper spend and makes it hallucinate text that was
|
||||
# never spoken. Only the head and tail are touched, with a guard margin so no
|
||||
# syllable is clipped. Set to false to upload raw audio.
|
||||
# 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 below which audio counts as silence for detection.
|
||||
# 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
|
||||
|
||||
Reference in New Issue
Block a user