1 /**
2  * @file fb.c Real-time Transport Control Protocol (RTCP)-Based Feedback
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_sys.h>
13 #include <re_sa.h>
14 #include <re_rtp.h>
15 #include "rtcp.h"
16 
17 
18 #define DEBUG_MODULE "rtcp_pb"
19 #define DEBUG_LEVEL 5
20 #include <re_dbg.h>
21 
22 
23 enum {
24 	GNACK_SIZE = 4,
25 	SLI_SIZE   = 4
26 };
27 
28 
29 /* Encode functions */
30 
31 
32 /**
33  * Encode an RTCP Generic NACK (GNACK) message
34  *
35  * @param mb  Buffer to encode into
36  * @param pid Packet ID
37  * @param blp Bitmask of following lost packets (BLP)
38  *
39  * @return 0 for success, otherwise errorcode
40  */
41 int rtcp_rtpfb_gnack_encode(struct mbuf *mb, uint16_t pid, uint16_t blp)
42 {
43 	int err;
44 	err  = mbuf_write_u16(mb, htons(pid));
45 	err |= mbuf_write_u16(mb, htons(blp));
46 	return err;
47 }
48 
49 
50 /**
51  * Encode an RTCP Slice Loss Indication (SLI) message
52  *
53  * @param mb     Buffer to encode into
54  * @param first  Macroblock (MB) address of the first lost macroblock
55  * @param number Number of lost macroblocks
56  * @param picid  Picture ID
57  *
58  * @return 0 for success, otherwise errorcode
59  */
60 int rtcp_psfb_sli_encode(struct mbuf *mb, uint16_t first, uint16_t number,
61 			 uint8_t picid)
62 {
63 	const uint32_t v = first<<19 | number<<6 | picid;
64 	return mbuf_write_u32(mb, htonl(v));
65 }
66 
67 
68 /* Decode functions */
69 
70 
71 /**
72  * Decode an RTCP Transport Layer Feedback Message
73  *
74  * @param mb  Buffer to decode
75  * @param msg RTCP Message to decode into
76  *
77  * @return 0 for success, otherwise errorcode
78  */
79 int rtcp_rtpfb_decode(struct mbuf *mb, struct rtcp_msg *msg)
80 {
81 	size_t i, sz;
82 
83 	if (!msg)
84 		return EINVAL;
85 
86 	switch (msg->hdr.count) {
87 
88 	case RTCP_RTPFB_GNACK:
89 		sz = msg->r.fb.n * sizeof(*msg->r.fb.fci.gnackv);
90 		msg->r.fb.fci.gnackv = mem_alloc(sz, NULL);
91 		if (!msg->r.fb.fci.gnackv)
92 			return ENOMEM;
93 
94 		if (mbuf_get_left(mb) < msg->r.fb.n * GNACK_SIZE)
95 			return EBADMSG;
96 		for (i=0; i<msg->r.fb.n; i++) {
97 			msg->r.fb.fci.gnackv[i].pid = ntohs(mbuf_read_u16(mb));
98 			msg->r.fb.fci.gnackv[i].blp = ntohs(mbuf_read_u16(mb));
99 		}
100 		break;
101 
102 	default:
103 		DEBUG_NOTICE("unknown RTPFB fmt %d\n", msg->hdr.count);
104 		break;
105 	}
106 
107 	return 0;
108 }
109 
110 
111 /**
112  * Decode an RTCP Payload-Specific Feedback Message
113  *
114  * @param mb  Buffer to decode
115  * @param msg RTCP Message to decode into
116  *
117  * @return 0 for success, otherwise errorcode
118  */
119 int rtcp_psfb_decode(struct mbuf *mb, struct rtcp_msg *msg)
120 {
121 	size_t i, sz;
122 
123 	if (!msg)
124 		return EINVAL;
125 
126 	switch (msg->hdr.count) {
127 
128 	case RTCP_PSFB_PLI:
129 		/* no params */
130 		break;
131 
132 	case RTCP_PSFB_SLI:
133 		sz = msg->r.fb.n * sizeof(*msg->r.fb.fci.sliv);
134 		msg->r.fb.fci.sliv = mem_alloc(sz, NULL);
135 		if (!msg->r.fb.fci.sliv)
136 			return ENOMEM;
137 
138 		if (mbuf_get_left(mb) < msg->r.fb.n * SLI_SIZE)
139 			return EBADMSG;
140 		for (i=0; i<msg->r.fb.n; i++) {
141 			const uint32_t v = ntohl(mbuf_read_u32(mb));
142 
143 			msg->r.fb.fci.sliv[i].first  = v>>19 & 0x1fff;
144 			msg->r.fb.fci.sliv[i].number = v>> 6 & 0x1fff;
145 			msg->r.fb.fci.sliv[i].picid  = v>> 0 & 0x003f;
146 		}
147 		break;
148 
149 	case RTCP_PSFB_AFB:
150 		sz = msg->r.fb.n * 4;
151 
152 		if (mbuf_get_left(mb) < sz)
153 			return EBADMSG;
154 
155 		msg->r.fb.fci.afb = mbuf_alloc_ref(mb);
156 		if (!msg->r.fb.fci.afb)
157 			return ENOMEM;
158 
159 		msg->r.fb.fci.afb->end = msg->r.fb.fci.afb->pos + sz;
160 		mbuf_advance(mb, sz);
161 		break;
162 
163 	default:
164 		DEBUG_NOTICE("unknown PSFB fmt %d\n", msg->hdr.count);
165 		break;
166 	}
167 
168 	return 0;
169 }
170