10 KiB
Adaptive Jitter Buffer Configuration Guide
Overview
The FNE (Fixed Network Equipment) includes an adaptive jitter buffer system that can automatically reorder out-of-sequence RTP packets from peers experiencing network issues such as:
- Satellite links with high latency and variable jitter
- Cellular connections with packet reordering
- Congested network paths causing sporadic delays
- Multi-path routing leading to out-of-order delivery
The jitter buffer operates with zero latency for perfect networks - if packets arrive in order, they pass through immediately without buffering. Only out-of-order packets trigger the adaptive buffering mechanism.
How It Works
Zero-Latency Fast Path
When packets arrive in perfect sequence order, they are processed immediately with no additional latency. The jitter buffer is effectively transparent.
Adaptive Reordering
When an out-of-order packet is detected:
- The jitter buffer holds the packet temporarily
- Waits for missing packets to arrive
- Delivers frames in correct sequence order
- Times out after a configurable period if gaps persist
Per-Peer, Per-Stream Isolation
- Each peer connection can have independent jitter buffer settings
- Within each peer, each call/stream has its own isolated buffer
- This prevents one problematic stream from affecting others
Configuration
Location
Jitter buffer configuration is defined in the FNE configuration file (typically fne-config.yml) under the master section:
master:
# ... other master configuration ...
jitterBuffer:
enabled: false
defaultMaxSize: 4
defaultMaxWait: 40000
peerOverrides:
- peerId: 31003
enabled: true
maxSize: 6
maxWait: 80000
Parameters
Global Settings
-
enabled (boolean, default:
false)- Master enable/disable switch for jitter buffering
- When
false, all peers operate with zero-latency pass-through - When
true, peers use jitter buffering with default parameters
-
defaultMaxSize (integer, range: 2-8, default:
4)- Maximum number of frames to buffer per stream
- Larger values provide more reordering capability but add latency
- Recommended values:
4- Standard networks (LAN, stable WAN)6- High-jitter networks (cellular, congested paths)8- Extreme conditions (satellite, very poor links)
-
defaultMaxWait (integer, range: 10000-200000 microseconds, default:
40000)- Maximum time to wait for missing packets
- Frames older than this are delivered even with gaps
- Recommended values:
40000(40ms) - Terrestrial networks60000(60ms) - Cellular networks80000(80ms) - Satellite links
Per-Peer Overrides
The peerOverrides array allows you to customize jitter buffer behavior for specific peers:
peerOverrides:
# Satellite link - high latency, requires larger buffer
- peerId: 31003
enabled: true
maxSize: 6
maxWait: 80000
# Cellular peer - variable jitter
- peerId: 31004
enabled: true
maxSize: 5
maxWait: 60000
# Local fiber peer - disable jitter buffer for minimal latency
- peerId: 31005
enabled: false
Each override entry supports:
- peerId (integer) - The peer ID to configure
- enabled (boolean) - Enable/disable for this specific peer
- maxSize (integer, range: 2-8) - Buffer size override
- maxWait (integer, range: 10000-200000) - Timeout override
Configuration Examples
Example 1: Disabled (Default)
For networks with reliable connectivity:
master:
jitterBuffer:
enabled: false
defaultMaxSize: 4
defaultMaxWait: 40000
All peers operate with zero-latency pass-through. Best for:
- Local area networks
- Stable dedicated connections
- Networks with minimal packet loss/reordering
Example 2: Global Enable with Defaults
Enable jitter buffering for all peers with conservative settings:
master:
jitterBuffer:
enabled: true
defaultMaxSize: 4
defaultMaxWait: 40000
Good starting point for:
- Mixed network environments
- Networks with occasional jitter
- General purpose deployments
Example 3: Selective Peer Configuration
Enable only for problematic peers:
master:
jitterBuffer:
enabled: false # Disabled by default
defaultMaxSize: 4
defaultMaxWait: 40000
peerOverrides:
# Enable only for satellite peer
- peerId: 31003
enabled: true
maxSize: 8
maxWait: 80000
# Enable for cellular peer
- peerId: 31004
enabled: true
maxSize: 6
maxWait: 60000
Recommended approach for:
- Mostly stable networks with a few problem peers
- Minimizing overall system latency
- Targeted optimization
Example 4: High-Jitter Network
For challenging network environments:
master:
jitterBuffer:
enabled: true
defaultMaxSize: 6
defaultMaxWait: 60000
peerOverrides:
# Satellite link needs even more buffering
- peerId: 31003
enabled: true
maxSize: 8
maxWait: 100000
Suitable for:
- Wide area networks with variable quality
- Networks with frequent reordering
- Deployments with multiple satellite/cellular links
Monitoring and Tuning
Startup Logging
When the FNE starts, jitter buffer configuration is displayed in the logs:
I: 2025-12-03 22:07:11.374 Jitter Buffer Enabled: yes
I: 2025-12-03 22:07:11.374 Jitter Buffer Default Max Size: 6 frames
I: 2025-12-03 22:07:11.374 Jitter Buffer Default Max Wait: 50000 microseconds
I: 2025-12-03 22:07:11.374 Jitter Buffer Peer Overrides: 3 peer(s) configured
Per-Peer Configuration Logging
When a peer connects and jitter buffering is enabled, you'll see (with verbose logging):
I: 2025-12-03 22:10:15.234 PEER 31003 jitter buffer configured (override): enabled=yes, maxSize=8, maxWait=80000
I: 2025-12-03 22:10:16.456 PEER 31004 jitter buffer configured (default): enabled=yes, maxSize=4, maxWait=40000
Future Monitoring (To Be Implemented)
Planned monitoring capabilities:
- Per-peer jitter buffer statistics (reordered frames, dropped frames, timeouts)
- InfluxDB metrics for trend analysis
- REST API endpoints for runtime statistics
- Automatic tuning recommendations based on observed behavior
Performance Characteristics
CPU Impact
- Zero-latency path: Negligible overhead (~1 comparison per packet)
- Buffering path: Minimal overhead (~map lookup + timestamp check)
- Memory: ~500 bytes per active stream buffer
Latency Impact
- In-order packets: 0ms additional latency
- Out-of-order packets: Buffered until:
- Missing packets arrive, OR
maxWaittimeout expires
- Typical latency: 10-40ms for reordered packets on terrestrial networks
Effectiveness
Based on the adaptive jitter buffer design:
- 100% pass-through for perfect networks (zero latency)
- ~95-99% recovery of out-of-order packets within timeout window
- Automatic timeout delivery prevents indefinite stalling
Troubleshooting
Symptom: Audio/Data Gaps Despite Jitter Buffer
Possible Causes:
maxWaittimeout too short for network conditionsmaxSizebuffer too small for reordering depth- Actual packet loss (not just reordering)
Solutions:
- Increase
maxWaitby 20-40ms increments - Increase
maxSizeby 1-2 frames - Verify network packet loss with diagnostics
Symptom: Excessive Latency
Possible Causes:
- Jitter buffer enabled on stable connections
maxWaitset too highmaxSizeset too large
Solutions:
- Disable jitter buffer for known-good peers using overrides
- Reduce
maxWaitin 10-20ms decrements - Reduce
maxSizeto minimum (2-4 frames)
Symptom: No Improvement
Possible Causes:
- Jitter buffer not actually enabled for the problematic peer
- Issues beyond reordering (e.g., corruption, auth failures)
- Problems at application layer, not transport layer
Solutions:
- Verify peer override configuration is correct
- Check FNE logs for peer-specific configuration messages
- Enable verbose and debug logging to trace packet flow
Technical Details
RTP Sequence Number Handling
The jitter buffer correctly handles RTP sequence number wraparound (RFC 3550):
- Sequence numbers are 16-bit unsigned integers (0-65535)
- After 65535, sequence resets to 0
- Buffer correctly calculates sequence differences across wraparound
- No special configuration needed
Thread Safety
- Each peer's jitter buffer map is protected by a mutex
- Per-stream buffers operate independently
- Safe for concurrent access from multiple worker threads
Memory Management
- Buffered frames use RAII for automatic cleanup
- Timed-out frames are automatically freed
- Stream buffers cleaned up when streams end
- No memory leaks under normal operation
Best Practices
- Start Disabled: Begin with jitter buffering disabled and enable only as needed
- Target Specific Peers: Use per-peer overrides rather than global enable when possible
- Conservative Tuning: Start with default parameters and adjust incrementally
- Monitor Performance: Watch for signs of latency or audio quality issues
- Document Changes: Keep records of which peers need special configuration
- Test Thoroughly: Validate changes don't introduce unintended latency
Reference
Related Documentation
ADAPTIVE_JITTER_BUFFER.md- Technical implementation detailsAdaptiveJitterBuffer.example.cpp- Code examplesfne-config.example.yml- Full configuration example
Configuration Schema
jitterBuffer:
enabled: <boolean> # false
defaultMaxSize: <2-8> # 4
defaultMaxWait: <10000-200000> # 40000
peerOverrides:
- peerId: <integer> # Required
enabled: <boolean> # Optional, defaults to global enabled
maxSize: <2-8> # Optional, defaults to defaultMaxSize
maxWait: <10000-200000> # Optional, defaults to defaultMaxWait
Version History
- December 2025 - Initial implementation
- Zero-latency fast path
- Per-peer, per-stream adaptive buffering
- Configuration parsing and validation
- Sequence wraparound support