169 lines
3.3 KiB
C
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;
|
|
}
|