@@ -56,6 +56,11 @@ static void reset_jitter_buffer(struct jitter_buffer *jb) {
5656 jb -> clock_drift_val = 0 ;
5757 jb -> prev_seq_ts = rtpe_now ;
5858 jb -> prev_seq = 0 ;
59+ jb -> jitter_mean = 0.0 ;
60+ jb -> jitter_variance = 0.0 ;
61+ jb -> jitter_m2 = 0.0 ;
62+ jb -> jitter_samples = 0 ;
63+ jb -> dynamic_capacity = 0 ;
5964
6065 jb -> num_resets ++ ;
6166 if (g_tree_nnodes (jb -> ttq .entries ) > 0 )
@@ -92,6 +97,54 @@ static int get_clock_rate(struct media_packet *mp, int payload_type) {
9297 return clock_rate ;
9398}
9499
100+ // jb is locked
101+ static void update_jitter_statistics (struct jitter_buffer * jb , int64_t jitter_sample_us ) {
102+ if (!rtpe_config .jb_adaptive )
103+ return ;
104+
105+ jb -> jitter_samples ++ ;
106+
107+ double delta = (double )jitter_sample_us - jb -> jitter_mean ;
108+ jb -> jitter_mean += delta / (double )jb -> jitter_samples ;
109+ double delta2 = (double )jitter_sample_us - jb -> jitter_mean ;
110+ jb -> jitter_m2 += delta * delta2 ;
111+
112+ if (jb -> jitter_samples > 1 )
113+ jb -> jitter_variance = jb -> jitter_m2 / (double )(jb -> jitter_samples - 1 );
114+ }
115+
116+ // jb is locked
117+ static void calculate_adaptive_buffer_size (struct jitter_buffer * jb ) {
118+ if (!rtpe_config .jb_adaptive || jb -> jitter_samples < 10 )
119+ return ;
120+
121+ double std_dev_us = sqrt (jb -> jitter_variance );
122+
123+ double optimal_buffer_us = jb -> jitter_mean + (4.0 * std_dev_us );
124+
125+ int optimal_buffer_ms = (int )(optimal_buffer_us / 1000.0 );
126+
127+ int min_capacity = rtpe_config .jb_adaptive_min ;
128+ int max_capacity = rtpe_config .jb_adaptive_max ;
129+
130+ if (max_capacity <= 0 )
131+ max_capacity = 300 ;
132+ if (min_capacity < 0 )
133+ min_capacity = 0 ;
134+ if (min_capacity > max_capacity )
135+ min_capacity = max_capacity ;
136+
137+ if (optimal_buffer_ms < min_capacity )
138+ optimal_buffer_ms = min_capacity ;
139+ if (optimal_buffer_ms > max_capacity )
140+ optimal_buffer_ms = max_capacity ;
141+
142+ jb -> dynamic_capacity = optimal_buffer_ms ;
143+
144+ ilog (LOG_DEBUG , "Adaptive JB: mean=%.2fms, stddev=%.2fms, capacity=%dms (samples=%u)" ,
145+ jb -> jitter_mean / 1000.0 , std_dev_us / 1000.0 , jb -> dynamic_capacity , jb -> jitter_samples );
146+ }
147+
95148static struct jb_packet * get_jb_packet (struct media_packet * mp , const str * s ) {
96149 if (!(mp -> rtp = rtp_payload (& mp -> payload , s , NULL )))
97150 return NULL ;
@@ -113,10 +166,97 @@ static struct jb_packet* get_jb_packet(struct media_packet *mp, const str *s) {
113166 return p ;
114167}
115168
169+ // jb is locked (temporarily unlocked during operation, then relocked)
170+ static int remove_oldest_packets (struct jitter_buffer * jb , int num_to_remove ) {
171+ if (num_to_remove <= 0 )
172+ return 0 ;
173+
174+ int removed = 0 ;
175+ mutex_unlock (& jb -> lock );
176+
177+ for (int i = 0 ; i < num_to_remove ; i ++ ) {
178+ struct timerthread_queue_entry * ttqe = rtpe_g_tree_first (jb -> ttq .entries );
179+ if (!ttqe )
180+ break ;
181+
182+ g_tree_remove (jb -> ttq .entries , ttqe );
183+ if (jb -> ttq .entry_free_func )
184+ jb -> ttq .entry_free_func (ttqe );
185+ removed ++ ;
186+ }
187+
188+ mutex_lock (& jb -> lock );
189+ return removed ;
190+ }
191+
192+ // jb is locked
193+ static int try_burst_aware_discard (struct jitter_buffer * jb , int current_buffer_size ) {
194+ if (!jb -> rtptime_delta || !jb -> clock_rate || !jb -> prev_seq_ts ) {
195+ ilog (LOG_DEBUG , "Burst-aware discard: insufficient data for calculation" );
196+ return 0 ;
197+ }
198+
199+ int64_t packetization_interval_us = ((int64_t )jb -> rtptime_delta * 1000000 ) / jb -> clock_rate ;
200+ if (packetization_interval_us <= 0 ) {
201+ ilog (LOG_DEBUG , "Burst-aware discard: invalid packetization interval" );
202+ return 0 ;
203+ }
204+
205+ int64_t delta_t = rtpe_now - jb -> prev_seq_ts ;
206+ if (delta_t < 0 ) {
207+ ilog (LOG_DEBUG , "Burst-aware discard: negative time delta" );
208+ return 0 ;
209+ }
210+
211+ int estimated_burst_size = (int )(delta_t / packetization_interval_us );
212+
213+ int target_capacity = rtpe_config .jb_adaptive ? jb -> dynamic_capacity : rtpe_config .jb_length ;
214+ if (target_capacity <= 0 )
215+ target_capacity = rtpe_config .jb_length ;
216+
217+ int packets_to_remove = estimated_burst_size - target_capacity ;
218+
219+ if (packets_to_remove <= 0 ) {
220+ ilog (LOG_DEBUG , "Burst-aware discard: no removal needed (burst: %d, capacity: %d)" ,
221+ estimated_burst_size , target_capacity );
222+ return 1 ;
223+ }
224+
225+ if (packets_to_remove >= current_buffer_size ) {
226+ ilog (LOG_DEBUG , "Burst-aware discard: would remove all packets (burst: %d, capacity: %d, buffer: %d)" ,
227+ estimated_burst_size , target_capacity , current_buffer_size );
228+ return 0 ;
229+ }
230+
231+ int packets_saved = current_buffer_size - packets_to_remove ;
232+ ilog (LOG_DEBUG , "Burst-aware discard: burst of %d packets detected, removing %d (saving %d packets)" ,
233+ estimated_burst_size , packets_to_remove , packets_saved );
234+
235+ int removed = remove_oldest_packets (jb , packets_to_remove );
236+
237+ if (removed > 0 ) {
238+ ilog (LOG_DEBUG , "Burst-aware discard: successfully removed %d packets" , removed );
239+ return 1 ;
240+ }
241+
242+ return 0 ;
243+ }
244+
116245// jb is locked
117246static 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" );
247+ int current_buffer_size = g_tree_nnodes (jb -> ttq .entries );
248+ int target_capacity = rtpe_config .jb_adaptive ? jb -> dynamic_capacity : rtpe_config .jb_length ;
249+
250+ if (current_buffer_size > target_capacity ) {
251+ if (jb -> rtptime_delta && jb -> clock_rate && jb -> prev_seq_ts ) {
252+ if (try_burst_aware_discard (jb , current_buffer_size )) {
253+ return ;
254+ }
255+ }
256+ }
257+
258+ if (current_buffer_size >= (3 * rtpe_config .jb_length )) {
259+ ilog (LOG_DEBUG , "Emergency buffer overflow at 3x capacity - forcing reset" );
120260 reset_jitter_buffer (jb );
121261 }
122262}
@@ -311,6 +451,21 @@ int buffer_packet(struct media_packet *mp, const str *s) {
311451 // packet consumed?
312452 if (ret == 0 )
313453 p = NULL ;
454+
455+ // Update adaptive jitter buffer statistics
456+ if (rtpe_config .jb_adaptive && jb -> first_send && jb -> rtptime_delta && jb -> clock_rate ) {
457+ unsigned long ts = ntohl (mp -> rtp -> timestamp );
458+ long ts_diff = (uint32_t )ts - (uint32_t )jb -> first_send_ts ;
459+ int64_t expected_arrival = jb -> first_send + (ts_diff * 1000000LL / jb -> clock_rate );
460+
461+ int64_t jitter_us = llabs (rtpe_now - expected_arrival );
462+
463+ update_jitter_statistics (jb , jitter_us );
464+
465+ // Recalculate adaptive buffer size every 10 packets
466+ if (jb -> jitter_samples % 10 == 0 )
467+ calculate_adaptive_buffer_size (jb );
468+ }
314469
315470 check_buffered_packets (jb );
316471
0 commit comments