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 #include <math.h>
22
23 #include "ortp/ortp.h"
24 #include "ortp/rtpsession.h"
25 #include "ortp/rtcp.h"
26 #include "rtpsession_priv.h"
27 #include "utils.h"
28
29
calc_rate(double d1,double d2)30 static uint8_t calc_rate(double d1, double d2) {
31 double rate = (d1 / d2) * 256;
32 uint32_t int_rate = (uint32_t)rate;
33 if (int_rate > 255) int_rate = 255;
34 return (uint8_t)int_rate;
35 }
36
rtcp_xr_header_init(uint8_t * buf,RtpSession * session,int bytes_len)37 static int rtcp_xr_header_init(uint8_t *buf, RtpSession *session, int bytes_len) {
38 rtcp_xr_header_t *header = (rtcp_xr_header_t *)buf;
39 rtcp_common_header_init(&header->ch, session, RTCP_XR, 0, bytes_len);
40 header->ssrc = htonl(session->snd.ssrc);
41 return sizeof(rtcp_xr_header_t);
42 }
43
rtcp_xr_rcvr_rtt_init(uint8_t * buf,RtpSession * session)44 static int rtcp_xr_rcvr_rtt_init(uint8_t *buf, RtpSession *session) {
45 struct timeval tv;
46 uint64_t ntp;
47 rtcp_xr_rcvr_rtt_report_block_t *block = (rtcp_xr_rcvr_rtt_report_block_t *)buf;
48
49 block->bh.bt = RTCP_XR_RCVR_RTT;
50 block->bh.flags = 0; // Reserved bits
51 block->bh.length = htons(2);
52 ortp_gettimeofday(&tv, NULL);
53 ntp = ortp_timeval_to_ntp(&tv);
54 block->ntp_timestamp_msw = htonl(ntp >> 32);
55 block->ntp_timestamp_lsw = htonl(ntp & 0xFFFFFFFF);
56 return sizeof(rtcp_xr_rcvr_rtt_report_block_t);
57 }
58
rtcp_xr_dlrr_init(uint8_t * buf,RtpSession * session)59 static int rtcp_xr_dlrr_init(uint8_t *buf, RtpSession *session) {
60 uint32_t dlrr = 0;
61 rtcp_xr_dlrr_report_block_t *block = (rtcp_xr_dlrr_report_block_t *)buf;
62
63 block->bh.bt = RTCP_XR_DLRR;
64 block->bh.flags = 0; // Reserved bits
65 block->bh.length = htons(3);
66 block->content[0].ssrc = htonl(rtp_session_get_recv_ssrc(session));
67 block->content[0].lrr = htonl(session->rtcp_xr_stats.last_rcvr_rtt_ts);
68 if (session->rtcp_xr_stats.last_rcvr_rtt_time.tv_sec != 0) {
69 struct timeval now;
70 double delay;
71 ortp_gettimeofday(&now, NULL);
72 delay = ((now.tv_sec - session->rtcp_xr_stats.last_rcvr_rtt_time.tv_sec)
73 + ((now.tv_usec - session->rtcp_xr_stats.last_rcvr_rtt_time.tv_usec) * 1e-6)) * 65536;
74 dlrr = (uint32_t) delay;
75 }
76 block->content[0].dlrr = htonl(dlrr);
77 return sizeof(rtcp_xr_dlrr_report_block_t);
78 }
79
rtcp_xr_stat_summary_init(uint8_t * buf,RtpSession * session)80 static int rtcp_xr_stat_summary_init(uint8_t *buf, RtpSession *session) {
81 rtcp_xr_stat_summary_report_block_t *block = (rtcp_xr_stat_summary_report_block_t *)buf;
82 uint16_t last_rcv_seq = session->rtp.hwrcv_extseq & 0xFFFF;
83 uint8_t flags = session->rtcp.xr_conf.stat_summary_flags;
84 uint32_t expected_packets;
85 uint32_t lost_packets = 0;
86 uint32_t dup_packets = session->rtcp_xr_stats.dup_since_last_stat_summary;
87
88 /* Compute lost and duplicate packets statistics */
89 if (flags & OrtpRtcpXrStatSummaryLoss) {
90 uint32_t no_duplicate_received = session->rtcp_xr_stats.rcv_since_last_stat_summary - dup_packets;
91 expected_packets = last_rcv_seq - session->rtcp_xr_stats.rcv_seq_at_last_stat_summary;
92 lost_packets = (expected_packets > session->rtcp_xr_stats.rcv_since_last_stat_summary)
93 ? (expected_packets - no_duplicate_received) : 0;
94 }
95
96 block->bh.bt = RTCP_XR_STAT_SUMMARY;
97 block->bh.flags = flags;
98 block->bh.length = htons(9);
99 block->ssrc = htonl(rtp_session_get_recv_ssrc(session));
100 block->begin_seq = htons(session->rtcp_xr_stats.rcv_seq_at_last_stat_summary + 1);
101 block->end_seq = htons(last_rcv_seq + 1);
102 block->lost_packets = htonl(lost_packets);
103 block->dup_packets = htonl(dup_packets);
104 if ((flags & OrtpRtcpXrStatSummaryJitt)
105 && (session->rtcp_xr_stats.rcv_since_last_stat_summary > 0)) {
106 block->min_jitter = htonl(session->rtcp_xr_stats.min_jitter_since_last_stat_summary);
107 block->max_jitter = htonl(session->rtcp_xr_stats.max_jitter_since_last_stat_summary);
108 block->mean_jitter = htonl((session->rtcp_xr_stats.rcv_since_last_stat_summary > 1)
109 ? (uint32_t)session->rtcp_xr_stats.newm_jitter_since_last_stat_summary : 0);
110 block->dev_jitter = htonl((session->rtcp_xr_stats.rcv_since_last_stat_summary > 2)
111 ? (uint32_t)sqrt(session->rtcp_xr_stats.news_jitter_since_last_stat_summary / (session->rtcp_xr_stats.rcv_since_last_stat_summary - 2)) : 0);
112 } else {
113 block->min_jitter = htonl(0);
114 block->max_jitter = htonl(0);
115 block->mean_jitter = htonl(0);
116 block->dev_jitter = htonl(0);
117 }
118 if ((flags & (OrtpRtcpXrStatSummaryTTL | OrtpRtcpXrStatSummaryHL))
119 && (session->rtcp_xr_stats.rcv_since_last_stat_summary > 0)) {
120 block->min_ttl_or_hl = session->rtcp_xr_stats.min_ttl_or_hl_since_last_stat_summary;
121 block->max_ttl_or_hl = session->rtcp_xr_stats.max_ttl_or_hl_since_last_stat_summary;
122 block->mean_ttl_or_hl = (session->rtcp_xr_stats.rcv_since_last_stat_summary > 0)
123 ? (uint8_t)session->rtcp_xr_stats.newm_ttl_or_hl_since_last_stat_summary : 0;
124 block->dev_ttl_or_hl = (session->rtcp_xr_stats.rcv_since_last_stat_summary > 1)
125 ? (uint8_t)sqrt(session->rtcp_xr_stats.news_ttl_or_hl_since_last_stat_summary / (session->rtcp_xr_stats.rcv_since_last_stat_summary - 1)) : 0;
126 } else {
127 block->min_ttl_or_hl = 0;
128 block->max_ttl_or_hl = 0;
129 block->mean_ttl_or_hl = 0;
130 block->dev_ttl_or_hl = 0;
131 }
132
133 session->rtcp_xr_stats.rcv_seq_at_last_stat_summary = last_rcv_seq;
134 session->rtcp_xr_stats.rcv_since_last_stat_summary = 0;
135 session->rtcp_xr_stats.dup_since_last_stat_summary = 0;
136
137 return sizeof(rtcp_xr_stat_summary_report_block_t);
138 }
139
rtcp_xr_voip_metrics_init(uint8_t * buf,RtpSession * session)140 static int rtcp_xr_voip_metrics_init(uint8_t *buf, RtpSession *session) {
141 JBParameters jbparams;
142 uint32_t expected_packets;
143 uint32_t lost_packets;
144 rtcp_xr_voip_metrics_report_block_t *block = (rtcp_xr_voip_metrics_report_block_t *)buf;
145 float rtt = rtp_session_get_round_trip_propagation(session);
146 uint16_t int_rtt = (uint16_t)((rtt >= 0) ? (rtt * 1000) : 0);
147 float qi = -1;
148 float lq_qi = -1;
149
150 rtp_session_get_jitter_buffer_params(session, &jbparams);
151 if (session->rtcp.xr_media_callbacks.average_qi != NULL) {
152 qi = session->rtcp.xr_media_callbacks.average_qi(session->rtcp.xr_media_callbacks.userdata);
153 }
154 if (session->rtcp.xr_media_callbacks.average_lq_qi != NULL) {
155 lq_qi = session->rtcp.xr_media_callbacks.average_lq_qi(session->rtcp.xr_media_callbacks.userdata);
156 }
157
158 block->bh.bt = RTCP_XR_VOIP_METRICS;
159 block->bh.flags = 0; // Reserved bits
160 block->bh.length = htons(8);
161 block->ssrc = htonl(rtp_session_get_recv_ssrc(session));
162 block->gmin = RTCP_XR_GMIN;
163 block->reserved2 = 0;
164
165 // Fill RX config
166 block->rx_config = 0;
167 if (jbparams.adaptive) {
168 block->rx_config |= RTCP_XR_VOIP_METRICS_CONFIG_JBA_ADA;
169 } else {
170 block->rx_config |= RTCP_XR_VOIP_METRICS_CONFIG_JBA_NON;
171 }
172 if (session->rtcp.xr_media_callbacks.plc != NULL) {
173 switch (session->rtcp.xr_media_callbacks.plc(session->rtcp.xr_media_callbacks.userdata)) {
174 default:
175 case OrtpRtcpXrNoPlc:
176 block->rx_config |= RTCP_XR_VOIP_METRICS_CONFIG_PLC_UNS;
177 break;
178 case OrtpRtcpXrSilencePlc:
179 block->rx_config |= RTCP_XR_VOIP_METRICS_CONFIG_PLC_DIS;
180 break;
181 case OrtpRtcpXrEnhancedPlc:
182 block->rx_config |= RTCP_XR_VOIP_METRICS_CONFIG_PLC_ENH;
183 break;
184 }
185 } else {
186 block->rx_config |= RTCP_XR_VOIP_METRICS_CONFIG_PLC_UNS;
187 }
188
189 // Fill JB fields
190 block->jb_nominal = htons((uint16_t)jbparams.nom_size);
191 if (jbparams.adaptive) {
192 block->jb_maximum = htons((session->rtp.jittctl.adapt_jitt_comp_ts * 1000) / session->rtp.jittctl.clock_rate);
193 } else {
194 block->jb_maximum = block->jb_nominal;
195 }
196 block->jb_abs_max = htons(65535);
197
198 if (session->rtcp_xr_stats.rcv_count > 0) {
199 expected_packets = session->rtcp_xr_stats.last_rcv_seq - session->rtcp_xr_stats.first_rcv_seq + 1;
200 lost_packets = expected_packets - session->rtcp_xr_stats.rcv_count;
201 block->loss_rate = calc_rate((double)lost_packets, (double)expected_packets);
202 block->discard_rate = calc_rate((double)session->rtcp_xr_stats.discarded_count, (double)expected_packets);
203 // TODO: fill burst_density, gap_density, burst_duration, gap_duration
204 block->burst_density = 0;
205 block->gap_density = 0;
206 block->burst_duration = htons(0);
207 block->gap_duration = htons(0);
208 block->round_trip_delay = htons(int_rtt);
209 // TODO: fill end_system_delay
210 block->end_system_delay = htons(0);
211 if (session->rtcp.xr_media_callbacks.signal_level != NULL) {
212 block->signal_level = session->rtcp.xr_media_callbacks.signal_level(session->rtcp.xr_media_callbacks.userdata);
213 } else {
214 block->signal_level = ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
215 }
216 if (session->rtcp.xr_media_callbacks.noise_level != NULL) {
217 block->noise_level = session->rtcp.xr_media_callbacks.noise_level(session->rtcp.xr_media_callbacks.userdata);
218 } else {
219 block->noise_level = ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
220 }
221 block->rerl = ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
222 if (qi < 0) {
223 block->r_factor = ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
224 } else {
225 block->r_factor = (uint8_t)(qi * 20);
226 }
227 block->ext_r_factor = ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
228 if (lq_qi < 0) {
229 block->mos_lq = ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
230 } else {
231 block->mos_lq = (uint8_t)(lq_qi * 10);
232 if (block->mos_lq < 10) block->mos_lq = 10;
233 }
234 if (qi < 0) {
235 block->mos_cq = ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
236 } else {
237 block->mos_cq = (uint8_t)(qi * 10);
238 if (block->mos_cq < 10) block->mos_cq = 10;
239 }
240 } else {
241 block->loss_rate = 0;
242 block->discard_rate = 0;
243 block->burst_density = 0;
244 block->gap_density = 0;
245 block->burst_duration = htons(0);
246 block->gap_duration = htons(0);
247 block->round_trip_delay = htons(0);
248 block->end_system_delay = htons(0);
249 block->signal_level = ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
250 block->noise_level = ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
251 block->rerl = ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
252 block->r_factor = ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
253 block->ext_r_factor = ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
254 block->mos_lq = ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
255 block->mos_cq = ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
256 }
257 return sizeof(rtcp_xr_voip_metrics_report_block_t);
258 }
259
260
make_xr_rcvr_rtt(RtpSession * session)261 mblk_t * make_xr_rcvr_rtt(RtpSession *session) {
262 int size = sizeof(rtcp_xr_header_t) + sizeof(rtcp_xr_rcvr_rtt_report_block_t);
263 mblk_t *h = allocb(size, 0);
264 h->b_wptr += rtcp_xr_header_init(h->b_wptr, session, size);
265 h->b_wptr += rtcp_xr_rcvr_rtt_init(h->b_wptr, session);
266 return h;
267 }
268
make_xr_dlrr(RtpSession * session)269 mblk_t * make_xr_dlrr(RtpSession *session) {
270 int size = sizeof(rtcp_xr_header_t) + sizeof(rtcp_xr_dlrr_report_block_t);
271 mblk_t *h = allocb(size, 0);
272 h->b_wptr += rtcp_xr_header_init(h->b_wptr, session, size);
273 h->b_wptr += rtcp_xr_dlrr_init(h->b_wptr, session);
274 return h;
275 }
276
make_xr_stat_summary(RtpSession * session)277 mblk_t * make_xr_stat_summary(RtpSession *session) {
278 int size = sizeof(rtcp_xr_header_t) + sizeof(rtcp_xr_stat_summary_report_block_t);
279 mblk_t *h = allocb(size, 0);
280 h->b_wptr += rtcp_xr_header_init(h->b_wptr, session, size);
281 h->b_wptr += rtcp_xr_stat_summary_init(h->b_wptr, session);
282 return h;
283 }
284
make_xr_voip_metrics(RtpSession * session)285 mblk_t * make_xr_voip_metrics(RtpSession *session) {
286 int size = sizeof(rtcp_xr_header_t) + sizeof(rtcp_xr_voip_metrics_report_block_t);
287 mblk_t *h = allocb(size, 0);
288 h->b_wptr += rtcp_xr_header_init(h->b_wptr, session, size);
289 h->b_wptr += rtcp_xr_voip_metrics_init(h->b_wptr, session);
290 return h;
291 }
292
rtp_session_configure_rtcp_xr(RtpSession * session,const OrtpRtcpXrConfiguration * config)293 void rtp_session_configure_rtcp_xr(RtpSession *session, const OrtpRtcpXrConfiguration *config) {
294 if (config != NULL) {
295 session->rtcp.xr_conf = *config;
296 }
297 }
298
rtp_session_set_rtcp_xr_media_callbacks(RtpSession * session,const OrtpRtcpXrMediaCallbacks * cbs)299 void rtp_session_set_rtcp_xr_media_callbacks(RtpSession *session, const OrtpRtcpXrMediaCallbacks *cbs) {
300 if (cbs != NULL) {
301 memcpy(&session->rtcp.xr_media_callbacks, cbs, sizeof(session->rtcp.xr_media_callbacks));
302 } else {
303 memset(&session->rtcp.xr_media_callbacks, 0, sizeof(session->rtcp.xr_media_callbacks));
304 }
305 }
306