1818#define DELAY_FACTOR 0x64
1919#define COMFORT_NOISE 0x0D
2020
21+ #define JB_ADAPTIVE_MIN_SAMPLES 0x0A // Minimum samples before calculating buffer size (10)
22+ #define JB_ADAPTIVE_RECALC_INTERVAL 0x0A // Recalculate buffer size every N packets (10)
23+ #define JB_MAX_BURST_SIZE 0x03E8 // Maximum burst size to prevent overflow (1000 packets = 20 sec)
24+ #define JB_MAX_JITTER_US 0x1E8480 // Maximum jitter value (2000000 µs = 2 seconds)
25+
2126
2227static struct timerthread jitter_buffer_thread ;
2328
@@ -56,6 +61,11 @@ static void reset_jitter_buffer(struct jitter_buffer *jb) {
5661 jb -> clock_drift_val = 0 ;
5762 jb -> prev_seq_ts = rtpe_now ;
5863 jb -> prev_seq = 0 ;
64+ jb -> jitter_mean = 0.0 ;
65+ jb -> jitter_variance = 0.0 ;
66+ jb -> jitter_m2 = 0.0 ;
67+ jb -> jitter_samples = 0 ;
68+ jb -> dynamic_capacity = 0 ;
5969
6070 jb -> num_resets ++ ;
6171 if (g_tree_nnodes (jb -> ttq .entries ) > 0 )
@@ -92,6 +102,69 @@ static int get_clock_rate(struct media_packet *mp, int payload_type) {
92102 return clock_rate ;
93103}
94104
105+
106+ // jb is locked
107+ static int get_target_capacity (struct jitter_buffer * jb ) {
108+ if (rtpe_config .jb_adaptive && jb -> dynamic_capacity > 0 )
109+ return jb -> dynamic_capacity ;
110+ return rtpe_config .jb_length ;
111+ }
112+
113+ // jb is locked
114+ static void update_jitter_statistics (struct jitter_buffer * jb , int64_t jitter_sample_us ) {
115+ if (!rtpe_config .jb_adaptive )
116+ return ;
117+
118+ if (jitter_sample_us < 0 || jitter_sample_us > JB_MAX_JITTER_US ) {
119+ ilog (LOG_WARN , "Extreme jitter value detected: %lld µs, ignoring" ,
120+ (long long )jitter_sample_us );
121+ return ;
122+ }
123+
124+ jb -> jitter_samples ++ ;
125+
126+ double delta = (double )jitter_sample_us - jb -> jitter_mean ;
127+ jb -> jitter_mean += delta / (double )jb -> jitter_samples ;
128+ double delta2 = (double )jitter_sample_us - jb -> jitter_mean ;
129+ jb -> jitter_m2 += delta * delta2 ;
130+
131+ if (jb -> jitter_samples > 1 )
132+ jb -> jitter_variance = jb -> jitter_m2 / (double )(jb -> jitter_samples - 1 );
133+ }
134+
135+ // jb is locked
136+ static void calculate_adaptive_buffer_size (struct jitter_buffer * jb ) {
137+ if (!rtpe_config .jb_adaptive || jb -> jitter_samples < JB_ADAPTIVE_MIN_SAMPLES )
138+ return ;
139+
140+ // Protect against negative variance due to floating-point errors
141+ double std_dev_us = sqrt (jb -> jitter_variance < 0.0 ? 0.0 : jb -> jitter_variance );
142+
143+ double optimal_buffer_us = jb -> jitter_mean + (4.0 * std_dev_us );
144+
145+ int optimal_buffer_ms = (int )(optimal_buffer_us / 1000.0 );
146+
147+ int min_capacity = rtpe_config .jb_adaptive_min ;
148+ int max_capacity = rtpe_config .jb_adaptive_max ;
149+
150+ if (max_capacity <= 0 )
151+ max_capacity = 300 ;
152+ if (min_capacity < 0 )
153+ min_capacity = 0 ;
154+ if (min_capacity > max_capacity )
155+ min_capacity = max_capacity ;
156+
157+ if (optimal_buffer_ms < min_capacity )
158+ optimal_buffer_ms = min_capacity ;
159+ if (optimal_buffer_ms > max_capacity )
160+ optimal_buffer_ms = max_capacity ;
161+
162+ jb -> dynamic_capacity = optimal_buffer_ms ;
163+
164+ ilog (LOG_DEBUG , "Adaptive JB: mean=%.2fms, stddev=%.2fms, capacity=%dms (samples=%u)" ,
165+ jb -> jitter_mean / 1000.0 , std_dev_us / 1000.0 , jb -> dynamic_capacity , jb -> jitter_samples );
166+ }
167+
95168static struct jb_packet * get_jb_packet (struct media_packet * mp , const str * s ) {
96169 if (!(mp -> rtp = rtp_payload (& mp -> payload , s , NULL )))
97170 return NULL ;
@@ -113,10 +186,100 @@ static struct jb_packet* get_jb_packet(struct media_packet *mp, const str *s) {
113186 return p ;
114187}
115188
189+ // jb is locked (temporarily unlocked during operation, then relocked)
190+ static int remove_oldest_packets (struct jitter_buffer * jb , int num_to_remove ) {
191+ if (num_to_remove <= 0 )
192+ return 0 ;
193+
194+ int removed = 0 ;
195+ mutex_unlock (& jb -> lock );
196+
197+ for (int i = 0 ; i < num_to_remove ; i ++ ) {
198+ struct timerthread_queue_entry * ttqe = rtpe_g_tree_first (jb -> ttq .entries );
199+ if (!ttqe )
200+ break ;
201+
202+ g_tree_remove (jb -> ttq .entries , ttqe );
203+ if (jb -> ttq .entry_free_func )
204+ jb -> ttq .entry_free_func (ttqe );
205+ removed ++ ;
206+ }
207+
208+ mutex_lock (& jb -> lock );
209+ return removed ;
210+ }
211+
212+ // jb is locked
213+ static int try_burst_aware_discard (struct jitter_buffer * jb , int current_buffer_size ) {
214+ if (!jb -> rtptime_delta || !jb -> clock_rate || !jb -> prev_seq_ts ) {
215+ ilog (LOG_DEBUG , "Burst-aware discard: insufficient data for calculation" );
216+ return 0 ;
217+ }
218+
219+ int64_t packetization_interval_us = ((int64_t )jb -> rtptime_delta * 1000000 ) / jb -> clock_rate ;
220+ if (packetization_interval_us <= 0 ) {
221+ ilog (LOG_DEBUG , "Burst-aware discard: invalid packetization interval" );
222+ return 0 ;
223+ }
224+
225+ int64_t delta_t = rtpe_now - jb -> prev_seq_ts ;
226+ if (delta_t < 0 ) {
227+ ilog (LOG_DEBUG , "Burst-aware discard: negative time delta" );
228+ return 0 ;
229+ }
230+
231+ int64_t burst_calc = delta_t / packetization_interval_us ;
232+ if (burst_calc > JB_MAX_BURST_SIZE ) {
233+ ilog (LOG_DEBUG , "Burst size exceeds maximum (%d packets), capping" , JB_MAX_BURST_SIZE );
234+ burst_calc = JB_MAX_BURST_SIZE ;
235+ }
236+ int estimated_burst_size = (int )burst_calc ;
237+
238+ int target_capacity = get_target_capacity (jb );
239+
240+ int packets_to_remove = estimated_burst_size - target_capacity ;
241+
242+ if (packets_to_remove <= 0 ) {
243+ ilog (LOG_DEBUG , "Burst-aware discard: no removal needed (burst: %d, capacity: %d)" ,
244+ estimated_burst_size , target_capacity );
245+ return 1 ;
246+ }
247+
248+ if (packets_to_remove >= current_buffer_size ) {
249+ ilog (LOG_DEBUG , "Burst-aware discard: would remove all packets (burst: %d, capacity: %d, buffer: %d)" ,
250+ estimated_burst_size , target_capacity , current_buffer_size );
251+ return 0 ;
252+ }
253+
254+ int packets_saved = current_buffer_size - packets_to_remove ;
255+ ilog (LOG_DEBUG , "Burst-aware discard: burst of %d packets detected, removing %d (saving %d packets)" ,
256+ estimated_burst_size , packets_to_remove , packets_saved );
257+
258+ int removed = remove_oldest_packets (jb , packets_to_remove );
259+
260+ if (removed > 0 ) {
261+ ilog (LOG_DEBUG , "Burst-aware discard: successfully removed %d packets" , removed );
262+ return 1 ;
263+ }
264+
265+ return 0 ;
266+ }
267+
116268// jb is locked
117269static void check_buffered_packets (struct jitter_buffer * jb ) {
118- if (g_tree_nnodes (jb -> ttq .entries ) >= (3 * rtpe_config .jb_length )) {
119- ilog (LOG_DEBUG , "Jitter reset due to buffer overflow" );
270+ int current_buffer_size = g_tree_nnodes (jb -> ttq .entries );
271+ int target_capacity = get_target_capacity (jb );
272+
273+ if (current_buffer_size > target_capacity ) {
274+ if (jb -> rtptime_delta && jb -> clock_rate && jb -> prev_seq_ts ) {
275+ if (try_burst_aware_discard (jb , current_buffer_size )) {
276+ return ;
277+ }
278+ }
279+ }
280+
281+ if (current_buffer_size >= (3 * rtpe_config .jb_length )) {
282+ ilog (LOG_DEBUG , "Emergency buffer overflow at 3x capacity - forcing reset" );
120283 reset_jitter_buffer (jb );
121284 }
122285}
@@ -311,6 +474,20 @@ int buffer_packet(struct media_packet *mp, const str *s) {
311474 // packet consumed?
312475 if (ret == 0 )
313476 p = NULL ;
477+
478+ // Update adaptive jitter buffer statistics
479+ if (rtpe_config .jb_adaptive && jb -> first_send && jb -> rtptime_delta && jb -> clock_rate ) {
480+ unsigned long ts = ntohl (mp -> rtp -> timestamp );
481+ long ts_diff = (uint32_t )ts - (uint32_t )jb -> first_send_ts ;
482+ int64_t expected_arrival = jb -> first_send + (ts_diff * 1000000LL / jb -> clock_rate );
483+
484+ int64_t jitter_us = llabs (rtpe_now - expected_arrival );
485+
486+ update_jitter_statistics (jb , jitter_us );
487+
488+ if (jb -> jitter_samples % JB_ADAPTIVE_RECALC_INTERVAL == 0 )
489+ calculate_adaptive_buffer_size (jb );
490+ }
314491
315492 check_buffered_packets (jb );
316493
0 commit comments