Skip to content

Adapt server ingress buffering online within a musical latency ceiling #78

Description

@christofmuc

Context

The server currently receives -b, -w, and -p buffer parameters from the command line. They are static packet-count guesses even though the useful values depend on frame duration, the current participants, clock drift, and changing network conditions.

In the ideal case, every active client supplies its next packet in sync and without jitter. The server should then mix as soon as one packet from every client is available, with zero additional safety queue.

The previous adaptive experiment in jn-fork optimized toward the 99th percentile of measured jitter. That is appropriate for preserving speech continuity, but on a poor Internet connection it immediately selects latency that is unsuitable for musical performance.

Queue fullness is also not evidence of bad network quality. A client with a slightly faster audio clock naturally accumulates packets while waiting for the slowest client. A hold followed by a flush creates the same condition as a burst. Neither should increase the buffering of the whole session.

Related:

Goal

Choose the smallest useful server ingress safety target during operation while enforcing a hard musical-latency ceiling. If the network cannot operate within that ceiling, JammerNetz must accept classified drops/concealment rather than silently raising latency until speech becomes stable.

The slowest active client remains the implicit mix clock. No wall-clock-driven server playout epoch is introduced.

Proposed control signals

Drive the session target from actual barrier starvation:

  • Start at zero extra frames.
  • A mix is ready when every active stream has its next packet.
  • Count occasions where the barrier must wait because the minimum queue is empty.
  • Increase the safety target by one frame only after repeated starvation within a defined window.
  • Use hysteresis and a cooldown between increases.
  • Decrease only after a long stable interval, or defer decreases to a reconnect/safe transition.
  • Clamp the target to a configured maximum expressed in milliseconds.

Do not use these as reasons to increase the session target:

  • a full or growing queue;
  • average or maximum queue depth;
  • audio-loop roundtrip time;
  • absolute jitter that counts early packets as harmful;
  • a single transient reorder or loss.

Clock drift and local overflow

Track relative source rate separately, for example from the slope of:

received packets - mixed packets - deliberate discards

A queue that grows gradually represents a faster source clock. A sudden large increase represents a burst or hold/flush. In both cases, apply a local fast-forward when that stream exceeds its high-water mark. Do not drain or enlarge unrelated queues.

The local fast-forward must use the deliberate queue operation specified by #76 so intentionally skipped counters are not recreated as normal loss fill-ins.

Runtime configuration

Reinterpret CLI/configuration values as policy constraints and overrides rather than mandatory operating points:

  • maximum server buffering in milliseconds;
  • acceptable barrier-starvation rate;
  • per-stream high-water allowance;
  • adjustment cooldown/window;
  • fixed/manual mode for diagnostics;
  • optional initial target.

Expose the currently selected target in both frames and milliseconds.

Changing the target is an explicit state transition:

  • Increasing it requires a bounded rebuffer of one frame.
  • Decreasing it requires a coherent latency reduction or deferral to a safe boundary.
  • Every transition increments a diagnostic counter and records its reason.

Acceptance criteria

  • With synchronized, jitter-free input, the target remains zero and every complete set is mixed immediately.
  • Repeated simulated late arrivals increase the target one frame at a time, never beyond the musical ceiling.
  • When the ceiling is insufficient, drops/concealment occur without further latency growth.
  • A source with positive simulated clock drift is locally fast-forwarded and does not increase the session target.
  • A hold/flush affects only the offending stream and does not drain other queues.
  • A single reordered or lost packet does not permanently raise the target.
  • Equivalent millisecond policies behave consistently with 64- and 128-sample network frames.
  • Join, leave, reconnect, counter wrap, and a stopped client do not corrupt the controller state.
  • Deterministic tests expose target changes, starvation events, local corrections, and resulting queue depths.

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

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions