Skip to content

V.34 handshake reliability: an opt-in carrier-loss watchdog workaround #13

Description

@szeremeta1

The README says:

Connections are unreliable, and it is currently difficult to connect at speeds higher than 14.4kbps or so.

To successfully connect, you will likely need to manually select a modulation and data rate. In our testing, V.32bis (14.4kbps) and below appears to be the most reliable, though V.34 (33.6kbps) connections are sometimes successful.

On one installation using slmodemd and the closed dsplibs.o with packet
audio, disabling a handshake carrier-loss criterion improved completed calls
in the interleaved comparison below. This is an installation-specific
workaround. The original claim that it explains the speed ceiling, or that
this intervention raised negotiated rates, was not supported by that comparison.

The mechanism

v34handshak (in dsplibs.o, at .text+0x62a92 in the build I have) ends the
call when a signal metric stays below a threshold for a run of consecutive
samples:

if ((short)metric < obj->lowsig_thresh)   obj->lowsig_count++;
else                                      obj->lowsig_count = 0;
if (obj->lowsig_count > 0x257f)           *status = 9;   /* -> hang up */

v34handshak runs once per sample, so 0x257f = 9599 samples is exactly one
second at the 9600 Hz DSP rate. The counter is consecutive: one good sample
resets it. status = 9 reaches vpcm_run, which logs vpcm: Link Error and
hangs up.

The threshold is the vendor default

The threshold is not a constant. VPcmV34SetMinimumSigLevel picks it from an
eight-entry table at .data+0xc0:

index      0    1    2    3    4    5    6    7
level    -48  -47  -46  -45  -44  -43  -42  -41   dBm
value     71   80   90  101  113  127  142  160

The index is a minLevel field plus 0x30, clamped to 3 when it falls
outside 0–7
. dp_runtime_create zeroes that field and nothing in the object
or the host driver ever writes it, so the index is 0x30 on every installation,
hardware included, and the threshold is always 101 (−45 dBm on the table's own
scale). It's the datapump's default, not something a packet path falls into.

Correction, 2026-09-08. As originally filed, this section said the lookup
fell through to the clamp because a packet path has no dBm-calibrated level to
index it with. That was wrong (G.711 defines the digital milliwatt, and the
index is a field nobody writes anyway); Manawyrm pointed it out below. The
threshold is the vendor default. The cause of the low metric, and whether
additional RX noise/self-echo addresses it, remain separate experimental
questions; disabling the criterion does not answer them.

The historical capture analysis reported activity resuming at 4.03–4.07 s,
4.30–4.54 s, or after an internal restart at 8.7–9.2 s across 76 windows. Those
observations motivated the experiment. They do not by themselves prove that
the observed quiet intervals are protocol-required, identify the cause of
the low metric, or establish the correct driver I/O delay.

Evidence

Interleaved A/B, identical binary in both arms, one environment variable
between them, three blocks with two warm-ups discarded each, n=30 per arm:

completions status 9 acquisition timeouts
watchdog armed (as shipped) 19/30 6 5
watchdog disabled 27/30 0 3

Fisher exact, two-sided: p = 0.030. Every call that completed, in both arms,
reported 33,600 bit/s caller receive rate in both arms. This comparison
supports improved completion on that setup, not increased speed, both
directional rates, or 99% call reliability. Both arms also shared earlier host
fixes and inherited service settings. The deposited artifacts do not contain
every prerequisite needed to reconstruct that complete historical stack.

Fix

PR #14 weakens
VPcmV34Progress with objcopy and links a wrapper in
front of it, so no vendor instruction changes and the vendor object is never
redistributed — the build runs objcopy against your own copy. It is off unless
an environment variable is set, so default behaviour does not change.

Full write-up, method, and the data: https://dialup.litenet.tel/research/v34-modem/

Review update, 2026-09-10

The title and unsupported mechanism/rate claims above have been corrected.
PR #14 is now a focused, opt-in watchdog workaround with exact vendor-object
pinning and an isolated, verified build; its default path passes directly to
the original function. The historical 19/30 versus 27/30 result has not been
relabelled as a new hardware trial.

Separate, disabled-by-default experiments now cover
RX conditioning,
near-echo output bypass,
socket stream handling,
and digital V.90 negotiation.
Their component/build checks do not establish higher rates or a
100+ call reliability criterion. Physical testing and end-to-end payload
validation are continuing. The digital negotiation work does not yet implement
a complete native 8 kHz digital transmitter/receiver journey or prove a 56k call.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions