/** * @file fb.c Real-time Transport Control Protocol (RTCP)-Based Feedback * * Copyright (C) 2010 Creytiv.com */ #include #include #include #include #include #include #include #include #include #include "rtcp.h" #define DEBUG_MODULE "rtcp_pb" #define DEBUG_LEVEL 5 #include enum { GNACK_SIZE = 4, SLI_SIZE = 4 }; /* Encode functions */ /** * Encode an RTCP Generic NACK (GNACK) message * * @param mb Buffer to encode into * @param pid Packet ID * @param blp Bitmask of following lost packets (BLP) * * @return 0 for success, otherwise errorcode */ int rtcp_rtpfb_gnack_encode(struct mbuf *mb, uint16_t pid, uint16_t blp) { int err; err = mbuf_write_u16(mb, htons(pid)); err |= mbuf_write_u16(mb, htons(blp)); return err; } /** * Encode an RTCP Slice Loss Indication (SLI) message * * @param mb Buffer to encode into * @param first Macroblock (MB) address of the first lost macroblock * @param number Number of lost macroblocks * @param picid Picture ID * * @return 0 for success, otherwise errorcode */ int rtcp_psfb_sli_encode(struct mbuf *mb, uint16_t first, uint16_t number, uint8_t picid) { const uint32_t v = first<<19 | number<<6 | picid; return mbuf_write_u32(mb, htonl(v)); } /* Decode functions */ /** * Decode an RTCP Transport Layer Feedback Message * * @param mb Buffer to decode * @param msg RTCP Message to decode into * * @return 0 for success, otherwise errorcode */ int rtcp_rtpfb_decode(struct mbuf *mb, struct rtcp_msg *msg) { size_t i, sz; if (!msg) return EINVAL; switch (msg->hdr.count) { case RTCP_RTPFB_GNACK: sz = msg->r.fb.n * sizeof(*msg->r.fb.fci.gnackv); msg->r.fb.fci.gnackv = mem_alloc(sz, NULL); if (!msg->r.fb.fci.gnackv) return ENOMEM; if (mbuf_get_left(mb) < msg->r.fb.n * GNACK_SIZE) return EBADMSG; for (i=0; ir.fb.n; i++) { msg->r.fb.fci.gnackv[i].pid = ntohs(mbuf_read_u16(mb)); msg->r.fb.fci.gnackv[i].blp = ntohs(mbuf_read_u16(mb)); } break; default: DEBUG_NOTICE("unknown RTPFB fmt %d\n", msg->hdr.count); break; } return 0; } /** * Decode an RTCP Payload-Specific Feedback Message * * @param mb Buffer to decode * @param msg RTCP Message to decode into * * @return 0 for success, otherwise errorcode */ int rtcp_psfb_decode(struct mbuf *mb, struct rtcp_msg *msg) { size_t i, sz; if (!msg) return EINVAL; switch (msg->hdr.count) { case RTCP_PSFB_PLI: /* no params */ break; case RTCP_PSFB_SLI: sz = msg->r.fb.n * sizeof(*msg->r.fb.fci.sliv); msg->r.fb.fci.sliv = mem_alloc(sz, NULL); if (!msg->r.fb.fci.sliv) return ENOMEM; if (mbuf_get_left(mb) < msg->r.fb.n * SLI_SIZE) return EBADMSG; for (i=0; ir.fb.n; i++) { const uint32_t v = ntohl(mbuf_read_u32(mb)); msg->r.fb.fci.sliv[i].first = v>>19 & 0x1fff; msg->r.fb.fci.sliv[i].number = v>> 6 & 0x1fff; msg->r.fb.fci.sliv[i].picid = v>> 0 & 0x003f; } break; case RTCP_PSFB_AFB: sz = msg->r.fb.n * 4; if (mbuf_get_left(mb) < sz) return EBADMSG; msg->r.fb.fci.afb = mbuf_alloc_ref(mb); if (!msg->r.fb.fci.afb) return ENOMEM; msg->r.fb.fci.afb->end = msg->r.fb.fci.afb->pos + sz; mbuf_advance(mb, sz); break; default: DEBUG_NOTICE("unknown PSFB fmt %d\n", msg->hdr.count); break; } return 0; }