Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
203 changes: 203 additions & 0 deletions source/rtcp_fb.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
#include "rtcp_fb.h"

#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "util.h"

rtcp_fb* rtcp_fb_create()
{
rtcp_fb *packet=(rtcp_fb*)malloc(sizeof(rtcp_fb));
if (packet) {
memset(packet, 0, sizeof(rtcp_fb));
}
return packet;
}

void rtcp_fb_init(rtcp_fb* packet, uint16_t pt, uint8_t fmt)
{
assert(packet != NULL);
memset(packet, 0, sizeof(rtcp_fb));
packet->header.app.version = 2;
packet->header.app.pt = pt;
packet->header.app.subtype = fmt;
packet->header.app.length = 2;
}

void rtcp_fb_free(rtcp_fb* packet)
{
assert(packet != NULL);
if (packet->fci) {
free(packet->fci);
}
free(packet);
}

size_t rtcp_fb_size(const rtcp_fb* packet)
{
assert(packet != NULL);
return 12 + packet->fci_size;
}

int rtcp_fb_set_fci(rtcp_fb* packet, const uint8_t* fci, uint16_t fci_size)
{
assert(packet != NULL);
if (packet->fci) {
return -1;
}

packet->fci = malloc(fci_size);
if (!packet->fci) {
return -1;
}
memcpy(packet->fci, fci, fci_size);
packet->fci_size = fci_size;
packet->header.app.length = (uint16_t)((rtcp_fb_size(packet) / 4) - 1);
return 0;
}

void rtcp_fb_free_fci(rtcp_fb* packet)
{
assert(packet != NULL);
if (packet->fci) {
free(packet->fci);
}
packet->fci = NULL;
packet->fci_size = 0;
packet->header.app.length = 2;
packet->header.app.p = 0;
}

int rtcp_fb_serialize(const rtcp_fb* packet, uint8_t* buffer, size_t size)
{
assert(packet);
const size_t packet_size = rtcp_fb_size(packet);
if (size < packet_size) {
return -1;
}

int r=rtcp_header_serialize(&packet->header, buffer, size);
if (r < 0) {
return r;
}

write_u32(buffer+4,packet->ssrc);
write_u32(buffer+8,packet->dst_src);


if (packet->fci_size > 0 && packet->fci) {
memcpy(buffer + 12, packet->fci, packet->fci_size);
}
return packet_size;
}

int rtcp_fb_parse(rtcp_fb* packet, const uint8_t* buffer, size_t size)
{
assert(packet != NULL);
assert(buffer != NULL);

uint16_t pt = rtcp_header_parse(&packet->header, buffer, size);
if (pt != RTCP_RTPFB && pt != RTCP_PSFB) {
return -1;
}

packet->ssrc = read_u32(buffer + 4);
packet->dst_src = read_u32(buffer + 8);

uint16_t fci_size = (packet->header.app.length - 2) * 4;
uint16_t packet_size = 12 + fci_size;
if (size < packet_size) {
return -1;
}

int r = rtcp_fb_set_fci(packet, buffer + 12, fci_size);
if (r < 0) {
return r;
}

return packet_size;
}


int rtcp_rtpfb_nack_set(rtcp_fb* packet,uint16_t fst_pid, uint16_t nxt16_pid)
{
assert(packet != NULL);
uint8_t buffer[4];
write_u16(buffer, fst_pid);
write_u16(buffer + 2, nxt16_pid);
return rtcp_fb_set_fci(packet, buffer, 4);
}

int rtcp_rtpfb_nack_get(const rtcp_fb* packet, uint16_t* fst_pid, uint16_t* nxt16_pid)
{
assert(packet != NULL);
assert(fst_pid != NULL);
assert(nxt16_pid != NULL);
if (packet->fci_size < 4) {
return -1;
}
*fst_pid = read_u16(packet->fci);
*nxt16_pid = read_u16(packet->fci + 2);
return 0;
}


int rtcp_psfb_fir_set_items(rtcp_fb* packet, const rtcp_psfb_fir_item* items,size_t count)
{
assert(packet != NULL);
size_t size = count * sizeof(rtcp_psfb_fir_item);
uint8_t* buffer=(uint8_t*)malloc(size);
if (!buffer) {
return -1;
}
for (size_t i = 0; i < count; ++i) {
int pos = i * sizeof(rtcp_psfb_fir_item);
write_u32(buffer+ pos, items[i].ssrc);
buffer[pos + 4] = items[i].seq_nr;
write_u24(buffer + pos +5, items[i].reserved);
}
rtcp_fb_set_fci(packet, buffer, size);
free(buffer);
return 0;
}

int rtcp_psfb_fir_find_item(const rtcp_fb* packet, uint32_t src, rtcp_psfb_fir_item* item)
{
assert(packet != NULL);
int count = rtcp_psfb_fir_item_count(packet);

for (int i = 0; i < count; i++)
{
int pos = i * sizeof(rtcp_psfb_fir_item);
uint32_t ssrc= read_u32(packet->fci + pos);
if (ssrc == src)
{
item->ssrc = ssrc;
item->seq_nr = packet->fci[pos + 4];
item->reserved = read_u24(packet->fci + pos + 5);
return i;
}
}

return -1;
}

int rtcp_psfb_fir_get_item(const rtcp_fb* packet, int idx, rtcp_psfb_fir_item* item)
{
assert(packet != NULL);
int count = rtcp_psfb_fir_item_count(packet);
if (idx >= count || idx < 0) {
return -1;
}

int pos = idx * sizeof(rtcp_psfb_fir_item);
item->ssrc = read_u32(packet->fci + pos);
item->seq_nr = packet->fci[pos + 4];
item->reserved = read_u24(packet->fci + pos + 5);
return 0;
}
int rtcp_psfb_fir_item_count(const rtcp_fb* packet)
{
assert(packet);
return (packet->header.app.length - 2) / 2;
}
176 changes: 176 additions & 0 deletions source/rtcp_fb.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/**
* @file rtcp_fb.h
* @brief RTCP feedback packet.
* @author Shijie Zhou
* @copyright 2022 Daxbot
* @ingroup fb
*/

/**
* @defgroup feedback Feedback packet
* @brief RTCP Feedback packet description.
* @ingroup rtcp
*
*
* @verbatim
* 0 1 2 3
* 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |V=2|P| fmt | PT=205|206 | length |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | SSRC |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | SSRC of media source |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | FCI ...
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* @endverbatim
*/

#ifndef LIBRTP_RTCP_FB_H_
#define LIBRTP_RTCP_FB_H_



#include "rtcp_header.h"

#if defined(__cplusplus)
extern "C" {
#endif // __cplusplus



typedef enum rtcp_rtpfb_fmt
{
RTCP_RTPFB_FMT_NACK=1,
}rtcp_rtpfb_fmt;

typedef enum rtcp_psfb_fmt
{
RTCP_PSFB_FMT_PLI = 1,
RTCP_PSFB_FMT_FIR = 4,
}rtcp_psfb_fmt;


typedef struct rtcp_fb
{
rtcp_header header; /**< RTCP header. */
uint32_t ssrc; /**< Source identifier. */
uint32_t dst_src; /**< Dst source identifier. */
uint8_t* fci; /**< Feedback Control Information */
uint16_t fci_size; /**< FCI data size */
}rtcp_fb;


typedef struct rtcp_psfb_fir_item
{
uint32_t ssrc;
uint32_t seq_nr : 8;
uint32_t reserved : 24;
}rtcp_psfb_fir_item;

/**
* @brief Allocate a new Feedback packet.
*
* @return rtcp_fb_packet*
*/
rtcp_fb* rtcp_fb_create();

/**
* @brief Initialize an Feedback packet with default values.
*
* @param [out] packet - packet to initialize.
* @param [in] pt - packet payload type.
* @param [in] fmt - packet fmt.
*/
void rtcp_fb_init(rtcp_fb* packet,uint16_t pt,uint8_t fmt);

/**
* @brief Free a Feedback packet.
*
* @param [out] packet - packet to free.
*/
void rtcp_fb_free(rtcp_fb* packet);

/**
* @brief Returns the Feedback packet size.
*
* @param [in] packet - packet to check.
* @return packet size in bytes.
*/
size_t rtcp_fb_size(const rtcp_fb* packet);

/**
* @brief Set the Feedback packet FCI data.
*
* Allocates a new buffer and initializes it with the passed in data. If a
* payload buffer already exists then this method will free it and realloc.
*
* @param [out] packet - packet to set on.
* @param [in] fci - fci data.
* @param [in] fci_size - fci data size.
* @return 0 on success.
*/
int rtcp_fb_set_fci(rtcp_fb* packet, const uint8_t* fci, uint16_t fci_size);

/**
* @brief Clear the FCI data.
*
* @param [out] packet - packet to clear on.
*/
void rtcp_fb_free_fci(rtcp_fb* packet);

/**
* @brief Write an Feedback packet to a buffer.
*
* @param [in] packet - packet to serialize.
* @param [out] buffer - buffer to write to.
* @param [in] size - buffer size.
* @return number of bytes written or -1 on failure.
*/
int rtcp_fb_serialize(const rtcp_fb* packet, uint8_t* buffer, size_t size);

/**
* @brief Parse an Feedback packet from a buffer.
*
* @param [out] packet - empty packet to fill.
* @param [in] buffer - buffer to parse.
* @param [in] size - buffer size.
* @return 0 on success.
*/
int rtcp_fb_parse(rtcp_fb* packet, const uint8_t* buffer, size_t size);



/**
* @brief Set the nack parameters in an Feedback packet.
*
* @param [out] packet - packet to set.
* @param [in] fst_pid - the first lost packet id.
* @param [in] nxt16_pid - bit for the next 16 lost packets.
* @return 0 on success.
*/
int rtcp_rtpfb_nack_set(rtcp_fb* packet,uint16_t fst_pid, uint16_t nxt16_pid);

/**
* @brief Get the nack parameters in an Feedback packet.
*
* @param [in] packet - packet to set.
* @param [out] fst_pid - the first lost packet id.
* @param [out] nxt16_pid - bit for the next 16 lost packets.
* @return 0 on success.
*/
int rtcp_rtpfb_nack_get(const rtcp_fb* packet, uint16_t* fst_pid, uint16_t* nxt16_pid);


int rtcp_psfb_fir_find_item(const rtcp_fb* packet, uint32_t src, rtcp_psfb_fir_item* item);
int rtcp_psfb_fir_set_items(rtcp_fb* packet, const rtcp_psfb_fir_item* items, size_t count);
int rtcp_psfb_fir_get_item(const rtcp_fb* packet, int idx, rtcp_psfb_fir_item* item);
int rtcp_psfb_fir_item_count(const rtcp_fb* packet);


#if defined(__cplusplus)
}
#endif // __cplusplus

#endif // LIBRTP_RTCP_FB_H_