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