rtcp: Combine generation of sender and receiver reports

This reduces the amount of duplicate code in rtcp.
This commit is contained in:
Joni Räsänen 2021-06-14 14:43:43 +03:00
parent 4abd24bd02
commit 55dad012a1
2 changed files with 69 additions and 121 deletions

View File

@ -341,13 +341,6 @@ namespace uvgrtp {
* should be increased before calculating the new average */
void update_rtcp_bandwidth(size_t pkt_size);
/* Functions for generating different kinds of reports.
* These functions will both generate the report and send it
*
* Return RTP_OK on success and RTP_ERROR on error */
rtp_error_t generate_sender_report();
rtp_error_t generate_receiver_report();
/* Because struct statistics contains uvgRTP clock object we cannot
* zero it out without compiler complaining about it so all the fields
* must be set to zero manually */

View File

@ -523,8 +523,6 @@ void uvgrtp::rtcp::update_session_statistics(uvgrtp::frame::rtp_frame *frame)
int dropped = expected - p->stats.received_pkts;
p->stats.dropped_pkts = dropped >= 0 ? dropped : 0;
uint64_t arrival =
p->stats.initial_rtp +
+ uvgrtp::clock::ntp::diff_now(p->stats.initial_ntp)
@ -653,7 +651,6 @@ rtp_error_t uvgrtp::rtcp::handle_incoming_packet(uint8_t *buffer, size_t size)
return ret;
}
rtp_error_t uvgrtp::rtcp::handle_sdes_packet(uint8_t* packet, size_t size)
{
if (!packet || !size)
@ -919,9 +916,75 @@ rtp_error_t uvgrtp::rtcp::generate_report()
{
rtcp_pkt_sent_count_++;
if (our_role_ == RECEIVER)
return generate_receiver_report();
return generate_sender_report();
LOG_DEBUG("Generating RTCP Sender Report");
if (!senders_) {
LOG_DEBUG("Session does not have any RTP senders!");
return RTP_NOT_READY;
}
rtp_error_t ret = RTP_OK;
uint8_t* frame = nullptr;
int ptr = RTCP_HEADER_SIZE + SSRC_CSRC_SIZE;
size_t frame_size = RTCP_HEADER_SIZE + SSRC_CSRC_SIZE + (size_t)num_receivers_ * REPORT_BLOCK_SIZE;
if (flags_ & RCE_SRTP)
frame_size += UVG_SRTCP_INDEX_LENGTH + UVG_AUTH_TAG_LENGTH;
if (our_role_ == SENDER)
{
// sender reports have sender information in addition compared to receiver reports
frame_size += SENDER_INFO_SIZE;
construct_rtcp_header(frame_size, frame, num_receivers_, uvgrtp::frame::RTCP_FT_SR, true);
}
else // RECEIVER
{
construct_rtcp_header(frame_size, frame, num_receivers_, uvgrtp::frame::RTCP_FT_RR, true);
}
if (our_role_ == SENDER)
{
/* Sender infoormation */
uint64_t ntp_ts = uvgrtp::clock::ntp::now();
uint64_t rtp_ts = rtp_ts_start_ + (uvgrtp::clock::ntp::diff(ntp_ts, clock_start_)) * 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));
}
// the report blocks for sender or receiver report. Both have same reports.
LOG_DEBUG("Report from 0x%x has %zu blocks", ssrc_, num_receivers_);
for (auto& p : participants_) {
int dropped = p.second->stats.dropped_pkts;
uint8_t frac = dropped ? p.second->stats.received_bytes / dropped : 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));
/* calculate delay of last SR only if SR has been received at least once */
if (p.second->stats.lsr) {
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)));
}
ptr += p.second->stats.lsr ? 0 : 4;
}
if (srtcp_ && (ret = srtcp_->handle_rtcp_encryption(flags_, rtcp_pkt_sent_count_, ssrc_, frame, frame_size)) != RTP_OK)
{
delete[] frame;
return ret;
}
return send_rtcp_packet_to_participants(frame, frame_size);
}
rtp_error_t uvgrtp::rtcp::send_sdes_packet(std::vector<uvgrtp::frame::rtcp_sdes_item>& items)
@ -1008,111 +1071,3 @@ rtp_error_t uvgrtp::rtcp::send_app_packet(char* name, uint8_t subtype,
return send_rtcp_packet_to_participants(frame, frame_size);
}
rtp_error_t uvgrtp::rtcp::generate_receiver_report()
{
if (!senders_) {
LOG_WARN("Session doesn't have any participants!");
return RTP_NOT_READY;
}
rtp_error_t ret = RTP_OK;
uint8_t* frame = nullptr;
size_t frame_size = RTCP_HEADER_SIZE + SSRC_CSRC_SIZE + (size_t)num_receivers_ * REPORT_BLOCK_SIZE;
int report_ptr = RTCP_HEADER_SIZE + SSRC_CSRC_SIZE;
if (flags_ & RCE_SRTP)
frame_size += UVG_SRTCP_INDEX_LENGTH + UVG_AUTH_TAG_LENGTH;
construct_rtcp_header(frame_size, frame, num_receivers_, uvgrtp::frame::RTCP_FT_RR, true);
LOG_DEBUG("Receiver Report from 0x%x has %zu blocks", ssrc_, num_receivers_);
for (auto& p : participants_) {
int dropped = p.second->stats.dropped_pkts;
// TODO: Shouldn't this be number of packets received no bytes?
uint8_t frac = dropped ? p.second->stats.received_bytes / dropped : 0;
SET_NEXT_FIELD_32(frame, report_ptr, htonl(p.first)); /* ssrc */
SET_NEXT_FIELD_32(frame, report_ptr, htonl((frac << 24) | p.second->stats.dropped_pkts));
SET_NEXT_FIELD_32(frame, report_ptr, htonl(p.second->stats.max_seq));
SET_NEXT_FIELD_32(frame, report_ptr, htonl(p.second->stats.jitter));
SET_NEXT_FIELD_32(frame, report_ptr, htonl(p.second->stats.lsr));
/* calculate delay of last SR only if SR has been received at least once */
if (p.second->stats.lsr) {
uint64_t diff = uvgrtp::clock::hrc::diff_now(p.second->stats.sr_ts);
SET_NEXT_FIELD_32(frame, report_ptr, (uint32_t)htonl((u_long)uvgrtp::clock::ms_to_jiffies(diff)));
}
report_ptr += p.second->stats.lsr ? 0 : 4;
}
if (srtcp_ && (ret = srtcp_->handle_rtcp_encryption(flags_, rtcp_pkt_sent_count_, ssrc_, frame, frame_size)) != RTP_OK)
{
delete[] frame;
return ret;
}
return send_rtcp_packet_to_participants(frame, frame_size);
}
rtp_error_t uvgrtp::rtcp::generate_sender_report()
{
LOG_DEBUG("Generating RTCP Sender Report");
if (!senders_) {
LOG_DEBUG("Session does not have any RTP senders!");
return RTP_NOT_READY;
}
rtp_error_t ret = RTP_OK;
uint8_t* frame = nullptr;
int ptr = RTCP_HEADER_SIZE + SSRC_CSRC_SIZE;
size_t frame_size = RTCP_HEADER_SIZE + SSRC_CSRC_SIZE + SENDER_INFO_SIZE;
frame_size += num_receivers_ * REPORT_BLOCK_SIZE; /* report blocks */
if (flags_ & RCE_SRTP)
frame_size += UVG_SRTCP_INDEX_LENGTH + UVG_AUTH_TAG_LENGTH;
construct_rtcp_header(frame_size, frame, num_receivers_, uvgrtp::frame::RTCP_FT_SR, true);
/* Sender information */
uint64_t ntp_ts = uvgrtp::clock::ntp::now();
uint64_t rtp_ts = rtp_ts_start_ + (uvgrtp::clock::ntp::diff(ntp_ts, clock_start_)) * 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));
LOG_DEBUG("Sender Report from 0x%x has %zu blocks", ssrc_, num_receivers_);
for (auto& p : participants_) {
int dropped = p.second->stats.dropped_pkts;
uint8_t frac = dropped ? p.second->stats.received_bytes / dropped : 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));
/* calculate delay of last SR only if SR has been received at least once */
if (p.second->stats.lsr) {
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)));
}
ptr += p.second->stats.lsr ? 0 : 4;
}
if (srtcp_ && (ret = srtcp_->handle_rtcp_encryption(flags_, rtcp_pkt_sent_count_, ssrc_, frame, frame_size)) != RTP_OK)
{
delete[] frame;
return ret;
}
return send_rtcp_packet_to_participants(frame, frame_size);
}