1 /**
2  * @file rtcp.c  Real-time Transport Control Protocol
3  *
4  * Copyright (C) 2010 Creytiv.com
5  */
6 #include <string.h>
7 #include <re_types.h>
8 #include <re_fmt.h>
9 #include <re_mem.h>
10 #include <re_mbuf.h>
11 #include <re_list.h>
12 #include <re_sa.h>
13 #include <re_rtp.h>
14 #include "rtcp.h"
15 
16 
rtcp_quick_send(struct rtp_sock * rs,enum rtcp_type type,uint32_t count,...)17 static int rtcp_quick_send(struct rtp_sock *rs, enum rtcp_type type,
18 			   uint32_t count, ...)
19 {
20 	struct mbuf *mb;
21 	va_list ap;
22 	int err;
23 
24 	mb = mbuf_alloc(32);
25 	if (!mb)
26 		return ENOMEM;
27 
28 	mb->pos = RTCP_HEADROOM;
29 
30 	va_start(ap, count);
31 	err = rtcp_vencode(mb, type, count, ap);
32 	va_end(ap);
33 
34 	mb->pos = RTCP_HEADROOM;
35 
36 	if (!err)
37 		err = rtcp_send(rs, mb);
38 
39 	mem_deref(mb);
40 
41 	return err;
42 }
43 
44 
45 /**
46  * Send an RTCP Application-Defined (APP) packet
47  *
48  * @param rs   RTP Socket
49  * @param name Ascii name (4 octets)
50  * @param data Application-dependent data
51  * @param len  Number of bytes of data
52  *
53  * @return 0 for success, otherwise errorcode
54  */
rtcp_send_app(struct rtp_sock * rs,const char name[4],const uint8_t * data,size_t len)55 int rtcp_send_app(struct rtp_sock *rs, const char name[4],
56 		  const uint8_t *data, size_t len)
57 {
58 	return rtcp_quick_send(rs, RTCP_APP, 0, rtp_sess_ssrc(rs),
59 			       name, data, len);
60 }
61 
62 
63 /**
64  * Send a Full INTRA-frame Request (FIR) packet
65  *
66  * @param rs   RTP Socket
67  * @param ssrc Synchronization source identifier for the sender of this packet
68  *
69  * @return 0 for success, otherwise errorcode
70  */
rtcp_send_fir(struct rtp_sock * rs,uint32_t ssrc)71 int rtcp_send_fir(struct rtp_sock *rs, uint32_t ssrc)
72 {
73 	return rtcp_quick_send(rs, RTCP_FIR, 0, ssrc);
74 }
75 
76 
77 /**
78  * Send an RTCP NACK packet
79  *
80  * @param rs   RTP Socket
81  * @param fsn  First Sequence Number lost
82  * @param blp  Bitmask of lost packets
83  *
84  * @return 0 for success, otherwise errorcode
85  */
rtcp_send_nack(struct rtp_sock * rs,uint16_t fsn,uint16_t blp)86 int rtcp_send_nack(struct rtp_sock *rs, uint16_t fsn, uint16_t blp)
87 {
88 	return rtcp_quick_send(rs, RTCP_NACK, 0, rtp_sess_ssrc(rs), fsn, blp);
89 }
90 
91 
92 /**
93  * Send an RTCP Picture Loss Indication (PLI) packet
94  *
95  * @param rs      RTP Socket
96  * @param fb_ssrc Feedback SSRC
97  *
98  * @return 0 for success, otherwise errorcode
99  */
rtcp_send_pli(struct rtp_sock * rs,uint32_t fb_ssrc)100 int rtcp_send_pli(struct rtp_sock *rs, uint32_t fb_ssrc)
101 {
102 	return rtcp_quick_send(rs, RTCP_PSFB, RTCP_PSFB_PLI,
103 			       rtp_sess_ssrc(rs), fb_ssrc, NULL, NULL);
104 }
105 
106 
rtcp_type_name(enum rtcp_type type)107 const char *rtcp_type_name(enum rtcp_type type)
108 {
109 	switch (type) {
110 
111 	case RTCP_FIR:   return "FIR";
112 	case RTCP_NACK:  return "NACK";
113 	case RTCP_SR:    return "SR";
114 	case RTCP_RR:    return "RR";
115 	case RTCP_SDES:  return "SDES";
116 	case RTCP_BYE:   return "BYE";
117 	case RTCP_APP:   return "APP";
118 	case RTCP_RTPFB: return "RTPFB";
119 	case RTCP_PSFB:  return "PSFB";
120 	case RTCP_XR:    return "XR";
121 	case RTCP_AVB:   return "AVB";
122 	default:         return "?";
123 	}
124 }
125 
126 
rtcp_sdes_name(enum rtcp_sdes_type sdes)127 const char *rtcp_sdes_name(enum rtcp_sdes_type sdes)
128 {
129 	switch (sdes) {
130 
131 	case RTCP_SDES_END:    return "END";
132 	case RTCP_SDES_CNAME:  return "CNAME";
133 	case RTCP_SDES_NAME:   return "NAME";
134 	case RTCP_SDES_EMAIL:  return "EMAIL";
135 	case RTCP_SDES_PHONE:  return "PHONE";
136 	case RTCP_SDES_LOC:    return "LOC";
137 	case RTCP_SDES_TOOL:   return "TOOL";
138 	case RTCP_SDES_NOTE:   return "NOTE";
139 	case RTCP_SDES_PRIV:   return "PRIV";
140 	default:               return "?";
141 	}
142 }
143 
144 
145 /**
146  * Print an RTCP Message
147  *
148  * @param pf  Print handler for debug output
149  * @param msg RTCP Message
150  *
151  * @return 0 if success, otherwise errorcode
152  */
rtcp_msg_print(struct re_printf * pf,const struct rtcp_msg * msg)153 int rtcp_msg_print(struct re_printf *pf, const struct rtcp_msg *msg)
154 {
155 	size_t i, j;
156 	int err;
157 
158 	if (!msg)
159 		return 0;
160 
161 	err = re_hprintf(pf, "%8s pad=%d count=%-2d pt=%-3d len=%u ",
162 			 rtcp_type_name((enum rtcp_type)msg->hdr.pt),
163 			 msg->hdr.p,
164 			 msg->hdr.count, msg->hdr.pt, msg->hdr.length);
165 	if (err)
166 		return err;
167 
168 	switch (msg->hdr.pt) {
169 
170 	case RTCP_SR:
171 		err = re_hprintf(pf, "%08x %u %u %u %u %u",
172 				 msg->r.sr.ssrc,
173 				 msg->r.sr.ntp_sec,
174 				 msg->r.sr.ntp_frac,
175 				 msg->r.sr.rtp_ts,
176 				 msg->r.sr.psent,
177 				 msg->r.sr.osent);
178 		for (i=0; i<msg->hdr.count && !err; i++) {
179 			const struct rtcp_rr *rr = &msg->r.sr.rrv[i];
180 			err = re_hprintf(pf, " {%08x %u %d %u %u %u %u}",
181 					 rr->ssrc, rr->fraction, rr->lost,
182 					 rr->last_seq, rr->jitter,
183 					 rr->lsr, rr->dlsr);
184 		}
185 		break;
186 
187 	case RTCP_RR:
188 		err = re_hprintf(pf, "%08x", msg->r.rr.ssrc);
189 		for (i=0; i<msg->hdr.count && !err; i++) {
190 			const struct rtcp_rr *rr = &msg->r.rr.rrv[i];
191 			err = re_hprintf(pf, " {0x%08x %u %d %u %u %u %u}",
192 					 rr->ssrc, rr->fraction, rr->lost,
193 					 rr->last_seq, rr->jitter,
194 					 rr->lsr, rr->dlsr);
195 		}
196 		break;
197 
198 	case RTCP_SDES:
199 		for (i=0; i<msg->hdr.count; i++) {
200 			const struct rtcp_sdes *sdes = &msg->r.sdesv[i];
201 
202 			err = re_hprintf(pf, " {0x%08x n=%u",
203 					 sdes->src, sdes->n);
204 			for (j=0; j<sdes->n && !err; j++) {
205 				const struct rtcp_sdes_item *item;
206 				item = &sdes->itemv[j];
207 				err = re_hprintf(pf, " <%s:%b>",
208 						 rtcp_sdes_name(item->type),
209 						 item->data,
210 						 (size_t)item->length);
211 			}
212 			err |= re_hprintf(pf, "}");
213 		}
214 		break;
215 
216 	case RTCP_BYE:
217 		err = re_hprintf(pf, "%u srcs:", msg->hdr.count);
218 		for (i=0; i<msg->hdr.count && !err; i++) {
219 			err = re_hprintf(pf, " %08x",
220 					 msg->r.bye.srcv[i]);
221 		}
222 		err |= re_hprintf(pf, " '%s'", msg->r.bye.reason);
223 		break;
224 
225 	case RTCP_APP:
226 		err = re_hprintf(pf, "src=%08x '%b' data=%zu",
227 				 msg->r.app.src,
228 				 msg->r.app.name, sizeof(msg->r.app.name),
229 				 msg->r.app.data_len);
230 		break;
231 
232 	case RTCP_FIR:
233 		err = re_hprintf(pf, "ssrc=%08x", msg->r.fir.ssrc);
234 		break;
235 
236 	case RTCP_NACK:
237 		err = re_hprintf(pf, "ssrc=%08x fsn=%04x blp=%04x",
238 				 msg->r.nack.ssrc, msg->r.nack.fsn,
239 				 msg->r.nack.blp);
240 		break;
241 
242 	case RTCP_RTPFB:
243 		err = re_hprintf(pf, "pkt=%08x med=%08x n=%u",
244 				 msg->r.fb.ssrc_packet,
245 				 msg->r.fb.ssrc_media,
246 				 msg->r.fb.n);
247 		if (msg->hdr.count == RTCP_RTPFB_GNACK) {
248 			err |= re_hprintf(pf, " GNACK");
249 			for (i=0; i<msg->r.fb.n; i++) {
250 				err |= re_hprintf(pf, " {%04x %04x}",
251 						  msg->r.fb.fci.gnackv[i].pid,
252 						  msg->r.fb.fci.gnackv[i].blp);
253 			}
254 		}
255 		break;
256 
257 	case RTCP_PSFB:
258 		err = re_hprintf(pf, "pkt=%08x med=%08x n=%u",
259 				 msg->r.fb.ssrc_packet,
260 				 msg->r.fb.ssrc_media,
261 				 msg->r.fb.n);
262 		if (msg->hdr.count == RTCP_PSFB_SLI) {
263 			err |= re_hprintf(pf, " SLI");
264 			for (i=0; i<msg->r.fb.n; i++) {
265 				err |= re_hprintf(pf, " {%04x %04x %02x}",
266 						  msg->r.fb.fci.sliv[i].first,
267 						  msg->r.fb.fci.sliv[i].number,
268 						  msg->r.fb.fci.sliv[i].picid);
269 			}
270 		}
271 		else if (msg->hdr.count == RTCP_PSFB_AFB) {
272 			err |= re_hprintf(pf, " AFB %u bytes",
273 					  msg->r.fb.n * 4);
274 		}
275 		break;
276 
277 	default:
278 		err = re_hprintf(pf, "<len=%u>", msg->hdr.length);
279 		break;
280 	}
281 
282 	err |= re_hprintf(pf, "\n");
283 
284 	return err;
285 }
286