rtcp: Calculate compound packet size correctly for app and bye
This commit is contained in:
parent
202209fe8e
commit
177a0b0d83
|
@ -298,10 +298,18 @@ namespace uvgrtp {
|
|||
// the length field is the rtcp packet size measured in 32-bit words - 1
|
||||
size_t rtcp_length_in_bytes(uint16_t length);
|
||||
|
||||
/// \cond DO_NOT_DOCUMENT
|
||||
void set_mtu_size(size_t mtu_size);
|
||||
|
||||
private:
|
||||
|
||||
rtp_error_t set_sdes_items(const std::vector<uvgrtp::frame::rtcp_sdes_item>& items);
|
||||
|
||||
size_t size_of_ready_app_packets() const;
|
||||
|
||||
size_t size_of_compound_packet(uint16_t reports,
|
||||
bool sr_packet, bool rr_packet, bool sdes_packet, size_t app_size, bool bye_packet) const;
|
||||
|
||||
/* read the header values from rtcp packet */
|
||||
void read_rtcp_header(const uint8_t* buffer, size_t& read_ptr,
|
||||
uvgrtp::frame::rtcp_header& header);
|
||||
|
@ -491,6 +499,8 @@ namespace uvgrtp {
|
|||
|
||||
uvgrtp::frame::rtcp_sdes_item cnameItem_;
|
||||
char cname_[255];
|
||||
|
||||
size_t mtu_size_;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -566,6 +566,7 @@ rtp_error_t uvgrtp::media_stream::configure_ctx(int flag, ssize_t value)
|
|||
}
|
||||
|
||||
rtp_->set_payload_size(value - hdr);
|
||||
rtcp_->set_mtu_size(value - (ETH_HDR_SIZE + IPV4_HDR_SIZE + UDP_HDR_SIZE));
|
||||
|
||||
}
|
||||
break;
|
||||
|
|
179
src/rtcp.cc
179
src/rtcp.cc
|
@ -54,7 +54,8 @@ uvgrtp::rtcp::rtcp(std::shared_ptr<uvgrtp::rtp> rtp, std::string cname, int flag
|
|||
active_(false),
|
||||
interval_ms_(DEFAULT_RTCP_INTERVAL_MS),
|
||||
ourItems_(),
|
||||
bye_ssrcs_(false)
|
||||
bye_ssrcs_(false),
|
||||
mtu_size_(MAX_PAYLOAD)
|
||||
{
|
||||
clock_rate_ = rtp->get_clock_rate();
|
||||
|
||||
|
@ -1471,8 +1472,61 @@ rtp_error_t uvgrtp::rtcp::send_rtcp_packet_to_participants(uint8_t* frame, size_
|
|||
return ret;
|
||||
}
|
||||
|
||||
size_t uvgrtp::rtcp::size_of_ready_app_packets() const
|
||||
{
|
||||
int ready_packets = 0;
|
||||
for (auto& app_name : app_packets_)
|
||||
{
|
||||
// TODO: Should we also send one per subtype?
|
||||
if (!app_name.second.empty())
|
||||
{
|
||||
++ready_packets;
|
||||
}
|
||||
}
|
||||
|
||||
return ready_packets;
|
||||
}
|
||||
|
||||
size_t uvgrtp::rtcp::size_of_compound_packet(uint16_t reports,
|
||||
bool sr_packet, bool rr_packet, bool sdes_packet, size_t app_size, bool bye_packet) const
|
||||
{
|
||||
size_t compound_packet_size = 0;
|
||||
|
||||
if (sr_packet)
|
||||
{
|
||||
compound_packet_size = get_sr_packet_size(flags_, reports);
|
||||
}
|
||||
else if (rr_packet)
|
||||
{
|
||||
compound_packet_size = get_rr_packet_size(flags_, reports);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("RTCP compound packet must start with either SR or RR");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sdes_packet)
|
||||
{
|
||||
compound_packet_size += get_sdes_packet_size(ourItems_);
|
||||
}
|
||||
|
||||
if (app_size != 0)
|
||||
{
|
||||
compound_packet_size += app_size;
|
||||
}
|
||||
|
||||
if (bye_packet)
|
||||
{
|
||||
compound_packet_size += get_bye_packet_size(bye_ssrcs_);
|
||||
}
|
||||
|
||||
return compound_packet_size;
|
||||
}
|
||||
|
||||
rtp_error_t uvgrtp::rtcp::generate_report()
|
||||
{
|
||||
packet_mutex_.lock();
|
||||
rtcp_pkt_sent_count_++;
|
||||
|
||||
uint16_t reports = 0;
|
||||
|
@ -1484,14 +1538,24 @@ rtp_error_t uvgrtp::rtcp::generate_report()
|
|||
}
|
||||
}
|
||||
|
||||
size_t compound_packet_size = get_rr_packet_size(flags_, reports);
|
||||
bool sr_packet = our_role_ == SENDER && our_stats.sent_rtp_packet;
|
||||
bool rr_packet = our_role_ == RECEIVER || our_stats.sent_rtp_packet == 0;
|
||||
bool sdes_packet = true;
|
||||
size_t app_packets_size = size_of_ready_app_packets();
|
||||
bool bye_packet = !bye_ssrcs_.empty();
|
||||
|
||||
if (our_role_ == SENDER && our_stats.sent_rtp_packet)
|
||||
size_t compound_packet_size = size_of_compound_packet(reports, sr_packet, rr_packet, sdes_packet, app_packets_size, bye_packet);
|
||||
|
||||
if (compound_packet_size == 0)
|
||||
{
|
||||
compound_packet_size = get_sr_packet_size(flags_, reports);
|
||||
LOG_WARN("Failed to get compound packet size");
|
||||
return RTP_GENERIC_ERROR;
|
||||
}
|
||||
if (compound_packet_size > mtu_size_)
|
||||
{
|
||||
LOG_WARN("Generate RTCP packet is too large %lli/%lli, reports should be circled, but not implemented!",
|
||||
compound_packet_size, mtu_size_);
|
||||
}
|
||||
|
||||
compound_packet_size += get_sdes_packet_size(ourItems_);
|
||||
|
||||
uint8_t* frame = new uint8_t[compound_packet_size];
|
||||
memset(frame, 0, compound_packet_size);
|
||||
|
@ -1499,7 +1563,7 @@ rtp_error_t uvgrtp::rtcp::generate_report()
|
|||
// see https://datatracker.ietf.org/doc/html/rfc3550#section-6.4.1
|
||||
|
||||
int write_ptr = 0;
|
||||
if (our_role_ == SENDER && our_stats.sent_rtp_packet)
|
||||
if (sr_packet)
|
||||
{
|
||||
// sender reports have sender information in addition compared to receiver reports
|
||||
size_t sender_report_size = get_sr_packet_size(flags_, reports);
|
||||
|
@ -1519,21 +1583,31 @@ rtp_error_t uvgrtp::rtcp::generate_report()
|
|||
uint64_t rtp_ts = rtp_ts_start_ + (uvgrtp::clock::ntp::diff(clock_start_, ntp_ts))
|
||||
* float(clock_rate_ / 1000);
|
||||
|
||||
|
||||
// TODO: Return error if these fail
|
||||
construct_rtcp_header(frame, write_ptr, sender_report_size, reports, uvgrtp::frame::RTCP_FT_SR);
|
||||
construct_ssrc(frame, write_ptr, ssrc_);
|
||||
construct_sender_info(frame, write_ptr, ntp_ts, rtp_ts, our_stats.sent_pkts, our_stats.sent_bytes);
|
||||
if (!construct_rtcp_header(frame, write_ptr, sender_report_size, reports, uvgrtp::frame::RTCP_FT_SR) ||
|
||||
!construct_ssrc(frame, write_ptr, ssrc_) ||
|
||||
!construct_sender_info(frame, write_ptr, ntp_ts, rtp_ts, our_stats.sent_pkts, our_stats.sent_bytes))
|
||||
{
|
||||
LOG_ERROR("Failed to construct SR");
|
||||
return RTP_GENERIC_ERROR;
|
||||
}
|
||||
|
||||
our_stats.sent_rtp_packet = false;
|
||||
|
||||
} else { // RECEIVER
|
||||
} else if (rr_packet) { // RECEIVER
|
||||
size_t receiver_report_size = get_rr_packet_size(flags_, reports);
|
||||
LOG_DEBUG("Generating RTCP Receiver report size: %li", receiver_report_size);
|
||||
|
||||
// TODO: Return error if these fail
|
||||
construct_rtcp_header(frame, write_ptr, receiver_report_size, reports, uvgrtp::frame::RTCP_FT_RR);
|
||||
construct_ssrc(frame, write_ptr, ssrc_);
|
||||
if (!construct_rtcp_header(frame, write_ptr, receiver_report_size, reports, uvgrtp::frame::RTCP_FT_RR) ||
|
||||
!construct_ssrc(frame, write_ptr, ssrc_))
|
||||
{
|
||||
LOG_ERROR("Failed to construct RR");
|
||||
return RTP_GENERIC_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// SR or RR is mandatory at the beginning
|
||||
return RTP_GENERIC_ERROR;
|
||||
}
|
||||
|
||||
// the report blocks for sender or receiver report. Both have same reports.
|
||||
|
@ -1565,48 +1639,49 @@ rtp_error_t uvgrtp::rtcp::generate_report()
|
|||
}
|
||||
}
|
||||
|
||||
packet_mutex_.lock();
|
||||
|
||||
// add the SDES packet after the SR/RR, mandatory, must contain CNAME
|
||||
if (!construct_rtcp_header(frame, write_ptr, get_sdes_packet_size(ourItems_), num_receivers_,
|
||||
uvgrtp::frame::RTCP_FT_SDES) ||
|
||||
!construct_sdes_chunk(frame, write_ptr, { ssrc_, ourItems_ }))
|
||||
if (sdes_packet)
|
||||
{
|
||||
LOG_ERROR("Failed to add SDES packet");
|
||||
delete[] frame;
|
||||
return RTP_GENERIC_ERROR;
|
||||
// add the SDES packet after the SR/RR, mandatory, must contain CNAME
|
||||
if (!construct_rtcp_header(frame, write_ptr, get_sdes_packet_size(ourItems_), num_receivers_,
|
||||
uvgrtp::frame::RTCP_FT_SDES) ||
|
||||
!construct_sdes_chunk(frame, write_ptr, { ssrc_, ourItems_ }))
|
||||
{
|
||||
LOG_ERROR("Failed to add SDES packet");
|
||||
delete[] frame;
|
||||
return RTP_GENERIC_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_DEBUG("Sending RTCP report compound packet, Total size: %lli, SDES packet size: %lli",
|
||||
compound_packet_size, get_sdes_packet_size(ourItems_));
|
||||
|
||||
|
||||
for (auto& app_name : app_packets_)
|
||||
if (app_packets_size != 0)
|
||||
{
|
||||
// we send one packet per APP name
|
||||
|
||||
// TODO: Should we also send one per subtype?
|
||||
if (!app_name.second.empty())
|
||||
for (auto& app_name : app_packets_)
|
||||
{
|
||||
// take the oldest APP packet and send it
|
||||
rtcp_app_packet next_packet = app_name.second.front();
|
||||
app_name.second.pop_front();
|
||||
// we send one packet per APP name
|
||||
|
||||
uint16_t secondField = (next_packet.subtype & 0x1f);
|
||||
|
||||
if (!construct_rtcp_header(frame, write_ptr, get_app_packet_size(next_packet.payload_len), secondField,
|
||||
uvgrtp::frame::RTCP_FT_APP) ||
|
||||
!construct_ssrc(frame, write_ptr, ssrc_) ||
|
||||
!construct_app_packet(frame, write_ptr, next_packet.name, next_packet.payload, next_packet.payload_len))
|
||||
// TODO: Should we also send one per subtype?
|
||||
if (!app_name.second.empty())
|
||||
{
|
||||
delete[] frame;
|
||||
return RTP_GENERIC_ERROR;
|
||||
// take the oldest APP packet and send it
|
||||
rtcp_app_packet next_packet = app_name.second.front();
|
||||
app_name.second.pop_front();
|
||||
|
||||
uint16_t secondField = (next_packet.subtype & 0x1f);
|
||||
|
||||
if (!construct_rtcp_header(frame, write_ptr, get_app_packet_size(next_packet.payload_len), secondField,
|
||||
uvgrtp::frame::RTCP_FT_APP) ||
|
||||
!construct_ssrc(frame, write_ptr, ssrc_) ||
|
||||
!construct_app_packet(frame, write_ptr, next_packet.name, next_packet.payload, next_packet.payload_len))
|
||||
{
|
||||
LOG_ERROR("Failed to construct APP packet");
|
||||
delete[] frame;
|
||||
return RTP_GENERIC_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// BYE is always last
|
||||
if (!bye_ssrcs_.empty())
|
||||
// BYE is last if it is sent
|
||||
if (bye_packet)
|
||||
{
|
||||
// header construction does not add our ssrc for BYE
|
||||
uint16_t secondField = (bye_ssrcs_.size() & 0x1f);
|
||||
|
@ -1615,6 +1690,7 @@ rtp_error_t uvgrtp::rtcp::generate_report()
|
|||
!construct_bye_packet(frame, write_ptr, bye_ssrcs_))
|
||||
{
|
||||
bye_ssrcs_.clear();
|
||||
LOG_ERROR("Failed to construct BYE");
|
||||
delete[] frame;
|
||||
return RTP_GENERIC_ERROR;
|
||||
}
|
||||
|
@ -1623,6 +1699,9 @@ rtp_error_t uvgrtp::rtcp::generate_report()
|
|||
}
|
||||
packet_mutex_.unlock();
|
||||
|
||||
LOG_DEBUG("Sending RTCP report compound packet, Total size: %lli",
|
||||
compound_packet_size);
|
||||
|
||||
return send_rtcp_packet_to_participants(frame, compound_packet_size, true);
|
||||
}
|
||||
|
||||
|
@ -1681,4 +1760,10 @@ void uvgrtp::rtcp::set_session_bandwidth(int kbps)
|
|||
interval_ms_ = DEFAULT_RTCP_INTERVAL_MS;
|
||||
}
|
||||
// TODO: This should follow the algorithm specified in RFC 3550 appendix-A.7
|
||||
}
|
||||
|
||||
|
||||
void uvgrtp::rtcp::set_mtu_size(size_t mtu_size)
|
||||
{
|
||||
mtu_size_ = mtu_size;
|
||||
}
|
|
@ -92,7 +92,7 @@ bool uvgrtp::construct_ssrc(uint8_t* frame, int& ptr, uint32_t ssrc)
|
|||
return true;
|
||||
}
|
||||
|
||||
void uvgrtp::construct_sender_info(uint8_t* frame, int& ptr, uint64_t ntp_ts, uint64_t rtp_ts,
|
||||
bool 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
|
||||
|
@ -100,9 +100,11 @@ void uvgrtp::construct_sender_info(uint8_t* frame, int& ptr, uint64_t ntp_ts, ui
|
|||
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)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void uvgrtp::construct_report_block(uint8_t* frame, int& ptr, uint32_t ssrc, uint8_t fraction,
|
||||
bool 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)
|
||||
{
|
||||
|
@ -112,6 +114,8 @@ void uvgrtp::construct_report_block(uint8_t* frame, int& ptr, uint32_t ssrc, uin
|
|||
SET_NEXT_FIELD_32(frame, ptr, htonl(jitter));
|
||||
SET_NEXT_FIELD_32(frame, ptr, htonl(lsr));
|
||||
SET_NEXT_FIELD_32(frame, ptr, htonl(dlsr));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool uvgrtp::construct_app_packet(uint8_t* frame, int& ptr,
|
||||
|
|
|
@ -27,11 +27,11 @@ namespace uvgrtp
|
|||
bool construct_ssrc(uint8_t* frame, int& ptr, uint32_t ssrc);
|
||||
|
||||
// Add sender info for sender report
|
||||
void construct_sender_info(uint8_t* frame, int& ptr,
|
||||
bool construct_sender_info(uint8_t* frame, int& ptr,
|
||||
uint64_t ntp_ts, uint64_t rtp_ts, uint32_t sent_packets, uint32_t sent_bytes);
|
||||
|
||||
// Add one report block for sender or receiver report
|
||||
void construct_report_block(uint8_t* frame, int& ptr, uint32_t ssrc, uint8_t fraction,
|
||||
bool 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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue