re/src/rtp/fb.c
2016-02-15 08:31:47 +00:00

169 lines
3.3 KiB
C

/**
* @file fb.c Real-time Transport Control Protocol (RTCP)-Based Feedback
*
* Copyright (C) 2010 Creytiv.com
*/
#include <string.h>
#include <re_types.h>
#include <re_fmt.h>
#include <re_mem.h>
#include <re_mbuf.h>
#include <re_list.h>
#include <re_sys.h>
#include <re_sa.h>
#include <re_rtp.h>
#include "rtcp.h"
#define DEBUG_MODULE "rtcp_pb"
#define DEBUG_LEVEL 5
#include <re_dbg.h>
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; i<msg->r.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; i<msg->r.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;
}