1 /*
2 * The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) implementation with additional features.
3 * Copyright (C) 2017 Belledonne Communications SARL
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 /***************************************************************************
21 * rtcp.c
22 *
23 * Wed Dec 1 11:45:30 2004
24 * Copyright 2004 Simon Morlat
25 * Email simon dot morlat at linphone dot org
26 ****************************************************************************/
27
28 #include "ortp/ortp.h"
29 #include "ortp/rtpsession.h"
30 #include "ortp/rtcp.h"
31 #include "utils.h"
32 #include "rtpsession_priv.h"
33 #include "jitterctl.h"
34
35 #define rtcp_bye_set_ssrc(b,pos,ssrc) (b)->ssrc[pos]=htonl(ssrc)
36 #define rtcp_bye_get_ssrc(b,pos) ntohl((b)->ssrc[pos])
37
38
rtcp_create_simple_bye_packet(uint32_t ssrc,const char * reason)39 static mblk_t *rtcp_create_simple_bye_packet(uint32_t ssrc, const char *reason) {
40 int packet_size;
41 int strsize = 0;
42 int strpadding = 0;
43 mblk_t *mp;
44 rtcp_bye_t *rtcp;
45
46 packet_size = RTCP_BYE_HEADER_SIZE;
47 if (reason!=NULL) {
48 strsize=(int)MIN(strlen(reason),RTCP_BYE_REASON_MAX_STRING_SIZE);
49 if (strsize > 0) {
50 strpadding = 3 - (strsize % 4);
51 packet_size += 1 + strsize + strpadding;
52 }
53 }
54 mp = allocb(packet_size, 0);
55
56 rtcp = (rtcp_bye_t*)mp->b_rptr;
57 rtcp_common_header_init(&rtcp->ch,NULL,RTCP_BYE,1,packet_size);
58 rtcp->ssrc[0] = htonl(ssrc);
59 mp->b_wptr += RTCP_BYE_HEADER_SIZE;
60 /* append the reason if any*/
61 if (reason!=NULL) {
62 const char pad[] = {0, 0, 0};
63 unsigned char strsize_octet = (unsigned char)strsize;
64
65 appendb(mp, (const char*)&strsize_octet, 1, FALSE);
66 appendb(mp, reason,strsize, FALSE);
67 appendb(mp, pad,strpadding, FALSE);
68 }
69 return mp;
70 }
71
sdes_chunk_new(uint32_t ssrc)72 static mblk_t *sdes_chunk_new(uint32_t ssrc){
73 mblk_t *m=allocb(RTCP_SDES_CHUNK_DEFAULT_SIZE,0);
74 sdes_chunk_t *sc=(sdes_chunk_t*)m->b_rptr;
75 sc->csrc=htonl(ssrc);
76 m->b_wptr+=sizeof(sc->csrc);
77 return m;
78 }
79
sdes_chunk_append_item(mblk_t * m,rtcp_sdes_type_t sdes_type,const char * content)80 static mblk_t * sdes_chunk_append_item(mblk_t *m, rtcp_sdes_type_t sdes_type, const char *content) {
81 if ( content )
82 {
83 sdes_item_t si;
84 si.item_type=sdes_type;
85 si.len=(uint8_t) MIN(strlen(content),RTCP_SDES_MAX_STRING_SIZE);
86 m=appendb(m,(char*)&si,RTCP_SDES_ITEM_HEADER_SIZE,FALSE);
87 m=appendb(m,content,si.len,FALSE);
88 }
89 return m;
90 }
91
sdes_chunk_set_ssrc(mblk_t * m,uint32_t ssrc)92 static void sdes_chunk_set_ssrc(mblk_t *m, uint32_t ssrc){
93 sdes_chunk_t *sc=(sdes_chunk_t*)m->b_rptr;
94 sc->csrc=htonl(ssrc);
95 }
96
97 #define sdes_chunk_get_ssrc(m) ntohl(((sdes_chunk_t*)((m)->b_rptr))->csrc)
98
sdes_chunk_pad(mblk_t * m)99 static mblk_t * sdes_chunk_pad(mblk_t *m){
100 return appendb(m,"",1,TRUE);
101 }
102
sdes_chunk_set_minimal_items(mblk_t * m,const char * cname)103 static mblk_t * sdes_chunk_set_minimal_items(mblk_t *m, const char *cname) {
104 if (cname == NULL) {
105 cname = "Unknown";
106 }
107 return sdes_chunk_append_item(m, RTCP_SDES_CNAME, cname);
108 }
109
sdes_chunk_set_full_items(mblk_t * m,const char * cname,const char * name,const char * email,const char * phone,const char * loc,const char * tool,const char * note)110 static mblk_t * sdes_chunk_set_full_items(mblk_t *m, const char *cname,
111 const char *name, const char *email, const char *phone, const char *loc,
112 const char *tool, const char *note) {
113 m = sdes_chunk_set_minimal_items(m, cname);
114 m = sdes_chunk_append_item(m, RTCP_SDES_NAME, name);
115 m = sdes_chunk_append_item(m, RTCP_SDES_EMAIL, email);
116 m = sdes_chunk_append_item(m, RTCP_SDES_PHONE, phone);
117 m = sdes_chunk_append_item(m, RTCP_SDES_LOC, loc);
118 m = sdes_chunk_append_item(m, RTCP_SDES_TOOL, tool);
119 m = sdes_chunk_append_item(m, RTCP_SDES_NOTE, note);
120 m = sdes_chunk_pad(m);
121 return m;
122 }
123
124 /**
125 * Set session's SDES item for automatic sending of RTCP compound packets.
126 * If some items are not specified, use NULL.
127 **/
rtp_session_set_source_description(RtpSession * session,const char * cname,const char * name,const char * email,const char * phone,const char * loc,const char * tool,const char * note)128 void rtp_session_set_source_description(RtpSession *session, const char *cname,
129 const char *name, const char *email, const char *phone, const char *loc,
130 const char *tool, const char *note) {
131 mblk_t *m;
132 mblk_t *chunk = sdes_chunk_new(session->snd.ssrc);
133 if (strlen(cname)>255) {
134 /*
135 * rfc3550,
136 * 6.5 SDES: Source Description RTCP Packet
137 * ...
138 * Note that the text can be no longer than 255 octets,
139 *
140 * */
141 ortp_warning("Cname [%s] too long for session [%p]",cname,session);
142 }
143
144 sdes_chunk_set_full_items(chunk, cname, name, email, phone, loc, tool, note);
145 if (session->full_sdes != NULL)
146 freemsg(session->full_sdes);
147 session->full_sdes = chunk;
148 chunk = sdes_chunk_new(session->snd.ssrc);
149 m = sdes_chunk_set_minimal_items(chunk, cname);
150 m = sdes_chunk_pad(m);
151 if (session->minimal_sdes != NULL)
152 freemsg(session->minimal_sdes);
153 session->minimal_sdes = chunk;
154 }
155
rtp_session_add_contributing_source(RtpSession * session,uint32_t csrc,const char * cname,const char * name,const char * email,const char * phone,const char * loc,const char * tool,const char * note)156 void rtp_session_add_contributing_source(RtpSession *session, uint32_t csrc,
157 const char *cname, const char *name, const char *email, const char *phone,
158 const char *loc, const char *tool, const char *note) {
159 mblk_t *chunk = sdes_chunk_new(csrc);
160 sdes_chunk_set_full_items(chunk, cname, name, email, phone, loc, tool, note);
161 putq(&session->contributing_sources, chunk);
162 }
163
rtp_session_remove_contributing_source(RtpSession * session,uint32_t ssrc)164 void rtp_session_remove_contributing_source(RtpSession *session, uint32_t ssrc) {
165 queue_t *q=&session->contributing_sources;
166 mblk_t *tmp;
167 for (tmp=qbegin(q); !qend(q,tmp); tmp=qnext(q,tmp)){
168 uint32_t csrc=sdes_chunk_get_ssrc(tmp);
169 if (csrc==ssrc) {
170 remq(q,tmp);
171 break;
172 }
173 }
174 tmp=rtcp_create_simple_bye_packet(ssrc, NULL);
175 rtp_session_rtcp_send(session,tmp);
176 }
177
rtcp_common_header_init(rtcp_common_header_t * ch,RtpSession * s,int type,int rc,size_t bytes_len)178 void rtcp_common_header_init(rtcp_common_header_t *ch, RtpSession *s,int type, int rc, size_t bytes_len){
179 rtcp_common_header_set_version(ch,2);
180 rtcp_common_header_set_padbit(ch,0);
181 rtcp_common_header_set_packet_type(ch,type);
182 rtcp_common_header_set_rc(ch,rc); /* as we don't yet support multi source receiving */
183 rtcp_common_header_set_length(ch,(unsigned short)((bytes_len/4)-1));
184 }
185
rtp_session_create_rtcp_sdes_packet(RtpSession * session,bool_t full)186 mblk_t* rtp_session_create_rtcp_sdes_packet(RtpSession *session, bool_t full) {
187 mblk_t *mp = allocb(sizeof(rtcp_common_header_t), 0);
188 rtcp_common_header_t *rtcp;
189 mblk_t *tmp;
190 mblk_t *m = mp;
191 mblk_t *sdes;
192 queue_t *q;
193 int rc = 0;
194
195 sdes = (full == TRUE) ? session->full_sdes : session->minimal_sdes;
196 rtcp = (rtcp_common_header_t *)mp->b_wptr;
197 mp->b_wptr += sizeof(rtcp_common_header_t);
198
199 /* Concatenate all sdes chunks. */
200 sdes_chunk_set_ssrc(sdes, session->snd.ssrc);
201 m = concatb(m, dupmsg(sdes));
202 rc++;
203
204 if (full == TRUE) {
205 q = &session->contributing_sources;
206 for (tmp = qbegin(q); !qend(q, tmp); tmp = qnext(q, mp)) {
207 m = concatb(m, dupmsg(tmp));
208 rc++;
209 }
210 }
211 rtcp_common_header_init(rtcp, session, RTCP_SDES, rc, msgdsize(mp));
212
213 return mp;
214 }
215
sender_info_init(sender_info_t * info,RtpSession * session)216 static void sender_info_init(sender_info_t *info, RtpSession *session){
217 struct timeval tv;
218 uint64_t ntp;
219 ortp_gettimeofday(&tv,NULL);
220 ntp=ortp_timeval_to_ntp(&tv);
221 info->ntp_timestamp_msw=htonl(ntp >>32);
222 info->ntp_timestamp_lsw=htonl(ntp & 0xFFFFFFFF);
223 info->rtp_timestamp=htonl(session->rtp.snd_last_ts);
224 info->senders_packet_count=(uint32_t) htonl((u_long) session->stats.packet_sent);
225 info->senders_octet_count=(uint32_t) htonl((u_long) session->rtp.sent_payload_bytes);
226 session->rtp.last_rtcp_packet_count=(uint32_t)session->stats.packet_sent;
227 }
228
report_block_init(report_block_t * b,RtpSession * session)229 static void report_block_init(report_block_t *b, RtpSession *session){
230 int packet_loss=0;
231 int loss_fraction=0;
232 RtpStream *stream=&session->rtp;
233 uint32_t delay_snc_last_sr=0;
234
235 /* compute the statistics */
236 if (stream->hwrcv_since_last_SR!=0){
237 uint32_t expected_packets=(uint32_t)(stream->hwrcv_extseq - stream->hwrcv_seq_at_last_SR);
238
239 if ( session->flags & RTCP_OVERRIDE_LOST_PACKETS ) {
240 /* If the test mode is enabled, replace the lost packet field with
241 the test vector value set by rtp_session_rtcp_set_lost_packet_value() */
242 packet_loss = session->lost_packets_test_vector;
243 /* The test value is the definite cumulative one, no need to increment
244 it each time a packet is sent */
245 session->stats.cum_packet_loss = packet_loss;
246 }else {
247 /* Normal mode */
248 packet_loss = (int)(expected_packets - stream->hwrcv_since_last_SR);
249 session->stats.cum_packet_loss += packet_loss;
250 }
251 if (expected_packets>0){/*prevent division by zero and negative loss fraction*/
252 loss_fraction=(int)( 256 * packet_loss) / expected_packets;
253 /*make sure this fits into 8 bit unsigned*/
254 if (loss_fraction>255) loss_fraction=255;
255 else if (loss_fraction<0) loss_fraction=0;
256 }else{
257 loss_fraction=0;
258 }
259 }
260 ortp_debug("report_block_init[%p]:\n"
261 "\texpected_packets=%d=%u-%u\n"
262 "\thwrcv_since_last_SR=%u\n"
263 "\tpacket_loss=%d\n"
264 "\tcum_packet_loss=%lld\n"
265 "\tloss_fraction=%f%%\n"
266 , session
267 , stream->hwrcv_extseq - stream->hwrcv_seq_at_last_SR, stream->hwrcv_extseq, stream->hwrcv_seq_at_last_SR
268 , stream->hwrcv_since_last_SR
269 , packet_loss
270 , (long long)session->stats.cum_packet_loss
271 , loss_fraction/2.56
272 );
273
274 /* reset them */
275 stream->hwrcv_since_last_SR=0;
276 stream->hwrcv_seq_at_last_SR=stream->hwrcv_extseq;
277
278 if (stream->last_rcv_SR_time.tv_sec!=0){
279 struct timeval now;
280 double delay;
281 ortp_gettimeofday(&now,NULL);
282 delay= (now.tv_sec-stream->last_rcv_SR_time.tv_sec)+ ((now.tv_usec-stream->last_rcv_SR_time.tv_usec)*1e-6);
283 delay= (delay*65536);
284 delay_snc_last_sr=(uint32_t) delay;
285 }
286
287 b->ssrc=htonl(session->rcv.ssrc);
288
289
290 report_block_set_cum_packet_lost(b, session->stats.cum_packet_loss);
291 report_block_set_fraction_lost(b, loss_fraction);
292
293 if ( session->flags & RTCP_OVERRIDE_JITTER ) {
294 /* If the test mode is enabled, replace the interarrival jitter field with the test vector value set by rtp_session_rtcp_set_jitter_value() */
295 b->interarrival_jitter = htonl( session->interarrival_jitter_test_vector );
296 }
297 else {
298 /* Normal mode */
299 b->interarrival_jitter = htonl( (uint32_t) stream->jittctl.inter_jitter );
300 }
301 b->ext_high_seq_num_rec=htonl(stream->hwrcv_extseq);
302 b->delay_snc_last_sr=htonl(delay_snc_last_sr);
303 if ( session->flags & RTCP_OVERRIDE_DELAY ) {
304 /* If the test mode is enabled, modifies the returned ts (LSR) so it matches the value of the delay test value */
305 /* refer to the rtp_session_rtcp_set_delay_value() documentation for further explanations */
306 double new_ts = ( (double)stream->last_rcv_SR_time.tv_sec + (double)stream->last_rcv_SR_time.tv_usec * 1e-6 ) - ( (double)session->delay_test_vector / 1000.0 );
307 uint32_t new_ts2;
308
309 /* Converting the time format in RFC3550 (par. 4) format */
310 new_ts += 2208988800.0; /* 2208988800 is the number of seconds from 1900 to 1970 (January 1, Oh TU) */
311 new_ts = 65536.0 * new_ts;
312 /* This non-elegant way of coding fits with the gcc and the icc compilers */
313 new_ts2 = (uint32_t)( (uint64_t)new_ts & 0xffffffff );
314 b->lsr = htonl( new_ts2 );
315 }
316 else {
317 /* Normal mode */
318 b->lsr = htonl( stream->last_rcv_SR_ts );
319 }
320 }
321
extended_statistics(RtpSession * session,report_block_t * rb)322 static void extended_statistics( RtpSession *session, report_block_t * rb ) {
323 /* the jitter raw value is kept in stream clock units */
324 uint32_t jitter = (uint32_t)session->rtp.jittctl.inter_jitter;
325 session->stats.sent_rtcp_packets ++;
326 session->rtp.jitter_stats.sum_jitter += jitter;
327 session->rtp.jitter_stats.jitter=jitter;
328 /* stores the biggest jitter for that session and its date (in millisecond) since Epoch */
329 if ( jitter > session->rtp.jitter_stats.max_jitter ) {
330 struct timeval now;
331
332 session->rtp.jitter_stats.max_jitter = jitter ;
333
334 ortp_gettimeofday( &now, NULL );
335 session->rtp.jitter_stats.max_jitter_ts = ( now.tv_sec * 1000LL ) + ( now.tv_usec / 1000LL );
336 }
337 /* compute mean jitter buffer size */
338 session->rtp.jitter_stats.jitter_buffer_size_ms=jitter_control_compute_mean_size(&session->rtp.jittctl);
339 }
340
rtcp_sr_init(RtpSession * session,uint8_t * buf,size_t size)341 static size_t rtcp_sr_init(RtpSession *session, uint8_t *buf, size_t size){
342 rtcp_sr_t *sr=(rtcp_sr_t*)buf;
343 int rr=(session->stats.packet_recv>0);
344 size_t sr_size=sizeof(rtcp_sr_t)-sizeof(report_block_t)+(rr*sizeof(report_block_t));
345 if (size<sr_size) return 0;
346 rtcp_common_header_init(&sr->ch,session,RTCP_SR,rr,sr_size);
347 sr->ssrc=htonl(session->snd.ssrc);
348 sender_info_init(&sr->si,session);
349 /*only include a report block if packets were received*/
350 if (rr) {
351 report_block_init( &sr->rb[0], session );
352 extended_statistics( session, &sr->rb[0] );
353 }
354 return sr_size;
355 }
356
rtcp_rr_init(RtpSession * session,uint8_t * buf,size_t size)357 static size_t rtcp_rr_init(RtpSession *session, uint8_t *buf, size_t size){
358 rtcp_rr_t *rr=(rtcp_rr_t*)buf;
359 if (size<sizeof(rtcp_rr_t)) return 0;
360 rtcp_common_header_init(&rr->ch,session,RTCP_RR,1,sizeof(rtcp_rr_t));
361 rr->ssrc=htonl(session->snd.ssrc);
362 report_block_init(&rr->rb[0],session);
363 extended_statistics( session, &rr->rb[0] );
364 return sizeof(rtcp_rr_t);
365 }
366
rtcp_app_init(RtpSession * session,uint8_t * buf,uint8_t subtype,const char * name,size_t size)367 static size_t rtcp_app_init(RtpSession *session, uint8_t *buf, uint8_t subtype, const char *name, size_t size){
368 rtcp_app_t *app=(rtcp_app_t*)buf;
369 if (size<sizeof(rtcp_app_t)) return 0;
370 rtcp_common_header_init(&app->ch,session,RTCP_APP,subtype,size);
371 app->ssrc=htonl(session->snd.ssrc);
372 memset(app->name,0,4);
373 strncpy(app->name,name,4);
374 return sizeof(rtcp_app_t);
375 }
376
make_rr(RtpSession * session)377 static mblk_t * make_rr(RtpSession *session) {
378 mblk_t *cm = allocb(sizeof(rtcp_sr_t), 0);
379 cm->b_wptr += rtcp_rr_init(session, cm->b_wptr, sizeof(rtcp_rr_t));
380 return cm;
381 }
382
make_sr(RtpSession * session)383 static mblk_t * make_sr(RtpSession *session) {
384 mblk_t *cm = allocb(sizeof(rtcp_sr_t), 0);
385 cm->b_wptr += rtcp_sr_init(session, cm->b_wptr, sizeof(rtcp_sr_t));
386 return cm;
387 }
388
append_sdes(RtpSession * session,mblk_t * m,bool_t full)389 static mblk_t * append_sdes(RtpSession *session, mblk_t *m, bool_t full) {
390 mblk_t *sdes = NULL;
391
392 if ((full == TRUE) && (session->full_sdes != NULL)) {
393 sdes = rtp_session_create_rtcp_sdes_packet(session, full);
394 } else if ((full == FALSE) && (session->minimal_sdes != NULL)) {
395 sdes = rtp_session_create_rtcp_sdes_packet(session, full);
396 }
397 return concatb(m, sdes);
398 }
399
notify_sent_rtcp(RtpSession * session,mblk_t * rtcp)400 static void notify_sent_rtcp(RtpSession *session, mblk_t *rtcp){
401 if (session->eventqs!=NULL){
402 OrtpEvent *ev;
403 OrtpEventData *evd;
404 ev=ortp_event_new(ORTP_EVENT_RTCP_PACKET_EMITTED);
405 evd=ortp_event_get_data(ev);
406 evd->packet=dupmsg(rtcp);
407 msgpullup(evd->packet,-1);
408 rtp_session_dispatch_event(session,ev);
409 }
410 }
411
append_xr_packets(RtpSession * session,mblk_t * m)412 static void append_xr_packets(RtpSession *session, mblk_t *m) {
413 if (session->rtcp.xr_conf.rcvr_rtt_mode != OrtpRtcpXrRcvrRttNone) {
414 concatb(m, make_xr_rcvr_rtt(session));
415 }
416 if (session->rtcp.rtcp_xr_dlrr_to_send == TRUE) {
417 concatb(m, make_xr_dlrr(session));
418 session->rtcp.rtcp_xr_dlrr_to_send = FALSE;
419 }
420 if (session->rtcp.xr_conf.stat_summary_enabled == TRUE) {
421 concatb(m, make_xr_stat_summary(session));
422 }
423 if (session->rtcp.xr_conf.voip_metrics_enabled == TRUE) {
424 concatb(m, make_xr_voip_metrics(session));
425 }
426 }
427
append_fb_packets(RtpSession * session,mblk_t * m)428 static void append_fb_packets(RtpSession *session, mblk_t *m) {
429 if (session->rtcp.send_algo.fb_packets != NULL) {
430 concatb(m, session->rtcp.send_algo.fb_packets);
431 session->rtcp.send_algo.fb_packets = NULL;
432 }
433
434 /* Repeat TMMBR packets until they are acknowledged with a TMMBN unless a TMMBN is being sent. */
435 if (rtp_session_avpf_feature_enabled(session, ORTP_AVPF_FEATURE_TMMBR)
436 && (session->rtcp.tmmbr_info.sent != NULL)
437 && (session->rtcp.send_algo.tmmbr_scheduled != TRUE)
438 && (session->rtcp.send_algo.tmmbn_scheduled != TRUE)) {
439 concatb(m, copymsg(session->rtcp.tmmbr_info.sent));
440 }
441
442 session->rtcp.send_algo.tmmbr_scheduled = FALSE;
443 session->rtcp.send_algo.tmmbn_scheduled = FALSE;
444 }
445
rtp_session_create_and_send_rtcp_packet(RtpSession * session,bool_t full)446 static void rtp_session_create_and_send_rtcp_packet(RtpSession *session, bool_t full) {
447 mblk_t *m=NULL;
448 bool_t is_sr = FALSE;
449
450 if (session->rtp.last_rtcp_packet_count < session->stats.packet_sent) {
451 m = make_sr(session);
452 session->rtp.last_rtcp_packet_count = (uint32_t)session->stats.packet_sent;
453 is_sr = TRUE;
454 } else if (session->stats.packet_recv > 0) {
455 /* Don't send RR when no packet are received yet */
456 m = make_rr(session);
457 is_sr = FALSE;
458 }
459 if (m != NULL) {
460 append_sdes(session, m, full);
461 if ((full == TRUE) && (session->rtcp.xr_conf.enabled == TRUE)) {
462 append_xr_packets(session, m);
463 }
464 if (rtp_session_avpf_enabled(session) == TRUE) {
465 append_fb_packets(session, m);
466 }
467 /* Send the compound packet */
468 notify_sent_rtcp(session, m);
469 ortp_message("Sending RTCP %s compound message on session [%p].",(is_sr ? "SR" : "RR"), session);
470 rtp_session_rtcp_send(session, m);
471 }
472 }
473
rtcp_rand(float t)474 static float rtcp_rand(float t) {
475 return t * ((rand() / (RAND_MAX * 1.0f)) + 0.5f);
476 }
477
478 /**
479 * This is a simplified version with this limit of the algorithm described in
480 * the appendix A.7 of RFC3550.
481 */
compute_rtcp_interval(RtpSession * session)482 void compute_rtcp_interval(RtpSession *session) {
483 float t;
484 float rtcp_min_time;
485 float rtcp_bw;
486
487 if (session->target_upload_bandwidth == 0) return;
488
489 /* Compute target RTCP bandwidth in bits/s. */
490 rtcp_bw = 0.05f * session->target_upload_bandwidth;
491
492 if (rtp_session_avpf_enabled(session) == TRUE) {
493 session->rtcp.send_algo.T_rr_interval = rtp_session_get_avpf_rr_interval(session);
494 rtcp_min_time = (float)session->rtcp.send_algo.Tmin;
495 } else {
496 rtcp_min_time = (float)session->rtcp.send_algo.T_rr_interval;
497 if (session->rtcp.send_algo.initial == TRUE) {
498 rtcp_min_time /= 2.;
499 }
500 }
501
502 t = ((session->rtcp.send_algo.avg_rtcp_size * 8 * 2) / rtcp_bw) * 1000;
503 if (t < rtcp_min_time) t = rtcp_min_time;
504 t = rtcp_rand(t);
505 t = t / (2.71828f - 1.5f); /* Compensation */
506 session->rtcp.send_algo.T_rr = (uint32_t)t;
507 }
508
update_avg_rtcp_size(RtpSession * session,int bytes)509 void update_avg_rtcp_size(RtpSession *session, int bytes) {
510 int overhead = (ortp_stream_is_ipv6(&session->rtcp.gs) == TRUE) ? IP6_UDP_OVERHEAD : IP_UDP_OVERHEAD;
511 int size = bytes + overhead;
512 session->rtcp.send_algo.avg_rtcp_size = ((size + (15 * session->rtcp.send_algo.avg_rtcp_size)) / 16.f);
513 }
514
rtp_session_schedule_first_rtcp_send(RtpSession * session)515 static void rtp_session_schedule_first_rtcp_send(RtpSession *session) {
516 uint64_t tc;
517 size_t overhead;
518 size_t report_size;
519 size_t sdes_size;
520 size_t xr_size = 0;
521 OrtpRtcpSendAlgorithm *sa = &session->rtcp.send_algo;
522
523 if ((session->rtcp.enabled == FALSE) || (session->target_upload_bandwidth == 0) || (sa->initialized == TRUE))
524 return;
525
526 overhead = (ortp_stream_is_ipv6(&session->rtcp.gs) == TRUE) ? IP6_UDP_OVERHEAD : IP_UDP_OVERHEAD;
527 sdes_size = (session->full_sdes != NULL) ? msgdsize(session->full_sdes) + sizeof(rtcp_common_header_t) : 0;
528 switch (session->mode) {
529 case RTP_SESSION_RECVONLY:
530 report_size = sizeof(rtcp_rr_t);
531 break;
532 case RTP_SESSION_SENDONLY:
533 report_size = sizeof(rtcp_sr_t) - sizeof(report_block_t);
534 break;
535 case RTP_SESSION_SENDRECV:
536 default:
537 report_size = sizeof(rtcp_sr_t);
538 break;
539 }
540 if (session->rtcp.xr_conf.enabled == TRUE) {
541 if (session->rtcp.xr_conf.rcvr_rtt_mode != OrtpRtcpXrRcvrRttNone)
542 xr_size += sizeof(rtcp_xr_header_t) + sizeof(rtcp_xr_rcvr_rtt_report_block_t);
543 if (session->rtcp.xr_conf.stat_summary_enabled == TRUE)
544 xr_size += sizeof(rtcp_xr_header_t) + sizeof(rtcp_xr_stat_summary_report_block_t);
545 if (session->rtcp.xr_conf.voip_metrics_enabled == TRUE)
546 xr_size += sizeof(rtcp_xr_header_t) + sizeof(rtcp_xr_voip_metrics_report_block_t);
547 }
548 sa->avg_rtcp_size = (float)(overhead + report_size + sdes_size + xr_size);
549 sa->initialized = TRUE;
550
551 tc = ortp_get_cur_time_ms();
552 compute_rtcp_interval(session);
553 if (sa->T_rr > 0) sa->tn = tc + sa->T_rr;
554 sa->tp = tc;
555 sa->t_rr_last = tc;
556 sa->Tmin = 0;
557 }
558
rtp_session_reschedule(RtpSession * session,uint64_t tc)559 static void rtp_session_reschedule(RtpSession *session, uint64_t tc) {
560 OrtpRtcpSendAlgorithm *sa = &session->rtcp.send_algo;
561 if (rtp_session_avpf_enabled(session) == TRUE) {
562 sa->tp = tc;
563 sa->tn = tc + sa->T_rr;
564 }
565 }
566
rtp_session_send_regular_rtcp_packet_and_reschedule(RtpSession * session,uint64_t tc)567 void rtp_session_send_regular_rtcp_packet_and_reschedule(RtpSession *session, uint64_t tc) {
568 OrtpRtcpSendAlgorithm *sa = &session->rtcp.send_algo;
569 rtp_session_create_and_send_rtcp_packet(session, TRUE);
570 sa->tp = tc;
571 sa->t_rr_last = sa->tn;
572 compute_rtcp_interval(session);
573 sa->tn = tc + sa->T_rr;
574 sa->initial = FALSE;
575 }
576
rtp_session_send_fb_rtcp_packet_and_reschedule(RtpSession * session)577 void rtp_session_send_fb_rtcp_packet_and_reschedule(RtpSession *session) {
578 uint64_t previous_tn;
579 OrtpRtcpSendAlgorithm *sa = &session->rtcp.send_algo;
580 rtp_session_create_and_send_rtcp_packet(session, FALSE);
581 sa->allow_early = FALSE;
582 previous_tn = sa->tn;
583 sa->tn = sa->tp + 2 * sa->T_rr;
584 sa->tp = previous_tn;
585 }
586
rtp_session_run_rtcp_send_scheduler(RtpSession * session)587 void rtp_session_run_rtcp_send_scheduler(RtpSession *session) {
588 uint64_t tc = ortp_get_cur_time_ms();
589 OrtpRtcpSendAlgorithm *sa = &session->rtcp.send_algo;
590
591 if (tc >= sa->tn) {
592 compute_rtcp_interval(session);
593 sa->tn = sa->tp + sa->T_rr;
594 if (tc >= sa->tn) {
595 if (sa->t_rr_last == 0) {
596 rtp_session_schedule_first_rtcp_send(session);
597 } else {
598 if (sa->T_rr_interval != 0) {
599 sa->T_rr_current_interval = (uint32_t)rtcp_rand((float)sa->T_rr_interval);
600 } else {
601 sa->T_rr_current_interval = 0;
602 }
603 if (sa->tn >= (sa->t_rr_last + sa->T_rr_current_interval)) {
604 rtp_session_send_regular_rtcp_packet_and_reschedule(session, tc);
605 } else if (rtp_session_has_fb_packets_to_send(session) == TRUE) {
606 rtp_session_send_fb_rtcp_packet_and_reschedule(session);
607 } else {
608 rtp_session_reschedule(session, tc);
609 }
610 }
611 }
612 }
613 }
614
rtp_session_rtcp_process_send(RtpSession * session)615 void rtp_session_rtcp_process_send(RtpSession *session) {
616 rtp_session_run_rtcp_send_scheduler(session);
617 }
618
rtp_session_rtcp_process_recv(RtpSession * session)619 void rtp_session_rtcp_process_recv(RtpSession *session){
620 rtp_session_run_rtcp_send_scheduler(session);
621 }
622
rtp_session_send_rtcp_APP(RtpSession * session,uint8_t subtype,const char * name,const uint8_t * data,int datalen)623 void rtp_session_send_rtcp_APP(RtpSession *session, uint8_t subtype, const char *name, const uint8_t *data, int datalen){
624 mblk_t *h=allocb(sizeof(rtcp_app_t),0);
625 mblk_t *d;
626 h->b_wptr+=rtcp_app_init(session,h->b_wptr,subtype,name,datalen+sizeof(rtcp_app_t));
627 d=esballoc((uint8_t*)data,datalen,0,NULL);
628 d->b_wptr+=datalen;
629 h->b_cont=d;
630 rtp_session_rtcp_send(session,h);
631 }
632
633 /**
634 * Sends a RTCP bye packet.
635 *@param session RtpSession
636 *@param reason the reason phrase.
637 **/
rtp_session_bye(RtpSession * session,const char * reason)638 int rtp_session_bye(RtpSession *session, const char *reason) {
639 mblk_t *cm;
640 mblk_t *sdes = NULL;
641 mblk_t *bye = NULL;
642 int ret;
643
644 /* Make a BYE packet (will be on the end of the compund packet). */
645 bye = rtcp_create_simple_bye_packet(session->snd.ssrc, reason);
646
647 /* SR or RR is determined by the fact whether stream was sent*/
648 if (session->stats.packet_sent>0)
649 {
650 cm = allocb(sizeof(rtcp_sr_t), 0);
651 cm->b_wptr += rtcp_sr_init(session,cm->b_wptr, sizeof(rtcp_sr_t));
652 /* make a SDES packet */
653 sdes = rtp_session_create_rtcp_sdes_packet(session, TRUE);
654 /* link them */
655 concatb(concatb(cm, sdes), bye);
656 } else if (session->stats.packet_recv>0){
657 /* make a RR packet */
658 cm = allocb(sizeof(rtcp_rr_t), 0);
659 cm->b_wptr += rtcp_rr_init(session, cm->b_wptr, sizeof(rtcp_rr_t));
660 /* link them */
661 cm->b_cont = bye;
662 }else cm=bye;
663
664 /* Send compound packet. */
665 ret = rtp_session_rtcp_send(session, cm);
666
667 return ret;
668 }
669
ortp_loss_rate_estimator_new(int min_packet_count_interval,uint64_t min_time_ms_interval,RtpSession * session)670 OrtpLossRateEstimator * ortp_loss_rate_estimator_new(int min_packet_count_interval, uint64_t min_time_ms_interval, RtpSession *session){
671 OrtpLossRateEstimator *obj=ortp_malloc(sizeof(OrtpLossRateEstimator));
672 ortp_loss_rate_estimator_init(obj,min_packet_count_interval, min_time_ms_interval, session);
673 return obj;
674 }
675
ortp_loss_rate_estimator_init(OrtpLossRateEstimator * obj,int min_packet_count_interval,uint64_t min_time_ms_interval,RtpSession * session)676 void ortp_loss_rate_estimator_init(OrtpLossRateEstimator *obj, int min_packet_count_interval, uint64_t min_time_ms_interval, RtpSession *session){
677 memset(obj,0,sizeof(*obj));
678 obj->min_packet_count_interval=min_packet_count_interval;
679 obj->last_ext_seq=rtp_session_get_seq_number(session);
680 obj->last_cum_loss=rtp_session_get_cum_loss(session);
681 obj->last_packet_sent_count=session->stats.packet_sent;
682 obj->last_dup_packet_sent_count=session->stats.packet_dup_sent;
683 obj->min_time_ms_interval=min_time_ms_interval;
684 obj->last_estimate_time_ms=(uint64_t)-1;
685 }
686
ortp_loss_rate_estimator_process_report_block(OrtpLossRateEstimator * obj,const RtpSession * session,const report_block_t * rb)687 bool_t ortp_loss_rate_estimator_process_report_block(OrtpLossRateEstimator *obj, const RtpSession *session, const report_block_t *rb){
688 int32_t cum_loss=report_block_get_cum_packet_lost(rb);
689 int32_t extseq=report_block_get_high_ext_seq(rb);
690 //int32_t diff_unique_outgoing=(int32_t)(session->stats.packet_sent-obj->last_packet_sent_count);
691 //int32_t diff_total_outgoing=diff_unique_outgoing+(int32_t)(session->stats.packet_dup_sent-obj->last_dup_packet_sent_count);
692 int32_t diff;
693 uint64_t curtime;
694 bool_t got_value=FALSE;
695
696 if (obj->last_ext_seq==-1 || obj->last_estimate_time_ms==(uint64_t)-1){
697 /*first report cannot be considered, since we don't know the interval it covers*/
698 obj->last_ext_seq=extseq;
699 obj->last_cum_loss=cum_loss;
700 obj->last_estimate_time_ms=ortp_get_cur_time_ms();
701 return FALSE;
702 }
703 diff=extseq-obj->last_ext_seq;
704 curtime=ortp_get_cur_time_ms();
705 if (diff<0 || diff>obj->min_packet_count_interval * 100){
706 if (extseq==0){
707 /*when extseq reset to 0, it probably means that rtp_session_sync was called but
708 since OrtplossRateEstimator is not reset, first RTCP packet received will be detected
709 as discontinuity instead of init RTCP packet. Avoid logging in such case.*/
710 ortp_message("ortp_loss_rate_estimator_process %p: Suspected RTP session restart, sequence numbering from %d to %d.", obj, obj->last_ext_seq, extseq);
711 }else{
712 ortp_warning("ortp_loss_rate_estimator_process %p: Suspected discontinuity in sequence numbering from %d to %d.", obj, obj->last_ext_seq, extseq);
713 }
714 obj->last_ext_seq=extseq;
715 obj->last_cum_loss=cum_loss;
716 obj->last_packet_sent_count=session->stats.packet_sent;
717 obj->last_dup_packet_sent_count=session->stats.packet_dup_sent;
718 }else if (diff>obj->min_packet_count_interval && curtime-obj->last_estimate_time_ms>=obj->min_time_ms_interval){
719 /*we have sufficient interval*/
720 int32_t new_losses=cum_loss-obj->last_cum_loss;
721
722 #if 0 /*SM: the following code try to takes into account sent duplicates - however by doing this it creates a bias in the loss rate computation
723 that can sometimes result in a negative loss rate, even if there is no duplicate.
724 Since the rate control doesn't use duplicates anymore, there is no good reason to take this into account.
725 */
726 /*if we are using duplicates, they will not be visible in 'diff' variable.
727 But since we are the emitter, we can retrieve the total count of packet we
728 sent and use this value to compute the loss rate instead.*/
729 obj->loss_rate = 100.f * (1.f - MAX(0, (diff_unique_outgoing - new_losses) * 1.f / diff_total_outgoing));
730 #endif
731 obj->loss_rate = 100.f * (float) new_losses / (float)( extseq - obj->last_ext_seq);
732
733 /*update last values with current*/
734 got_value=TRUE;
735 obj->last_estimate_time_ms=curtime;
736
737 if (obj->loss_rate>100.f){
738 obj->loss_rate = 100.f;
739 ortp_error("ortp_loss_rate_estimator_process %p: Loss rate MUST NOT be greater than 100%%", obj);
740 }else if(obj->loss_rate < 0){
741 obj->loss_rate = 0;
742 ortp_error("ortp_loss_rate_estimator_process %p: Loss rate MUST NOT be negative", obj);
743 }
744 obj->last_ext_seq=extseq;
745 obj->last_cum_loss=cum_loss;
746 obj->last_packet_sent_count=session->stats.packet_sent;
747 obj->last_dup_packet_sent_count=session->stats.packet_dup_sent;
748 }
749 return got_value;
750
751 }
752
ortp_loss_rate_estimator_get_value(OrtpLossRateEstimator * obj)753 float ortp_loss_rate_estimator_get_value(OrtpLossRateEstimator *obj){
754 return obj->loss_rate;
755 }
756
ortp_loss_rate_estimator_destroy(OrtpLossRateEstimator * obj)757 void ortp_loss_rate_estimator_destroy(OrtpLossRateEstimator *obj){
758 ortp_free(obj);
759 }
760