jitterctl.c 12.8 KB
Newer Older
aymeric's avatar
aymeric committed
1
/*
2
 * Copyright (c) 2010-2019 Belledonne Communications SARL.
3
 *
4
 * This file is part of oRTP.
5
 *
6 7 8 9
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
10
 *
11 12 13 14 15 16 17
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18
 */
aymeric's avatar
aymeric committed
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
/***************************************************************************
 *            jitterctl.c
 *
 *  Mon Nov  8 11:53:21 2004
 *  Copyright  2004  Simon MORLAT
 *  Email simon.morlat@linphone.org
 ****************************************************************************/

#include "ortp/rtpsession.h"
#include "ortp/payloadtype.h"
#include "ortp/ortp.h"
#include "utils.h"
#include "rtpsession_priv.h"
#include <math.h>

34
#define JC_BETA .01
aymeric's avatar
aymeric committed
35 36 37 38
#define JC_GAMMA (JC_BETA)

#include "jitterctl.h"

39
void jitter_control_init(JitterControl *ctl, PayloadType *payload){
aymeric's avatar
aymeric committed
40
	ctl->count=0;
41 42
	ctl->clock_offset_ts=0;
	ctl->prev_clock_offset_ts=0;
aymeric's avatar
aymeric committed
43 44
	ctl->jitter=0;
	ctl->inter_jitter=0;
45 46
	ctl->cum_jitter_buffer_count=0;
	ctl->cum_jitter_buffer_size=0;
47 48
	ctl->corrective_slide=0;

49
	ctl->clock_rate=8000;
50 51
	ctl->adapt_refresh_prev_ts=0;

aymeric's avatar
aymeric committed
52 53 54 55 56
	if (payload!=NULL){
		jitter_control_set_payload(ctl,payload);
	}
}

57

aymeric's avatar
aymeric committed
58
void jitter_control_enable_adaptive(JitterControl *ctl, bool_t val){
59
	ctl->params.adaptive=val;
aymeric's avatar
aymeric committed
60 61 62 63
}

void jitter_control_set_payload(JitterControl *ctl, PayloadType *pt){
	ctl->jitt_comp_ts =
64
			(int) (((double) ctl->params.nom_size / 1000.0) * (pt->clock_rate));
65 66
	/*make correction by not less than 10ms */
	ctl->corrective_step=(int) (0.01 * (float)pt->clock_rate);
aymeric's avatar
aymeric committed
67
	ctl->adapt_jitt_comp_ts=ctl->jitt_comp_ts;
68
	ctl->clock_rate=pt->clock_rate;
aymeric's avatar
aymeric committed
69 70 71 72
}


void jitter_control_dump_stats(JitterControl *ctl){
73
	ortp_message("JitterControl:\n\tslide=%g,jitter=%g,adapt_jitt_comp_ts=%i,corrective_slide=%i, count=%i",
74
			(double)ctl->clock_offset_ts,ctl->jitter, ctl->adapt_jitt_comp_ts, ctl->corrective_slide,ctl->count);
aymeric's avatar
aymeric committed
75 76 77 78 79 80
}

/*the goal of this method is to compute "corrective_slide": a timestamp unit'd value to be added
 to recv timestamp to make them reflect the instant they are delivered by the jitter buffer. */
void jitter_control_update_corrective_slide(JitterControl *ctl){
	int tmp;
81
	tmp=(int)(ctl->clock_offset_ts-ctl->prev_clock_offset_ts);
aymeric's avatar
aymeric committed
82 83
	if (tmp>ctl->corrective_step) {
		ctl->corrective_slide+=ctl->corrective_step;
84
		ctl->prev_clock_offset_ts=ctl->clock_offset_ts+ctl->corrective_step;
aymeric's avatar
aymeric committed
85 86 87
	}
	else if (tmp<-ctl->corrective_step) {
		ctl->corrective_slide-=ctl->corrective_step;
88
		ctl->prev_clock_offset_ts=ctl->clock_offset_ts-ctl->corrective_step;
aymeric's avatar
aymeric committed
89 90 91
	}
}

92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
void jitter_control_update_size(JitterControl *ctl, queue_t *q){
	mblk_t *newest=qlast(q);
	mblk_t *oldest=qbegin(q);
	uint32_t newest_ts,oldest_ts;
	if (newest==NULL) return;
	newest_ts=rtp_get_timestamp(newest);
	oldest_ts=rtp_get_timestamp(oldest);
	ctl->cum_jitter_buffer_count++;
	ctl->cum_jitter_buffer_size+=(uint32_t)(newest_ts-oldest_ts);
}

float jitter_control_compute_mean_size(JitterControl *ctl){
	if (ctl->cum_jitter_buffer_count!=0){
		double tmp=((double)ctl->cum_jitter_buffer_size)/(double)ctl->cum_jitter_buffer_count;
		ctl->cum_jitter_buffer_size=0;
		ctl->cum_jitter_buffer_count=0;
108 109
		ctl->jitter_buffer_mean_size = 1000.0f*(float)tmp/(float)ctl->clock_rate;
		return ctl->jitter_buffer_mean_size;
110 111 112
	}
	return 0;
}
aymeric's avatar
aymeric committed
113

114 115 116 117 118 119 120 121
void rtp_session_init_jitter_buffer(RtpSession *session){
	PayloadType *payload=NULL;
	
	if (session->rcv.pt!=-1) {
		payload = rtp_profile_get_payload (session->rcv.profile,session->rcv.pt);
	}/*else not set yet */
	jitter_control_init(&session->rtp.jittctl,payload);
}
aymeric's avatar
aymeric committed
122 123

/**
124 125
 *@param session: a RtpSession
 *@param milisec: the time interval in milisec to be jitter compensed.
aymeric's avatar
aymeric committed
126
 *
127
 * Sets the time interval for which packet are buffered instead of being delivered to the
aymeric's avatar
aymeric committed
128 129 130 131 132
 * application.
 **/
void
rtp_session_set_jitter_compensation (RtpSession * session, int milisec)
{
133 134
	session->rtp.jittctl.params.min_size = session->rtp.jittctl.params.nom_size = milisec;
	rtp_session_init_jitter_buffer(session);
aymeric's avatar
aymeric committed
135 136 137 138 139 140 141
}

void rtp_session_enable_adaptive_jitter_compensation(RtpSession *session, bool_t val){
	jitter_control_enable_adaptive(&session->rtp.jittctl,val);
}

bool_t rtp_session_adaptive_jitter_compensation_enabled(RtpSession *session){
142
	return session->rtp.jittctl.params.adaptive;
aymeric's avatar
aymeric committed
143 144 145
}

void rtp_session_enable_jitter_buffer(RtpSession *session, bool_t enabled){
146
	session->rtp.jittctl.params.enabled = enabled;
aymeric's avatar
aymeric committed
147 148 149 150
	session->flags|=RTP_SESSION_RECV_SYNC;
}

bool_t rtp_session_jitter_buffer_enabled(const RtpSession *session){
151
	return session->rtp.jittctl.params.enabled;
aymeric's avatar
aymeric committed
152 153 154
}

void rtp_session_set_jitter_buffer_params(RtpSession *session, const JBParameters *par){
155 156
	if (par == &session->rtp.jittctl.params) return;
	memcpy(&session->rtp.jittctl.params, par, sizeof (JBParameters));
157 158
	//rtp_session_init_jitter_buffer(session);
	session->rtp.jittctl.jb_size_updated = TRUE;
aymeric's avatar
aymeric committed
159 160 161
}

void rtp_session_get_jitter_buffer_params(RtpSession *session, JBParameters *par){
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
	memcpy(par, &session->rtp.jittctl.params, sizeof(JBParameters));
}


/*
 The algorithm computes two values:
	slide: an average of difference between the expected and the socket-received timestamp
	jitter: an average of the absolute value of the difference between socket-received timestamp and slide.
	slide is used to make clock-slide detection and correction.
	jitter is added to the initial jitt_comp_time value. It compensates bursty packets arrival (packets
	not arriving at regular interval ).
*/
void jitter_control_new_packet(JitterControl *ctl, uint32_t packet_ts, uint32_t cur_str_ts){
	switch (ctl->params.buffer_algorithm){
		case OrtpJitterBufferBasic:
			jitter_control_new_packet_basic (ctl, packet_ts, cur_str_ts);
		break;
		case OrtpJitterBufferRecursiveLeastSquare:
			jitter_control_new_packet_rls (ctl, packet_ts, cur_str_ts);
		break;
		default:
			ortp_fatal("No such new packet strategy: %d", ctl->params.buffer_algorithm);
		break;
	}
	ctl->count++;
}

Ghislain MARY's avatar
Ghislain MARY committed
189
static void jitter_control_update_interarrival_jitter(JitterControl *ctl, int32_t diff){
190
	/*compute interarrival jitter*/
191
	int32_t delta;
Ghislain MARY's avatar
Ghislain MARY committed
192
	delta=diff-ctl->olddiff;
193 194 195 196 197
	ctl->inter_jitter=(float) (ctl->inter_jitter+ (( (float)abs(delta) - ctl->inter_jitter)*(1/16.0)));
	ctl->olddiff=diff;
}

void jitter_control_new_packet_basic(JitterControl *ctl, uint32_t packet_ts, uint32_t cur_str_ts){
198
	int32_t diff = packet_ts - cur_str_ts;
199 200 201
	double gap,slide;

	if (ctl->count==0){
202 203
		ctl->clock_offset_ts=ctl->prev_clock_offset_ts=diff;
		slide=(double)diff;
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
		ctl->olddiff=diff;
		ctl->jitter=0;
	}else{
		slide=((double)ctl->clock_offset_ts*(1-JC_BETA)) + ((double)diff*JC_BETA);
	}
	gap=(double)diff - slide;
	gap=gap<0 ? -gap : 0; /*compute only for late packets*/
	ctl->jitter=(float) ((ctl->jitter*(1-JC_GAMMA)) + (gap*JC_GAMMA));
	jitter_control_update_interarrival_jitter(ctl, diff);
	
	if (ctl->params.adaptive){
		if (ctl->count%50==0) {
			ctl->adapt_jitt_comp_ts=(int) MAX(ctl->jitt_comp_ts,2*ctl->jitter);
			//jitter_control_dump_stats(ctl);
		}
Ghislain MARY's avatar
Ghislain MARY committed
219
		ctl->clock_offset_ts=(int32_t)slide;
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
	}else {
		/*ctl->slide and jitter size are not updated*/
	}
}

static bool_t time_for_log(JitterControl *ctl, uint32_t cur_str_ts){
	int32_t elapsed = (int32_t)(cur_str_ts - ctl->last_log_ts);
	if (elapsed >= 5*ctl->clock_rate){
		ctl->last_log_ts = cur_str_ts;
		return TRUE;
	}
	return FALSE;
}

static uint32_t jitter_control_local_ts_to_remote_ts_rls(JitterControl *ctl, uint32_t local_ts){
235
	return (uint32_t)( (int64_t)(ctl->capped_clock_ratio*(double)(local_ts - ctl->local_ts_start) + ctl->clock_offset_ts));
236 237 238 239
}

/**************************** RLS *********************************/
void jitter_control_new_packet_rls(JitterControl *ctl, uint32_t packet_ts, uint32_t cur_str_ts){
240
	int32_t diff = packet_ts - cur_str_ts;
241
	int deviation;
242 243 244 245 246 247 248 249 250
	
	if (ctl->is_diverging){
		int32_t elapsed = (int32_t)(cur_str_ts - ctl->diverged_start_ts);
		if (elapsed >= ctl->clock_rate){
			ortp_error("Jitter buffer stays unconverged for one second, reset it.");
			ctl->count = 0;
			ctl->is_diverging = FALSE;
		}
	}
251 252

	if (ctl->count==0){
253 254 255 256 257 258 259 260 261 262 263
		ctl->clock_offset_ts = ctl->prev_clock_offset_ts = (int32_t)packet_ts;
		/*
		 * Offset compensation. In order to avoid managing the rollover of the uint32_t timestamp, the timestamps passed
		 * to the kalman filter are substracted with their initial value.
		 * This allows a video stream to run 13hours (clockrate: 90 000), which looks at first sight
		 * sufficient for a VoIP application.
		 */
		ctl->local_ts_start = cur_str_ts;
		ctl->remote_ts_start = packet_ts;
		ctl->olddiff = diff;
		ctl->jitter = 0;
264

Simon Morlat's avatar
Simon Morlat committed
265
		ortp_extremum_init(&ctl->max_ts_deviation, (int)(ctl->params.refresh_ms / 1000.f * ctl->clock_rate));
266
		ortp_extremum_record_max(&ctl->max_ts_deviation, 0, (float)ctl->jitt_comp_ts);
267

268 269
		// clock rates should be the same
		ortp_kalman_rls_init(&ctl->kalman_rls, 1.0, 0.0);
270 271 272
		ctl->capped_clock_ratio = ctl->kalman_rls.m;
	}
	
273 274 275 276 277
	/*Compute the deviation from the value predicted by the kalman filter*/
	deviation = abs((int32_t)(packet_ts - jitter_control_local_ts_to_remote_ts_rls(ctl, cur_str_ts)));
	
	/*update the kalman filter*/
	ortp_kalman_rls_record(&ctl->kalman_rls, cur_str_ts - ctl->local_ts_start, packet_ts - ctl->remote_ts_start);
278

279 280 281 282 283
	ctl->capped_clock_ratio = MAX(.5, MIN(ctl->kalman_rls.m, 2));
	
	if (.5f<ctl->kalman_rls.m && ctl->kalman_rls.m<2.f){
		/*realistic clock ratio, the filter is well converged*/
		ctl->clock_offset_ts = (int32_t)((int32_t)ctl->kalman_rls.b + ctl->remote_ts_start);
284 285 286
		if (ctl->is_diverging){
			ctl->is_diverging = FALSE;
		}
287 288
	}else{
		ctl->clock_offset_ts = diff;
289 290 291 292
		if (!ctl->is_diverging){
			ctl->is_diverging = TRUE;
			ctl->diverged_start_ts = cur_str_ts;
		}
293
	}
294 295 296 297
	
	/*ortp_message("deviation=%g ms", 1000.0*deviation/(double)ctl->clock_rate);*/
	
	jitter_control_update_interarrival_jitter(ctl, diff);
298 299
	cur_str_ts -= ctl->local_ts_start;
	
300
	if (ctl->params.adaptive || ctl->jb_size_updated){
301
		bool_t max_updated = ortp_extremum_record_max(&ctl->max_ts_deviation, cur_str_ts, (float)deviation);
302 303
		float max_deviation = MAX(ortp_extremum_get_previous(&ctl->max_ts_deviation), ortp_extremum_get_current(&ctl->max_ts_deviation));
		if (max_updated && max_deviation > ctl->adapt_jitt_comp_ts){
304
			ctl->adapt_jitt_comp_ts=(int)max_deviation;
305
			ctl->jb_size_updated = TRUE;
306 307 308 309
		}else if (max_deviation < ctl->params.ramp_threshold/100.f*ctl->adapt_jitt_comp_ts){
			/*Jitter is decreasing. Make a smooth descent to avoid dropping lot of packets*/
			if ( (int32_t)(cur_str_ts - ctl->adapt_refresh_prev_ts) > ((ctl->params.ramp_refresh_ms*ctl->clock_rate)/1000)) {
				ctl->adapt_jitt_comp_ts -= (ctl->params.ramp_step_ms * ctl->clock_rate) / 1000;
310
				ctl->jb_size_updated = TRUE;
311 312
			}
		}
313
		if (ctl->jb_size_updated){
314 315 316 317 318 319 320 321
			int min_size_ts = (ctl->params.min_size * ctl->clock_rate) / 1000;
			int max_size_ts = (ctl->params.max_size * ctl->clock_rate) / 1000;
			if (ctl->adapt_jitt_comp_ts < min_size_ts){
				ctl->adapt_jitt_comp_ts = min_size_ts;
			}else if (ctl->adapt_jitt_comp_ts > max_size_ts){
				ctl->adapt_jitt_comp_ts = max_size_ts;
			}
			ctl->adapt_refresh_prev_ts = cur_str_ts;
322
			ctl->jb_size_updated = FALSE;
323 324 325
		}
	}
	if (time_for_log(ctl, cur_str_ts)){
326
		ortp_message("jitter buffer %s: target-size: %f ms, effective-size: %f (min: %i nom: %i, max: %i)",ctl->jb_size_updated ? "updated" : "stable",
327 328 329
			((float)ctl->adapt_jitt_comp_ts/(float)ctl->clock_rate)*1000.0,
			ctl->jitter_buffer_mean_size,
			ctl->params.min_size, ctl->params.nom_size, ctl->params.max_size);
330
		ortp_message("jitter buffer rls stats: count=%d, clockrate=%i"
331 332 333
			", offset=%g clock_ratio=%g"
			", capped_offset=%i capped_clock_ratio=%f"
			", max_ts_deviation=%f prev_max_ts_deviation=%f"
334
			", deviation=%i"
335
			", RLS VARIABLES: P[0][0]=%f, P[1][0]=%f, P[0][1]=%f, P[1][1]=%f"
336
			, ctl->count, ctl->clock_rate
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
			, ctl->kalman_rls.b, ctl->kalman_rls.m
			, (int) ctl->clock_offset_ts, (float)ctl->capped_clock_ratio
			, ortp_extremum_get_current(&ctl->max_ts_deviation), ortp_extremum_get_previous(&ctl->max_ts_deviation)
			, deviation
			, ctl->kalman_rls.P[0][0], ctl->kalman_rls.P[1][0], ctl->kalman_rls.P[0][1], ctl->kalman_rls.P[1][1]);
	}
}

uint32_t jitter_control_get_compensated_timestamp(JitterControl *obj , uint32_t user_ts){
	uint32_t ret = 0;
	switch (obj->params.buffer_algorithm){
		case OrtpJitterBufferBasic:
			ret = (uint32_t)( (int64_t)user_ts+obj->clock_offset_ts-(int64_t)obj->adapt_jitt_comp_ts);
		break;
		case OrtpJitterBufferRecursiveLeastSquare:
			ret = jitter_control_local_ts_to_remote_ts_rls(obj, user_ts) - obj->adapt_jitt_comp_ts;
		break;
		default:
			ortp_fatal("No such new packet strategy: %d", obj->params.buffer_algorithm);
		break;
	}
	return ret;
aymeric's avatar
aymeric committed
359 360
}