Raise tail pad to 3s so short transmissions are not clipped

The recording window is anchored to OP25 control-channel timestamps, but
the buffered audio lags those by roughly 1.5s. Trim logs across seven
calls measured the offset at 0.84-1.62s, consistently present.

At a 1.0s pad a short call closed its window before the voice arrived:
a 0.97s control-channel call closed at T+1.97 while voice started around
T+1.5, capturing ~0.4s of speech and cutting mid-word. Confirmed by a
0.57s file whose final 0.10s measured -12.2dB against its own -18.2dB
average - clipped speech, not a tail - and by two short calls that
logged no trim at all because no trailing silence remained.

Being generous is free here: trim_silence already strips trailing
silence back to the guard margin before upload, so long calls are
unaffected while short ones gain the window they need. Over-capture
costs nothing; under-capture loses words permanently.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Logan Cusano
2026-08-04 22:34:17 -04:00
parent 7c4a3f2f20
commit ceb2836371
4 changed files with 87 additions and 17 deletions
+23 -4
View File
@@ -47,10 +47,29 @@ class Settings(BaseSettings):
# Audio kept after the observed end of the last transmission. The srcaddr
# 1→0 edge can be up to one poll (0.5 s) late and the encoder adds its own
# latency, so this is the only headroom protecting the last word of a
# transmission — which is usually the disposition or the address. Field
# measurement at 0.5 s left only 0.290.37 s of real trailing margin and one
# recording ended mid-word, hence 1.0 s.
call_tail_pad_seconds: float = 1.0
# transmission — which is usually the disposition or the address.
#
# Raised 1.0 -> 3.0 after field measurement showed the recording WINDOW
# (anchored to OP25 control-channel timestamps) closing well before the
# actual voice audio arrives: grant->speech offset measured 0.84-1.62s
# across 7 calls (~1.5s typical). At the old 1.0s pad, a short
# transmission (e.g. a 0.97s control-channel call) had its window close
# at T+1.97 while voice didn't start until ~T+1.5 — leaving ~0.4s of
# captured speech, clipped mid-word. Confirmed by a 0.57s output file
# whose final 0.10s measured -12.2dB, louder than its own -18.2dB
# average (i.e. clipped speech, not trailing silence), and by two short
# calls that produced no "Trimmed" log line at all because there was no
# trailing silence left to trim.
#
# Safe to be generous here: trim_silence already strips trailing silence
# back to trim_silence_guard_seconds before upload, so a larger pad costs
# long calls nothing (the extra is trimmed away) while giving short
# transmissions enough window to actually capture the voice. Over-capture
# is free; under-capture loses words permanently. Do not tune this back
# down without new field data showing the grant->speech offset has
# shrunk — see DEFERRED.md for the call_idle_timeout coupling this value
# now sits at.
call_tail_pad_seconds: float = 3.0
# Strip leading/trailing dead air before upload. ~63% of a typical recording
# is silence (the grant→speech delay plus the tail pad), which inflates
@@ -58,8 +58,13 @@ def _tail_pad() -> float:
edge (up to one poll late) plus encoder latency never clips the tail.
Read live from settings (env CALL_TAIL_PAD_SECONDS) rather than frozen into a
module constant, so it is tunable per node. See the setting for why the
default moved 0.51.0.
module constant, so it is tunable per node. See the setting in config.py for
why the default moved 1.03.0 (short calls' recording window was closing
before the ~1.5s grant→speech offset let voice audio even start).
Only the idle-timeout close path below uses this pad — the tgid_change and
tgid_change_unlogged paths close at an exact, already-known boundary (the
new grant's timestamp, or the same poll tick) and intentionally add none.
"""
return settings.call_tail_pad_seconds