blob: 6e708de29c5fed753e88c42011761a5793b7b21d [file] [log] [blame]
James Kuszmaul82f6c042021-01-17 11:30:16 -08001/**
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
17static 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 */
55int 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 */
71int 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 */
86int 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 */
100int 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
107const 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
127const 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 */
153int 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}