rtcp: Move SR and RR construction to rtcp packets module

This commit is contained in:
Joni Räsänen 2022-07-08 09:53:49 +03:00
parent 473b7abf0b
commit a08d92e848
7 changed files with 84 additions and 62 deletions

View File

@ -122,7 +122,7 @@ void receiver_hook(uvgrtp::frame::rtcp_receiver_report *frame)
std::cout << "last_seq: " << block.last_seq << std::endl;
std::cout << "jitter: " << block.jitter << std::endl;
std::cout << "lsr: " << block.lsr << std::endl;
std::cout << "dlsr (ms): " << uvgrtp::clock::jiffies_to_ms(block.dlsr)
std::cout << "dlsr (jiffies): " << uvgrtp::clock::jiffies_to_ms(block.dlsr)
<< std::endl << std::endl;
}
@ -147,7 +147,7 @@ void sender_hook(uvgrtp::frame::rtcp_sender_report *frame)
std::cout << "last_seq: " << block.last_seq << std::endl;
std::cout << "jitter: " << block.jitter << std::endl;
std::cout << "lsr: " << block.lsr << std::endl;
std::cout << "dlsr (ms): " << uvgrtp::clock::jiffies_to_ms(block.dlsr)
std::cout << "dlsr (jiffies): " << uvgrtp::clock::jiffies_to_ms(block.dlsr)
<< std::endl << std::endl;
}

View File

@ -39,7 +39,7 @@ namespace uvgrtp {
uint32_t received_bytes = 0; /* Number of bytes received excluding RTP Header */
bool received_rtp_packet = false; // since last report
float jitter = 0; /* The estimation of jitter (see RFC 3550 A.8) */
double jitter = 0; /* The estimation of jitter (see RFC 3550 A.8) */
uint32_t transit = 0; /* TODO: */
@ -54,7 +54,7 @@ namespace uvgrtp {
uint16_t max_seq = 0; /* Highest sequence number received */
uint32_t base_seq = 0; /* First sequence number received */
uint32_t bad_seq = 0; /* TODO: */
uint32_t cycles = 0; /* Number of sequence cycles */
uint16_t cycles = 0; /* Number of sequence cycles */
};
struct rtcp_participant {

View File

@ -82,7 +82,7 @@ uint64_t uvgrtp::clock::hrc::diff_now_us(hrc_t& then)
uint64_t uvgrtp::clock::ms_to_jiffies(uint64_t ms)
{
return (uint64_t)(((double)ms / 1000) * 65536);
return (uint64_t)(((double)ms/1000)* 65536);
}
uint64_t uvgrtp::clock::jiffies_to_ms(uint64_t jiffies)

View File

@ -786,7 +786,7 @@ rtp_error_t uvgrtp::rtcp::update_participant_seq(uint32_t ssrc, uint16_t seq)
if (seq < p->stats.max_seq)
{
/* Sequence number wrapped - count another 64K cycle. */
p->stats.cycles += RTP_SEQ_MOD;
p->stats.cycles += 1;
}
p->stats.max_seq = seq;
} else if (udelta <= RTP_SEQ_MOD - MAX_MISORDER) {
@ -1395,23 +1395,21 @@ rtp_error_t uvgrtp::rtcp::generate_report()
memset(frame, 0, rtcp_packet_size);
construct_rtcp_header(frame, ptr, rtcp_packet_size, reports, uvgrtp::frame::RTCP_FT_SR, ssrc_);
// add sender info to packet
/* TODO: The clock would be better to start with first sent RTP packet.
* In reality it should be provided by user which I think is implemented? */
if (clock_start_ == 0)
{
clock_start_ = uvgrtp::clock::ntp::now();
}
/* Sender information */
/* TODO: The RTP timestamp should be from an actual RTP packet and NTP timestamp should be the one
corresponding to it. */
uint64_t ntp_ts = uvgrtp::clock::ntp::now();
uint64_t rtp_ts = rtp_ts_start_ + (uvgrtp::clock::ntp::diff(clock_start_, ntp_ts))
* float(clock_rate_ / 1000);
SET_NEXT_FIELD_32(frame, ptr, htonl(ntp_ts >> 32));
SET_NEXT_FIELD_32(frame, ptr, htonl(ntp_ts & 0xffffffff));
SET_NEXT_FIELD_32(frame, ptr, htonl((u_long)rtp_ts));
SET_NEXT_FIELD_32(frame, ptr, htonl(our_stats.sent_pkts));
SET_NEXT_FIELD_32(frame, ptr, htonl(our_stats.sent_bytes));
construct_sender_info(frame, ptr, ntp_ts, rtp_ts,
our_stats.sent_pkts, our_stats.sent_bytes);
our_stats.sent_rtp_packet = false;
@ -1429,24 +1427,23 @@ rtp_error_t uvgrtp::rtcp::generate_report()
// only add report blocks if we have received data from them
if (p.second->stats.received_rtp_packet)
{
int dropped = p.second->stats.dropped_pkts;
uint32_t dropped_packets = p.second->stats.dropped_pkts;
// TODO: This should be the number of packets lost compared to number of packets expected (see fraction lost in RFC 3550)
// see https://datatracker.ietf.org/doc/html/rfc3550#appendix-A.3
uint8_t frac = dropped ? p.second->stats.received_bytes / dropped : 0;
uint8_t fraction = dropped_packets ? p.second->stats.received_bytes / dropped_packets : 0;
SET_NEXT_FIELD_32(frame, ptr, htonl(p.first)); /* ssrc */
SET_NEXT_FIELD_32(frame, ptr, htonl((frac << 24) | p.second->stats.dropped_pkts));
SET_NEXT_FIELD_32(frame, ptr, htonl(p.second->stats.max_seq));
SET_NEXT_FIELD_32(frame, ptr, htonl(p.second->stats.jitter));
SET_NEXT_FIELD_32(frame, ptr, htonl(p.second->stats.lsr));
uint64_t diff = (u_long)uvgrtp::clock::hrc::diff_now(p.second->stats.sr_ts);
uint32_t dlrs = uvgrtp::clock::ms_to_jiffies(diff);
/* calculate delay of last SR only if SR has been received at least once */
if (p.second->stats.lsr)
if (p.second->stats.lsr == 0)
{
uint64_t diff = (u_long)uvgrtp::clock::hrc::diff_now(p.second->stats.sr_ts);
SET_NEXT_FIELD_32(frame, ptr, (uint32_t)htonl((u_long)uvgrtp::clock::ms_to_jiffies(diff)));
dlrs = 0;
}
ptr += p.second->stats.lsr ? 0 : 4;
construct_report_block(frame, ptr, p.first, fraction, dropped_packets,
p.second->stats.cycles, p.second->stats.max_seq, p.second->stats.jitter,
p.second->stats.lsr, dlrs);
// we only send reports if there is something to report since last report
p.second->stats.received_rtp_packet = false;

View File

@ -5,35 +5,6 @@
#include "uvgrtp/debug.hh"
bool uvgrtp::construct_rtcp_header(uint8_t* frame, int& ptr, size_t packet_size,
uint16_t secondField,
uvgrtp::frame::RTCP_FRAME_TYPE frame_type,
uint32_t ssrc)
{
if (packet_size > UINT16_MAX)
{
LOG_ERROR("RTCP receiver report packet size too large!");
return false;
}
// header |V=2|P| SC | PT | length |
frame[ptr] = (2 << 6) | (0 << 5) | secondField;
frame[ptr + 1] = frame_type;
// The RTCP header length field is measured in 32-bit words - 1
*(uint16_t*)&frame[ptr + 2] = htons((uint16_t)packet_size / sizeof(uint32_t) - 1);
ptr += RTCP_HEADER_SIZE;
if (ssrc)
{
*(uint32_t*)&frame[ptr] = htonl(ssrc);
ptr += SSRC_CSRC_SIZE;
}
return true;
}
size_t uvgrtp::get_sr_packet_size(int flags, uint16_t reports)
{
/* Sender report is otherwise identical with receiver report,
@ -84,6 +55,56 @@ size_t uvgrtp::get_bye_packet_size(const std::vector<uint32_t>& ssrcs)
return RTCP_HEADER_SIZE + ssrcs.size() * SSRC_CSRC_SIZE;
}
bool uvgrtp::construct_rtcp_header(uint8_t* frame, int& ptr, size_t packet_size,
uint16_t secondField,
uvgrtp::frame::RTCP_FRAME_TYPE frame_type,
uint32_t ssrc)
{
if (packet_size > UINT16_MAX)
{
LOG_ERROR("RTCP receiver report packet size too large!");
return false;
}
// header |V=2|P| SC | PT | length |
frame[ptr] = (2 << 6) | (0 << 5) | secondField;
frame[ptr + 1] = frame_type;
// The RTCP header length field is measured in 32-bit words - 1
*(uint16_t*)&frame[ptr + 2] = htons((uint16_t)packet_size / sizeof(uint32_t) - 1);
ptr += RTCP_HEADER_SIZE;
if (ssrc)
{
*(uint32_t*)&frame[ptr] = htonl(ssrc);
ptr += SSRC_CSRC_SIZE;
}
return true;
}
void uvgrtp::construct_sender_info(uint8_t* frame, int& ptr, uint64_t ntp_ts, uint64_t rtp_ts,
uint32_t sent_packets, uint32_t sent_bytes)
{
SET_NEXT_FIELD_32(frame, ptr, htonl(ntp_ts >> 32)); // NTP ts msw
SET_NEXT_FIELD_32(frame, ptr, htonl(ntp_ts & 0xffffffff)); // NTP ts lsw
SET_NEXT_FIELD_32(frame, ptr, htonl((uint32_t)rtp_ts)); // RTP ts
SET_NEXT_FIELD_32(frame, ptr, htonl(sent_packets)); // sender's packet count
SET_NEXT_FIELD_32(frame, ptr, htonl(sent_bytes)); // sender's octet count (not bytes)
}
void uvgrtp::construct_report_block(uint8_t* frame, int& ptr, uint32_t ssrc, uint8_t fraction,
uint32_t dropped_packets, uint16_t seq_cycles, uint16_t max_seq, uint32_t jitter,
uint32_t lsr, uint32_t dlsr)
{
SET_NEXT_FIELD_32(frame, ptr, htonl(ssrc));
SET_NEXT_FIELD_32(frame, ptr, htonl(uint32_t(fraction << 24) | dropped_packets));
SET_NEXT_FIELD_32(frame, ptr, htonl(uint32_t(seq_cycles) << 16 | max_seq));
SET_NEXT_FIELD_32(frame, ptr, htonl(jitter));
SET_NEXT_FIELD_32(frame, ptr, htonl(lsr));
SET_NEXT_FIELD_32(frame, ptr, htonl(dlsr));
}
bool uvgrtp::construct_app_packet(uint8_t* frame, int& ptr,
const char* name, const uint8_t* payload, size_t payload_len)
{

View File

@ -13,16 +13,22 @@ namespace uvgrtp
const uint16_t REPORT_BLOCK_SIZE = 24;
const uint16_t APP_NAME_SIZE = 4;
/* Set the first four or eight bytes of an RTCP packet */
bool construct_rtcp_header(uint8_t* frame, int& ptr, size_t packet_size,
uint16_t secondField, uvgrtp::frame::RTCP_FRAME_TYPE frame_type, uint32_t ssrc);
size_t get_sr_packet_size(int flags, uint16_t reports);
size_t get_rr_packet_size(int flags, uint16_t reports);
size_t get_sdes_packet_size(const std::vector<uvgrtp::frame::rtcp_sdes_item>& items);
size_t get_app_packet_size(size_t payload_len);
size_t get_bye_packet_size(const std::vector<uint32_t>& ssrcs);
/* Set the first four or eight bytes of an RTCP packet */
bool construct_rtcp_header(uint8_t* frame, int& ptr, size_t packet_size,
uint16_t secondField, uvgrtp::frame::RTCP_FRAME_TYPE frame_type, uint32_t ssrc);
void construct_sender_info(uint8_t* frame, int& ptr, uint64_t ntp_ts, uint64_t rtp_ts,
uint32_t sent_packets, uint32_t sent_bytes);
void construct_report_block(uint8_t* frame, int& ptr, uint32_t ssrc, uint8_t fraction,
uint32_t dropped_packets, uint16_t seq_cycles, uint16_t max_seq, uint32_t jitter,
uint32_t lsr, uint32_t dlsr);
bool construct_sdes_packet(uint8_t* frame, int& ptr,
const std::vector<uvgrtp::frame::rtcp_sdes_item>& items);
bool construct_app_packet(uint8_t* frame, int& ptr,

View File

@ -153,8 +153,7 @@ void receiver_hook(uvgrtp::frame::rtcp_receiver_report* frame)
std::cout << "last_seq: " << block.last_seq << std::endl;
std::cout << "jitter: " << block.jitter << std::endl;
std::cout << "lsr: " << block.lsr << std::endl;
std::cout << "dlsr (ms): " << uvgrtp::clock::jiffies_to_ms(block.dlsr)
<< std::endl << std::endl;
std::cout << "dlsr (jiffies): " << block.dlsr << std::endl << std::endl;
}
/* RTCP frames can be deallocated using delete */
@ -178,8 +177,7 @@ void sender_hook(uvgrtp::frame::rtcp_sender_report* frame)
std::cout << "last_seq: " << block.last_seq << std::endl;
std::cout << "jitter: " << block.jitter << std::endl;
std::cout << "lsr: " << block.lsr << std::endl;
std::cout << "dlsr (ms): " << uvgrtp::clock::jiffies_to_ms(block.dlsr)
<< std::endl << std::endl;
std::cout << "dlsr (jiffies): " << block.dlsr << std::endl << std::endl;
}
/* RTCP frames can be deallocated using delete */