Split RTCP code into different files
Having a 1100 lines long file is not manageable so split RTCP code into different files by packet type and leave all the session-related code to src/rtcp.cc
This commit is contained in:
parent
39e9b07726
commit
6067a2ed18
|
@ -1,6 +1,7 @@
|
|||
src/*.o
|
||||
src/formats/*.o
|
||||
src/mzrtp/*.o
|
||||
src/rtcp/*.o
|
||||
src/crypto/*.o
|
||||
libkvzrtp.a
|
||||
*.a
|
||||
|
|
2
Makefile
2
Makefile
|
@ -3,7 +3,7 @@
|
|||
CXX = g++
|
||||
CXXFLAGS = -g -Wno-unused-function -Wall -Wextra -Wuninitialized -O2 -std=c++11 -Iinclude -fPIC -DNDEBUG
|
||||
SOURCES = $(wildcard src/*.cc)
|
||||
MODULES := src/formats src/mzrtp
|
||||
MODULES := src/formats src/mzrtp src/rtcp
|
||||
-include $(patsubst %, %/module.mk, $(MODULES))
|
||||
OBJECTS := $(patsubst %.cc, %.o, $(filter %.cc, $(SOURCES)))
|
||||
|
||||
|
|
|
@ -38,15 +38,15 @@ namespace uvg_rtp {
|
|||
* return RTP_OK on success */
|
||||
rtp_error_t stop();
|
||||
|
||||
/* return true if this RTCP instance belongs to an RTP receiver
|
||||
/* return true if this RTCP instance belongs to an RTP receiver
|
||||
* and a receiver report should be generated, otherwise sender report is generated */
|
||||
bool receiver() const;
|
||||
|
||||
/* Generate either RTCP Sender or Receiver report and sent it to all participants
|
||||
/* Generate either RTCP Sender or Receiver report and sent it to all participants
|
||||
* Return RTP_OK on success and RTP_ERROR on error */
|
||||
rtp_error_t generate_report();
|
||||
|
||||
/* Handle different kinds of incoming packets
|
||||
/* Handle different kinds of incoming packets
|
||||
*
|
||||
* These routines will convert the fields of "frame" from network to host byte order
|
||||
*
|
||||
|
@ -95,7 +95,7 @@ namespace uvg_rtp {
|
|||
std::vector<uvg_rtp::socket>& get_sockets();
|
||||
|
||||
/* Somebody joined the multicast group the owner of this RTCP instance is part of
|
||||
* Add it to RTCP participant list so we can start listening for reports
|
||||
* Add it to RTCP participant list so we can start listening for reports
|
||||
*
|
||||
* "clock_rate" tells how much the RTP timestamp advances, this information is needed
|
||||
* to calculate the interarrival jitter correctly. It has nothing do with our clock rate,
|
||||
|
@ -151,7 +151,7 @@ namespace uvg_rtp {
|
|||
static void rtcp_runner(rtcp *rtcp);
|
||||
|
||||
/* when we start the RTCP instance, we don't know what the SSRC of the remote is
|
||||
* when an RTP packet is received, we must check if we've already received a packet
|
||||
* when an RTP packet is received, we must check if we've already received a packet
|
||||
* from this sender and if not, create new entry to receiver_stats_ map */
|
||||
bool is_participant(uint32_t ssrc);
|
||||
|
||||
|
@ -181,14 +181,14 @@ namespace uvg_rtp {
|
|||
* packet-related statistics should not be updated */
|
||||
rtp_error_t update_participant_seq(uint32_t ssrc, uint16_t seq);
|
||||
|
||||
/* Update the RTCP bandwidth variables
|
||||
/* Update the RTCP bandwidth variables
|
||||
*
|
||||
* "pkt_size" tells how much rtcp_byte_count_
|
||||
* "pkt_size" tells how much rtcp_byte_count_
|
||||
* 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
|
||||
/* 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();
|
||||
|
|
504
src/rtcp.cc
504
src/rtcp.cc
|
@ -478,327 +478,6 @@ rtp_error_t uvg_rtp::rtcp::receiver_update_stats(uvg_rtp::frame::rtp_frame *fram
|
|||
return RTP_OK;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::rtcp::send_sender_report_packet(uvg_rtp::frame::rtcp_sender_frame *frame)
|
||||
{
|
||||
LOG_INFO("Generating sender report...");
|
||||
|
||||
if (!frame)
|
||||
return RTP_INVALID_VALUE;
|
||||
|
||||
rtp_error_t ret = RTP_OK;
|
||||
std::vector<uint32_t> ssrcs;
|
||||
uint16_t len = frame->header.length;
|
||||
|
||||
/* RTCP header + SSRC */
|
||||
frame->header.length = htons(frame->header.length);
|
||||
frame->sender_ssrc = htonl(frame->sender_ssrc);
|
||||
|
||||
/* RTCP Sender Info */
|
||||
frame->s_info.ntp_msw = htonl(frame->s_info.ntp_msw);
|
||||
frame->s_info.ntp_lsw = htonl(frame->s_info.ntp_lsw);
|
||||
frame->s_info.rtp_ts = htonl(frame->s_info.rtp_ts);
|
||||
frame->s_info.pkt_cnt = htonl(frame->s_info.pkt_cnt);
|
||||
frame->s_info.byte_cnt = htonl(frame->s_info.byte_cnt);
|
||||
|
||||
/* report block(s) */
|
||||
for (size_t i = 0; i < frame->header.count; ++i) {
|
||||
ssrcs.push_back(frame->blocks[i].ssrc);
|
||||
|
||||
frame->blocks[i].last_seq = htonl(frame->blocks[i].last_seq);
|
||||
frame->blocks[i].jitter = htonl(frame->blocks[i].jitter);
|
||||
frame->blocks[i].ssrc = htonl(frame->blocks[i].ssrc);
|
||||
frame->blocks[i].lost = htonl(frame->blocks[i].lost);
|
||||
frame->blocks[i].dlsr = htonl(frame->blocks[i].dlsr);
|
||||
frame->blocks[i].lsr = htonl(frame->blocks[i].lsr);
|
||||
}
|
||||
|
||||
for (auto& p : participants_) {
|
||||
if ((ret = p.second->socket->sendto(p.second->address, (uint8_t *)frame, len, 0)) != RTP_OK) {
|
||||
LOG_ERROR("sendto() failed!");
|
||||
}
|
||||
|
||||
update_rtcp_bandwidth(len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::rtcp::send_receiver_report_packet(uvg_rtp::frame::rtcp_receiver_frame *frame)
|
||||
{
|
||||
if (!frame)
|
||||
return RTP_INVALID_VALUE;
|
||||
|
||||
rtp_error_t ret;
|
||||
uint16_t len = frame->header.length;
|
||||
|
||||
/* rtcp header + ssrc */
|
||||
frame->header.length = htons(frame->header.length);
|
||||
frame->sender_ssrc = htonl(frame->sender_ssrc);
|
||||
|
||||
/* report block(s) */
|
||||
for (size_t i = 0; i < frame->header.count; ++i) {
|
||||
frame->blocks[i].last_seq = htonl(frame->blocks[i].last_seq);
|
||||
frame->blocks[i].jitter = htonl(frame->blocks[i].jitter);
|
||||
frame->blocks[i].ssrc = htonl(frame->blocks[i].ssrc);
|
||||
frame->blocks[i].lost = htonl(frame->blocks[i].lost);
|
||||
frame->blocks[i].dlsr = htonl(frame->blocks[i].dlsr);
|
||||
frame->blocks[i].lsr = htonl(frame->blocks[i].lsr);
|
||||
}
|
||||
|
||||
for (auto& participant : participants_) {
|
||||
auto p = participant.second;
|
||||
|
||||
if ((ret = p->socket->sendto(p->address, (uint8_t *)frame, len, 0)) != RTP_OK) {
|
||||
LOG_ERROR("sendto() failed!");
|
||||
return ret;
|
||||
}
|
||||
|
||||
update_rtcp_bandwidth(len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::rtcp::send_bye_packet(uvg_rtp::frame::rtcp_bye_frame *frame)
|
||||
{
|
||||
if (!frame)
|
||||
return RTP_INVALID_VALUE;
|
||||
|
||||
if (frame->header.count == 0) {
|
||||
LOG_WARN("Source Count in RTCP BYE packet is 0");
|
||||
}
|
||||
|
||||
uint16_t len = frame->header.length;
|
||||
frame->header.length = htons(frame->header.length);
|
||||
|
||||
for (size_t i = 0; i < frame->header.count; ++i) {
|
||||
frame->ssrc[i] = htonl(frame->ssrc[i]);
|
||||
}
|
||||
|
||||
rtp_error_t ret;
|
||||
|
||||
for (auto& participant : participants_) {
|
||||
auto p = participant.second;
|
||||
|
||||
if ((ret = p->socket->sendto(p->address, (uint8_t *)frame, len, 0)) != RTP_OK) {
|
||||
LOG_ERROR("sendto() failed!");
|
||||
return ret;
|
||||
}
|
||||
|
||||
update_rtcp_bandwidth(len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::rtcp::send_sdes_packet(uvg_rtp::frame::rtcp_sdes_frame *frame)
|
||||
{
|
||||
if (!frame)
|
||||
return RTP_INVALID_VALUE;
|
||||
|
||||
if (frame->header.count == 0) {
|
||||
LOG_WARN("");
|
||||
}
|
||||
|
||||
uint16_t len = frame->header.length;
|
||||
|
||||
/* rtcp header + ssrc */
|
||||
frame->header.length = htons(frame->header.length);
|
||||
frame->sender_ssrc = htonl(frame->sender_ssrc);
|
||||
|
||||
for (size_t i = 0; i < frame->header.count; ++i) {
|
||||
frame->items[i].length = htons(frame->items[i].length);
|
||||
}
|
||||
|
||||
rtp_error_t ret;
|
||||
|
||||
for (auto& participant : participants_) {
|
||||
auto p = participant.second;
|
||||
|
||||
if ((ret = p->socket->sendto(p->address, (uint8_t *)frame, len, 0)) != RTP_OK) {
|
||||
LOG_ERROR("sendto() failed!");
|
||||
return ret;
|
||||
}
|
||||
|
||||
update_rtcp_bandwidth(len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::rtcp::send_app_packet(uvg_rtp::frame::rtcp_app_frame *frame)
|
||||
{
|
||||
if (!frame)
|
||||
return RTP_INVALID_VALUE;
|
||||
|
||||
uint16_t len = frame->length;
|
||||
uint32_t ssrc = frame->ssrc;
|
||||
|
||||
frame->length = htons(frame->length);
|
||||
frame->ssrc = htonl(frame->ssrc);
|
||||
|
||||
if (!is_participant(ssrc)) {
|
||||
LOG_ERROR("Unknown participant 0x%x", ssrc);
|
||||
return RTP_INVALID_VALUE;
|
||||
}
|
||||
|
||||
rtp_error_t ret = participants_[ssrc]->socket->sendto((uint8_t *)frame, len, 0, NULL);
|
||||
|
||||
if (ret == RTP_OK)
|
||||
update_rtcp_bandwidth(len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uvg_rtp::frame::rtcp_sender_frame *uvg_rtp::rtcp::get_sender_packet(uint32_t ssrc)
|
||||
{
|
||||
if (participants_.find(ssrc) == participants_.end())
|
||||
return nullptr;
|
||||
|
||||
auto frame = participants_[ssrc]->s_frame;
|
||||
participants_[ssrc]->s_frame = nullptr;
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
uvg_rtp::frame::rtcp_receiver_frame *uvg_rtp::rtcp::get_receiver_packet(uint32_t ssrc)
|
||||
{
|
||||
if (participants_.find(ssrc) == participants_.end())
|
||||
return nullptr;
|
||||
|
||||
auto frame = participants_[ssrc]->r_frame;
|
||||
participants_[ssrc]->r_frame = nullptr;
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
uvg_rtp::frame::rtcp_sdes_frame *uvg_rtp::rtcp::get_sdes_packet(uint32_t ssrc)
|
||||
{
|
||||
if (participants_.find(ssrc) == participants_.end())
|
||||
return nullptr;
|
||||
|
||||
auto frame = participants_[ssrc]->sdes_frame;
|
||||
participants_[ssrc]->sdes_frame = nullptr;
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
uvg_rtp::frame::rtcp_app_frame *uvg_rtp::rtcp::get_app_packet(uint32_t ssrc)
|
||||
{
|
||||
if (participants_.find(ssrc) == participants_.end())
|
||||
return nullptr;
|
||||
|
||||
auto frame = participants_[ssrc]->app_frame;
|
||||
participants_[ssrc]->app_frame = nullptr;
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::rtcp::generate_sender_report()
|
||||
{
|
||||
/* No one to generate report for */
|
||||
if (num_receivers_ == 0)
|
||||
return RTP_NOT_READY;
|
||||
|
||||
uvg_rtp::frame::rtcp_sender_frame *frame;
|
||||
|
||||
if ((frame = uvg_rtp::frame::alloc_rtcp_sender_frame(senders_)) == nullptr) {
|
||||
LOG_ERROR("Failed to allocate RTCP Receiver Report frame!");
|
||||
return rtp_errno;
|
||||
}
|
||||
|
||||
size_t ptr = 0;
|
||||
uint64_t timestamp = uvg_rtp::clock::ntp::now();
|
||||
rtp_error_t ret = RTP_OK;
|
||||
|
||||
frame->header.count = senders_;
|
||||
frame->sender_ssrc = ssrc_;
|
||||
frame->s_info.ntp_msw = timestamp >> 32;
|
||||
frame->s_info.ntp_lsw = timestamp & 0xffffffff;
|
||||
frame->s_info.rtp_ts = rtp_ts_start_ + (uvg_rtp::clock::ntp::diff(timestamp, clock_start_)) * clock_rate_ / 1000;
|
||||
frame->s_info.pkt_cnt = sender_stats.sent_pkts;
|
||||
frame->s_info.byte_cnt = sender_stats.sent_bytes;
|
||||
|
||||
LOG_DEBUG("Sender Report from 0x%x has %zu blocks", ssrc_, senders_);
|
||||
|
||||
for (auto& participant : participants_) {
|
||||
if (!participant.second->sender)
|
||||
continue;
|
||||
|
||||
frame->blocks[ptr].ssrc = participant.first;
|
||||
|
||||
if (participant.second->stats.dropped_pkts != 0) {
|
||||
frame->blocks[ptr].fraction =
|
||||
participant.second->stats.received_pkts / participant.second->stats.dropped_pkts;
|
||||
}
|
||||
|
||||
frame->blocks[ptr].lost = participant.second->stats.dropped_pkts;
|
||||
frame->blocks[ptr].last_seq = participant.second->stats.max_seq;
|
||||
frame->blocks[ptr].jitter = participant.second->stats.jitter;
|
||||
frame->blocks[ptr].lsr = participant.second->stats.lsr;
|
||||
|
||||
ptr++;
|
||||
}
|
||||
|
||||
/* Send sender report only if the session contains other senders */
|
||||
if (ptr != 0)
|
||||
ret = uvg_rtp::rtcp::send_sender_report_packet(frame);
|
||||
|
||||
(void)uvg_rtp::frame::dealloc_frame(frame);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::rtcp::generate_receiver_report()
|
||||
{
|
||||
/* It is possible that haven't yet received an RTP packet from remote */
|
||||
if (num_receivers_ == 0) {
|
||||
LOG_WARN("cannot send receiver report yet, haven't received anything");
|
||||
return RTP_NOT_READY;
|
||||
}
|
||||
|
||||
size_t ptr = 0;
|
||||
rtp_error_t ret;
|
||||
uvg_rtp::frame::rtcp_receiver_frame *frame;
|
||||
|
||||
if ((frame = uvg_rtp::frame::alloc_rtcp_receiver_frame(num_receivers_)) == nullptr) {
|
||||
LOG_ERROR("Failed to allocate RTCP Receiver Report frame!");
|
||||
return rtp_errno;
|
||||
}
|
||||
|
||||
frame->header.count = num_receivers_;
|
||||
frame->sender_ssrc = ssrc_;
|
||||
|
||||
LOG_INFO("Receiver Report from 0x%x has %zu blocks", ssrc_, num_receivers_);
|
||||
|
||||
for (auto& participant : participants_) {
|
||||
frame->blocks[ptr].ssrc = participant.first;
|
||||
|
||||
if (participant.second->stats.dropped_pkts != 0) {
|
||||
frame->blocks[ptr].fraction =
|
||||
participant.second->stats.received_bytes / participant.second->stats.dropped_pkts;
|
||||
}
|
||||
|
||||
frame->blocks[ptr].lost = participant.second->stats.dropped_pkts;
|
||||
frame->blocks[ptr].last_seq = participant.second->stats.max_seq;
|
||||
frame->blocks[ptr].jitter = participant.second->stats.jitter;
|
||||
frame->blocks[ptr].lsr = participant.second->stats.lsr;
|
||||
|
||||
/* calculate delay of last SR only if SR has been received at least once */
|
||||
if (frame->blocks[ptr].lsr != 0) {
|
||||
uint64_t diff = uvg_rtp::clock::hrc::diff_now(participant.second->stats.sr_ts);
|
||||
frame->blocks[ptr].dlsr = uvg_rtp::clock::ms_to_jiffies(diff);
|
||||
}
|
||||
|
||||
ptr++;
|
||||
}
|
||||
|
||||
ret = uvg_rtp::rtcp::send_receiver_report_packet(frame);
|
||||
(void)uvg_rtp::frame::dealloc_frame(frame);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::rtcp::generate_report()
|
||||
{
|
||||
if (receiver_)
|
||||
|
@ -842,189 +521,6 @@ rtp_error_t uvg_rtp::rtcp::install_app_hook(void (*hook)(uvg_rtp::frame::rtcp_ap
|
|||
return RTP_OK;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::rtcp::handle_sender_report_packet(uvg_rtp::frame::rtcp_sender_frame *frame, size_t size)
|
||||
{
|
||||
(void)size;
|
||||
|
||||
if (!frame)
|
||||
return RTP_INVALID_VALUE;
|
||||
|
||||
frame->sender_ssrc = ntohl(frame->sender_ssrc);
|
||||
|
||||
if (!is_participant(frame->sender_ssrc))
|
||||
add_participant(frame->sender_ssrc);
|
||||
|
||||
uint32_t ntp_msw = ntohl(frame->s_info.ntp_msw);
|
||||
uint32_t ntp_lsw = ntohl(frame->s_info.ntp_lsw);
|
||||
uint32_t lsr = ((ntp_msw >> 16) & 0xffff) | ((ntp_lsw & 0xffff0000) >> 16);
|
||||
|
||||
participants_[frame->sender_ssrc]->stats.lsr = lsr;
|
||||
participants_[frame->sender_ssrc]->stats.sr_ts = uvg_rtp::clock::hrc::now();
|
||||
|
||||
/* We need to make a copy of the frame because right now frame points to RTCP recv buffer
|
||||
* Deallocate previous frame if it exists */
|
||||
if (participants_[frame->sender_ssrc]->s_frame != nullptr)
|
||||
(void)uvg_rtp::frame::dealloc_frame(participants_[frame->sender_ssrc]->s_frame);
|
||||
|
||||
auto cpy_frame = uvg_rtp::frame::alloc_rtcp_sender_frame(frame->header.count);
|
||||
memcpy(cpy_frame, frame, size);
|
||||
|
||||
fprintf(stderr, "Sender report:\n");
|
||||
for (int i = 0; i < frame->header.count; ++i) {
|
||||
cpy_frame->blocks[i].lost = ntohl(cpy_frame->blocks[i].lost);
|
||||
cpy_frame->blocks[i].last_seq = ntohl(cpy_frame->blocks[i].last_seq);
|
||||
cpy_frame->blocks[i].lsr = ntohl(cpy_frame->blocks[i].lsr);
|
||||
cpy_frame->blocks[i].dlsr = ntohl(cpy_frame->blocks[i].dlsr);
|
||||
|
||||
fprintf(stderr, "-------\n");
|
||||
fprintf(stderr, "lost: %d\n", cpy_frame->blocks[i].lost);
|
||||
fprintf(stderr, "last_seq: %u\n", cpy_frame->blocks[i].last_seq);
|
||||
fprintf(stderr, "last sr: %u\n", cpy_frame->blocks[i].lsr);
|
||||
fprintf(stderr, "dlsr: %u\n", cpy_frame->blocks[i].dlsr);
|
||||
fprintf(stderr, "-------\n");
|
||||
}
|
||||
|
||||
if (sender_hook_)
|
||||
sender_hook_(cpy_frame);
|
||||
else
|
||||
participants_[frame->sender_ssrc]->s_frame = cpy_frame;
|
||||
|
||||
return RTP_OK;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::rtcp::handle_receiver_report_packet(uvg_rtp::frame::rtcp_receiver_frame *frame, size_t size)
|
||||
{
|
||||
(void)size;
|
||||
|
||||
if (!frame)
|
||||
return RTP_INVALID_VALUE;
|
||||
|
||||
frame->header.length = ntohs(frame->header.length);
|
||||
frame->sender_ssrc = ntohl(frame->sender_ssrc);
|
||||
|
||||
/* Receiver Reports are sent from participant that don't send RTP packets
|
||||
* This means that the sender of this report is not in the participants_ map
|
||||
* but rather in the initial_participants_ vector
|
||||
*
|
||||
* Check if that's the case and if so, move the entry from initial_participants_ to participants_ */
|
||||
if (!is_participant(frame->sender_ssrc)) {
|
||||
/* TODO: this is not correct way to do it! fix before multicast */
|
||||
add_participant(frame->sender_ssrc);
|
||||
}
|
||||
|
||||
if (frame->header.count == 0) {
|
||||
LOG_ERROR("Receiver Report cannot have 0 report blocks!");
|
||||
return RTP_INVALID_VALUE;
|
||||
}
|
||||
|
||||
/* We need to make a copy of the frame because right now frame points to RTCP recv buffer
|
||||
* Deallocate previous frame if it exists */
|
||||
if (participants_[frame->sender_ssrc]->r_frame != nullptr)
|
||||
(void)uvg_rtp::frame::dealloc_frame(participants_[frame->sender_ssrc]->r_frame);
|
||||
|
||||
auto cpy_frame = uvg_rtp::frame::alloc_rtcp_receiver_frame(frame->header.count);
|
||||
memcpy(cpy_frame, frame, size);
|
||||
|
||||
fprintf(stderr, "Receiver report:\n");
|
||||
for (int i = 0; i < frame->header.count; ++i) {
|
||||
cpy_frame->blocks[i].lost = ntohl(cpy_frame->blocks[i].lost);
|
||||
cpy_frame->blocks[i].last_seq = ntohl(cpy_frame->blocks[i].last_seq);
|
||||
cpy_frame->blocks[i].jitter = ntohl(cpy_frame->blocks[i].jitter);
|
||||
cpy_frame->blocks[i].lsr = ntohl(cpy_frame->blocks[i].lsr);
|
||||
cpy_frame->blocks[i].dlsr = ntohl(cpy_frame->blocks[i].dlsr);
|
||||
|
||||
fprintf(stderr, "-------\n");
|
||||
fprintf(stderr, "lost: %d\n", cpy_frame->blocks[i].lost);
|
||||
fprintf(stderr, "last_seq: %u\n", cpy_frame->blocks[i].last_seq);
|
||||
fprintf(stderr, "jitter: %u\n", cpy_frame->blocks[i].jitter);
|
||||
fprintf(stderr, "last sr: %u\n", cpy_frame->blocks[i].lsr);
|
||||
fprintf(stderr, "dlsr: %u\n", cpy_frame->blocks[i].dlsr);
|
||||
fprintf(stderr, "-------\n");
|
||||
}
|
||||
|
||||
if (receiver_hook_)
|
||||
receiver_hook_(cpy_frame);
|
||||
else
|
||||
participants_[frame->sender_ssrc]->r_frame = cpy_frame;
|
||||
|
||||
return RTP_OK;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::rtcp::handle_sdes_packet(uvg_rtp::frame::rtcp_sdes_frame *frame, size_t size)
|
||||
{
|
||||
if (!frame)
|
||||
return RTP_INVALID_VALUE;
|
||||
|
||||
if (frame->header.count == 0) {
|
||||
LOG_ERROR("SDES packet cannot contain 0 fields!");
|
||||
return RTP_INVALID_VALUE;
|
||||
}
|
||||
|
||||
frame->sender_ssrc = ntohl(frame->sender_ssrc);
|
||||
|
||||
/* We need to make a copy of the frame because right now frame points to RTCP recv buffer
|
||||
* Deallocate previous frame if it exists */
|
||||
if (participants_[frame->sender_ssrc]->sdes_frame != nullptr)
|
||||
(void)uvg_rtp::frame::dealloc_frame(participants_[frame->sender_ssrc]->sdes_frame);
|
||||
|
||||
uint8_t *cpy_frame = new uint8_t[size];
|
||||
memcpy(cpy_frame, frame, size);
|
||||
|
||||
if (sdes_hook_)
|
||||
sdes_hook_((uvg_rtp::frame::rtcp_sdes_frame *)cpy_frame);
|
||||
else
|
||||
participants_[frame->sender_ssrc]->sdes_frame = (uvg_rtp::frame::rtcp_sdes_frame *)cpy_frame;
|
||||
|
||||
return RTP_OK;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::rtcp::handle_bye_packet(uvg_rtp::frame::rtcp_bye_frame *frame, size_t size)
|
||||
{
|
||||
(void)size;
|
||||
|
||||
if (!frame)
|
||||
return RTP_INVALID_VALUE;
|
||||
|
||||
for (size_t i = 0; i < frame->header.count; ++i) {
|
||||
uint32_t ssrc = ntohl(frame->ssrc[i]);
|
||||
|
||||
if (!is_participant(ssrc)) {
|
||||
LOG_WARN("Participants 0x%x is not part of this group!", ssrc);
|
||||
continue;
|
||||
}
|
||||
|
||||
delete participants_[ssrc]->socket;
|
||||
delete participants_[ssrc];
|
||||
participants_.erase(ssrc);
|
||||
}
|
||||
|
||||
return RTP_OK;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::rtcp::handle_app_packet(uvg_rtp::frame::rtcp_app_frame *frame, size_t size)
|
||||
{
|
||||
if (!frame)
|
||||
return RTP_INVALID_VALUE;
|
||||
|
||||
frame->ssrc = ntohl(frame->ssrc);
|
||||
frame->length = ntohs(frame->length);
|
||||
|
||||
/* We need to make a copy of the frame because right now frame points to RTCP recv buffer
|
||||
* Deallocate previous frame if it exists */
|
||||
if (participants_[frame->ssrc]->app_frame != nullptr)
|
||||
(void)uvg_rtp::frame::dealloc_frame(participants_[frame->ssrc]->app_frame);
|
||||
|
||||
uint8_t *cpy_frame = new uint8_t[size];
|
||||
memcpy(cpy_frame, frame, size);
|
||||
|
||||
if (app_hook_)
|
||||
app_hook_((uvg_rtp::frame::rtcp_app_frame *)cpy_frame);
|
||||
else
|
||||
participants_[frame->ssrc]->app_frame = (uvg_rtp::frame::rtcp_app_frame *)cpy_frame;
|
||||
|
||||
return RTP_OK;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::rtcp::handle_incoming_packet(uint8_t *buffer, size_t size)
|
||||
{
|
||||
(void)size;
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
#ifdef _WIN32
|
||||
#else
|
||||
#endif
|
||||
|
||||
#include "rtcp.hh"
|
||||
|
||||
uvg_rtp::frame::rtcp_app_frame *uvg_rtp::rtcp::get_app_packet(uint32_t ssrc)
|
||||
{
|
||||
if (participants_.find(ssrc) == participants_.end())
|
||||
return nullptr;
|
||||
|
||||
auto frame = participants_[ssrc]->app_frame;
|
||||
participants_[ssrc]->app_frame = nullptr;
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::rtcp::handle_app_packet(uvg_rtp::frame::rtcp_app_frame *frame, size_t size)
|
||||
{
|
||||
if (!frame)
|
||||
return RTP_INVALID_VALUE;
|
||||
|
||||
frame->ssrc = ntohl(frame->ssrc);
|
||||
frame->length = ntohs(frame->length);
|
||||
|
||||
/* We need to make a copy of the frame because right now frame points to RTCP recv buffer
|
||||
* Deallocate previous frame if it exists */
|
||||
if (participants_[frame->ssrc]->app_frame != nullptr)
|
||||
(void)uvg_rtp::frame::dealloc_frame(participants_[frame->ssrc]->app_frame);
|
||||
|
||||
uint8_t *cpy_frame = new uint8_t[size];
|
||||
memcpy(cpy_frame, frame, size);
|
||||
|
||||
if (app_hook_)
|
||||
app_hook_((uvg_rtp::frame::rtcp_app_frame *)cpy_frame);
|
||||
else
|
||||
participants_[frame->ssrc]->app_frame = (uvg_rtp::frame::rtcp_app_frame *)cpy_frame;
|
||||
|
||||
return RTP_OK;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::rtcp::send_app_packet(uvg_rtp::frame::rtcp_app_frame *frame)
|
||||
{
|
||||
if (!frame)
|
||||
return RTP_INVALID_VALUE;
|
||||
|
||||
uint16_t len = frame->length;
|
||||
uint32_t ssrc = frame->ssrc;
|
||||
|
||||
frame->length = htons(frame->length);
|
||||
frame->ssrc = htonl(frame->ssrc);
|
||||
|
||||
if (!is_participant(ssrc)) {
|
||||
LOG_ERROR("Unknown participant 0x%x", ssrc);
|
||||
return RTP_INVALID_VALUE;
|
||||
}
|
||||
|
||||
rtp_error_t ret = participants_[ssrc]->socket->sendto((uint8_t *)frame, len, 0, NULL);
|
||||
|
||||
if (ret == RTP_OK)
|
||||
update_rtcp_bandwidth(len);
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
#ifdef _WIN32
|
||||
#else
|
||||
#endif
|
||||
|
||||
#include "rtcp.hh"
|
||||
|
||||
rtp_error_t uvg_rtp::rtcp::handle_bye_packet(uvg_rtp::frame::rtcp_bye_frame *frame, size_t size)
|
||||
{
|
||||
(void)size;
|
||||
|
||||
if (!frame)
|
||||
return RTP_INVALID_VALUE;
|
||||
|
||||
for (size_t i = 0; i < frame->header.count; ++i) {
|
||||
uint32_t ssrc = ntohl(frame->ssrc[i]);
|
||||
|
||||
if (!is_participant(ssrc)) {
|
||||
LOG_WARN("Participants 0x%x is not part of this group!", ssrc);
|
||||
continue;
|
||||
}
|
||||
|
||||
delete participants_[ssrc]->socket;
|
||||
delete participants_[ssrc];
|
||||
participants_.erase(ssrc);
|
||||
}
|
||||
|
||||
return RTP_OK;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::rtcp::send_bye_packet(uvg_rtp::frame::rtcp_bye_frame *frame)
|
||||
{
|
||||
if (!frame)
|
||||
return RTP_INVALID_VALUE;
|
||||
|
||||
if (frame->header.count == 0) {
|
||||
LOG_WARN("Source Count in RTCP BYE packet is 0");
|
||||
}
|
||||
|
||||
uint16_t len = frame->header.length;
|
||||
frame->header.length = htons(frame->header.length);
|
||||
|
||||
for (size_t i = 0; i < frame->header.count; ++i) {
|
||||
frame->ssrc[i] = htonl(frame->ssrc[i]);
|
||||
}
|
||||
|
||||
rtp_error_t ret;
|
||||
|
||||
for (auto& participant : participants_) {
|
||||
auto p = participant.second;
|
||||
|
||||
if ((ret = p->socket->sendto(p->address, (uint8_t *)frame, len, 0)) != RTP_OK) {
|
||||
LOG_ERROR("sendto() failed!");
|
||||
return ret;
|
||||
}
|
||||
|
||||
update_rtcp_bandwidth(len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
SOURCES += \
|
||||
src/rtcp/app.cc \
|
||||
src/rtcp/sdes.cc \
|
||||
src/rtcp/bye.cc \
|
||||
src/rtcp/receiver.cc \
|
||||
src/rtcp/sender.cc
|
|
@ -0,0 +1,160 @@
|
|||
#ifdef _WIN32
|
||||
#else
|
||||
#endif
|
||||
|
||||
#include "rtcp.hh"
|
||||
|
||||
uvg_rtp::frame::rtcp_receiver_frame *uvg_rtp::rtcp::get_receiver_packet(uint32_t ssrc)
|
||||
{
|
||||
if (participants_.find(ssrc) == participants_.end())
|
||||
return nullptr;
|
||||
|
||||
auto frame = participants_[ssrc]->r_frame;
|
||||
participants_[ssrc]->r_frame = nullptr;
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::rtcp::handle_receiver_report_packet(uvg_rtp::frame::rtcp_receiver_frame *frame, size_t size)
|
||||
{
|
||||
(void)size;
|
||||
|
||||
if (!frame)
|
||||
return RTP_INVALID_VALUE;
|
||||
|
||||
frame->header.length = ntohs(frame->header.length);
|
||||
frame->sender_ssrc = ntohl(frame->sender_ssrc);
|
||||
|
||||
/* Receiver Reports are sent from participant that don't send RTP packets
|
||||
* This means that the sender of this report is not in the participants_ map
|
||||
* but rather in the initial_participants_ vector
|
||||
*
|
||||
* Check if that's the case and if so, move the entry from initial_participants_ to participants_ */
|
||||
if (!is_participant(frame->sender_ssrc)) {
|
||||
/* TODO: this is not correct way to do it! fix before multicast */
|
||||
add_participant(frame->sender_ssrc);
|
||||
}
|
||||
|
||||
if (frame->header.count == 0) {
|
||||
LOG_ERROR("Receiver Report cannot have 0 report blocks!");
|
||||
return RTP_INVALID_VALUE;
|
||||
}
|
||||
|
||||
/* We need to make a copy of the frame because right now frame points to RTCP recv buffer
|
||||
* Deallocate previous frame if it exists */
|
||||
if (participants_[frame->sender_ssrc]->r_frame != nullptr)
|
||||
(void)uvg_rtp::frame::dealloc_frame(participants_[frame->sender_ssrc]->r_frame);
|
||||
|
||||
auto cpy_frame = uvg_rtp::frame::alloc_rtcp_receiver_frame(frame->header.count);
|
||||
memcpy(cpy_frame, frame, size);
|
||||
|
||||
fprintf(stderr, "Receiver report:\n");
|
||||
for (int i = 0; i < frame->header.count; ++i) {
|
||||
cpy_frame->blocks[i].lost = ntohl(cpy_frame->blocks[i].lost);
|
||||
cpy_frame->blocks[i].last_seq = ntohl(cpy_frame->blocks[i].last_seq);
|
||||
cpy_frame->blocks[i].jitter = ntohl(cpy_frame->blocks[i].jitter);
|
||||
cpy_frame->blocks[i].lsr = ntohl(cpy_frame->blocks[i].lsr);
|
||||
cpy_frame->blocks[i].dlsr = ntohl(cpy_frame->blocks[i].dlsr);
|
||||
|
||||
fprintf(stderr, "-------\n");
|
||||
fprintf(stderr, "lost: %d\n", cpy_frame->blocks[i].lost);
|
||||
fprintf(stderr, "last_seq: %u\n", cpy_frame->blocks[i].last_seq);
|
||||
fprintf(stderr, "jitter: %u\n", cpy_frame->blocks[i].jitter);
|
||||
fprintf(stderr, "last sr: %u\n", cpy_frame->blocks[i].lsr);
|
||||
fprintf(stderr, "dlsr: %u\n", cpy_frame->blocks[i].dlsr);
|
||||
fprintf(stderr, "-------\n");
|
||||
}
|
||||
|
||||
if (receiver_hook_)
|
||||
receiver_hook_(cpy_frame);
|
||||
else
|
||||
participants_[frame->sender_ssrc]->r_frame = cpy_frame;
|
||||
|
||||
return RTP_OK;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::rtcp::send_receiver_report_packet(uvg_rtp::frame::rtcp_receiver_frame *frame)
|
||||
{
|
||||
if (!frame)
|
||||
return RTP_INVALID_VALUE;
|
||||
|
||||
rtp_error_t ret;
|
||||
uint16_t len = frame->header.length;
|
||||
|
||||
/* rtcp header + ssrc */
|
||||
frame->header.length = htons(frame->header.length);
|
||||
frame->sender_ssrc = htonl(frame->sender_ssrc);
|
||||
|
||||
/* report block(s) */
|
||||
for (size_t i = 0; i < frame->header.count; ++i) {
|
||||
frame->blocks[i].last_seq = htonl(frame->blocks[i].last_seq);
|
||||
frame->blocks[i].jitter = htonl(frame->blocks[i].jitter);
|
||||
frame->blocks[i].ssrc = htonl(frame->blocks[i].ssrc);
|
||||
frame->blocks[i].lost = htonl(frame->blocks[i].lost);
|
||||
frame->blocks[i].dlsr = htonl(frame->blocks[i].dlsr);
|
||||
frame->blocks[i].lsr = htonl(frame->blocks[i].lsr);
|
||||
}
|
||||
|
||||
for (auto& participant : participants_) {
|
||||
auto p = participant.second;
|
||||
|
||||
if ((ret = p->socket->sendto(p->address, (uint8_t *)frame, len, 0)) != RTP_OK) {
|
||||
LOG_ERROR("sendto() failed!");
|
||||
return ret;
|
||||
}
|
||||
|
||||
update_rtcp_bandwidth(len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::rtcp::generate_receiver_report()
|
||||
{
|
||||
/* It is possible that haven't yet received an RTP packet from remote */
|
||||
if (num_receivers_ == 0) {
|
||||
LOG_WARN("cannot send receiver report yet, haven't received anything");
|
||||
return RTP_NOT_READY;
|
||||
}
|
||||
|
||||
size_t ptr = 0;
|
||||
rtp_error_t ret;
|
||||
uvg_rtp::frame::rtcp_receiver_frame *frame;
|
||||
|
||||
if ((frame = uvg_rtp::frame::alloc_rtcp_receiver_frame(num_receivers_)) == nullptr) {
|
||||
LOG_ERROR("Failed to allocate RTCP Receiver Report frame!");
|
||||
return rtp_errno;
|
||||
}
|
||||
|
||||
frame->header.count = num_receivers_;
|
||||
frame->sender_ssrc = ssrc_;
|
||||
|
||||
LOG_INFO("Receiver Report from 0x%x has %zu blocks", ssrc_, num_receivers_);
|
||||
|
||||
for (auto& participant : participants_) {
|
||||
frame->blocks[ptr].ssrc = participant.first;
|
||||
|
||||
if (participant.second->stats.dropped_pkts != 0) {
|
||||
frame->blocks[ptr].fraction =
|
||||
participant.second->stats.received_bytes / participant.second->stats.dropped_pkts;
|
||||
}
|
||||
|
||||
frame->blocks[ptr].lost = participant.second->stats.dropped_pkts;
|
||||
frame->blocks[ptr].last_seq = participant.second->stats.max_seq;
|
||||
frame->blocks[ptr].jitter = participant.second->stats.jitter;
|
||||
frame->blocks[ptr].lsr = participant.second->stats.lsr;
|
||||
|
||||
/* calculate delay of last SR only if SR has been received at least once */
|
||||
if (frame->blocks[ptr].lsr != 0) {
|
||||
uint64_t diff = uvg_rtp::clock::hrc::diff_now(participant.second->stats.sr_ts);
|
||||
frame->blocks[ptr].dlsr = uvg_rtp::clock::ms_to_jiffies(diff);
|
||||
}
|
||||
|
||||
ptr++;
|
||||
}
|
||||
|
||||
ret = uvg_rtp::rtcp::send_receiver_report_packet(frame);
|
||||
(void)uvg_rtp::frame::dealloc_frame(frame);
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
#ifdef _WIN32
|
||||
#else
|
||||
#endif
|
||||
|
||||
#include "rtcp.hh"
|
||||
|
||||
uvg_rtp::frame::rtcp_sdes_frame *uvg_rtp::rtcp::get_sdes_packet(uint32_t ssrc)
|
||||
{
|
||||
if (participants_.find(ssrc) == participants_.end())
|
||||
return nullptr;
|
||||
|
||||
auto frame = participants_[ssrc]->sdes_frame;
|
||||
participants_[ssrc]->sdes_frame = nullptr;
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::rtcp::handle_sdes_packet(uvg_rtp::frame::rtcp_sdes_frame *frame, size_t size)
|
||||
{
|
||||
if (!frame)
|
||||
return RTP_INVALID_VALUE;
|
||||
|
||||
if (frame->header.count == 0) {
|
||||
LOG_ERROR("SDES packet cannot contain 0 fields!");
|
||||
return RTP_INVALID_VALUE;
|
||||
}
|
||||
|
||||
frame->sender_ssrc = ntohl(frame->sender_ssrc);
|
||||
|
||||
/* We need to make a copy of the frame because right now frame points to RTCP recv buffer
|
||||
* Deallocate previous frame if it exists */
|
||||
if (participants_[frame->sender_ssrc]->sdes_frame != nullptr)
|
||||
(void)uvg_rtp::frame::dealloc_frame(participants_[frame->sender_ssrc]->sdes_frame);
|
||||
|
||||
uint8_t *cpy_frame = new uint8_t[size];
|
||||
memcpy(cpy_frame, frame, size);
|
||||
|
||||
if (sdes_hook_)
|
||||
sdes_hook_((uvg_rtp::frame::rtcp_sdes_frame *)cpy_frame);
|
||||
else
|
||||
participants_[frame->sender_ssrc]->sdes_frame = (uvg_rtp::frame::rtcp_sdes_frame *)cpy_frame;
|
||||
|
||||
return RTP_OK;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::rtcp::send_sdes_packet(uvg_rtp::frame::rtcp_sdes_frame *frame)
|
||||
{
|
||||
if (!frame)
|
||||
return RTP_INVALID_VALUE;
|
||||
|
||||
if (frame->header.count == 0) {
|
||||
LOG_WARN("");
|
||||
}
|
||||
|
||||
uint16_t len = frame->header.length;
|
||||
|
||||
/* rtcp header + ssrc */
|
||||
frame->header.length = htons(frame->header.length);
|
||||
frame->sender_ssrc = htonl(frame->sender_ssrc);
|
||||
|
||||
for (size_t i = 0; i < frame->header.count; ++i) {
|
||||
frame->items[i].length = htons(frame->items[i].length);
|
||||
}
|
||||
|
||||
rtp_error_t ret;
|
||||
|
||||
for (auto& participant : participants_) {
|
||||
auto p = participant.second;
|
||||
|
||||
if ((ret = p->socket->sendto(p->address, (uint8_t *)frame, len, 0)) != RTP_OK) {
|
||||
LOG_ERROR("sendto() failed!");
|
||||
return ret;
|
||||
}
|
||||
|
||||
update_rtcp_bandwidth(len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
#ifdef _WIN32
|
||||
#else
|
||||
#endif
|
||||
|
||||
#include "rtcp.hh"
|
||||
|
||||
uvg_rtp::frame::rtcp_sender_frame *uvg_rtp::rtcp::get_sender_packet(uint32_t ssrc)
|
||||
{
|
||||
if (participants_.find(ssrc) == participants_.end())
|
||||
return nullptr;
|
||||
|
||||
auto frame = participants_[ssrc]->s_frame;
|
||||
participants_[ssrc]->s_frame = nullptr;
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::rtcp::handle_sender_report_packet(uvg_rtp::frame::rtcp_sender_frame *frame, size_t size)
|
||||
{
|
||||
(void)size;
|
||||
|
||||
if (!frame)
|
||||
return RTP_INVALID_VALUE;
|
||||
|
||||
frame->sender_ssrc = ntohl(frame->sender_ssrc);
|
||||
|
||||
if (!is_participant(frame->sender_ssrc))
|
||||
add_participant(frame->sender_ssrc);
|
||||
|
||||
uint32_t ntp_msw = ntohl(frame->s_info.ntp_msw);
|
||||
uint32_t ntp_lsw = ntohl(frame->s_info.ntp_lsw);
|
||||
uint32_t lsr = ((ntp_msw >> 16) & 0xffff) | ((ntp_lsw & 0xffff0000) >> 16);
|
||||
|
||||
participants_[frame->sender_ssrc]->stats.lsr = lsr;
|
||||
participants_[frame->sender_ssrc]->stats.sr_ts = uvg_rtp::clock::hrc::now();
|
||||
|
||||
/* We need to make a copy of the frame because right now frame points to RTCP recv buffer
|
||||
* Deallocate previous frame if it exists */
|
||||
if (participants_[frame->sender_ssrc]->s_frame != nullptr)
|
||||
(void)uvg_rtp::frame::dealloc_frame(participants_[frame->sender_ssrc]->s_frame);
|
||||
|
||||
auto cpy_frame = uvg_rtp::frame::alloc_rtcp_sender_frame(frame->header.count);
|
||||
memcpy(cpy_frame, frame, size);
|
||||
|
||||
fprintf(stderr, "Sender report:\n");
|
||||
for (int i = 0; i < frame->header.count; ++i) {
|
||||
cpy_frame->blocks[i].lost = ntohl(cpy_frame->blocks[i].lost);
|
||||
cpy_frame->blocks[i].last_seq = ntohl(cpy_frame->blocks[i].last_seq);
|
||||
cpy_frame->blocks[i].lsr = ntohl(cpy_frame->blocks[i].lsr);
|
||||
cpy_frame->blocks[i].dlsr = ntohl(cpy_frame->blocks[i].dlsr);
|
||||
|
||||
fprintf(stderr, "-------\n");
|
||||
fprintf(stderr, "lost: %d\n", cpy_frame->blocks[i].lost);
|
||||
fprintf(stderr, "last_seq: %u\n", cpy_frame->blocks[i].last_seq);
|
||||
fprintf(stderr, "last sr: %u\n", cpy_frame->blocks[i].lsr);
|
||||
fprintf(stderr, "dlsr: %u\n", cpy_frame->blocks[i].dlsr);
|
||||
fprintf(stderr, "-------\n");
|
||||
}
|
||||
|
||||
if (sender_hook_)
|
||||
sender_hook_(cpy_frame);
|
||||
else
|
||||
participants_[frame->sender_ssrc]->s_frame = cpy_frame;
|
||||
|
||||
return RTP_OK;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::rtcp::send_sender_report_packet(uvg_rtp::frame::rtcp_sender_frame *frame)
|
||||
{
|
||||
LOG_INFO("Generating sender report...");
|
||||
|
||||
if (!frame)
|
||||
return RTP_INVALID_VALUE;
|
||||
|
||||
rtp_error_t ret = RTP_OK;
|
||||
std::vector<uint32_t> ssrcs;
|
||||
uint16_t len = frame->header.length;
|
||||
|
||||
/* RTCP header + SSRC */
|
||||
frame->header.length = htons(frame->header.length);
|
||||
frame->sender_ssrc = htonl(frame->sender_ssrc);
|
||||
|
||||
/* RTCP Sender Info */
|
||||
frame->s_info.ntp_msw = htonl(frame->s_info.ntp_msw);
|
||||
frame->s_info.ntp_lsw = htonl(frame->s_info.ntp_lsw);
|
||||
frame->s_info.rtp_ts = htonl(frame->s_info.rtp_ts);
|
||||
frame->s_info.pkt_cnt = htonl(frame->s_info.pkt_cnt);
|
||||
frame->s_info.byte_cnt = htonl(frame->s_info.byte_cnt);
|
||||
|
||||
/* report block(s) */
|
||||
for (size_t i = 0; i < frame->header.count; ++i) {
|
||||
ssrcs.push_back(frame->blocks[i].ssrc);
|
||||
|
||||
frame->blocks[i].last_seq = htonl(frame->blocks[i].last_seq);
|
||||
frame->blocks[i].jitter = htonl(frame->blocks[i].jitter);
|
||||
frame->blocks[i].ssrc = htonl(frame->blocks[i].ssrc);
|
||||
frame->blocks[i].lost = htonl(frame->blocks[i].lost);
|
||||
frame->blocks[i].dlsr = htonl(frame->blocks[i].dlsr);
|
||||
frame->blocks[i].lsr = htonl(frame->blocks[i].lsr);
|
||||
}
|
||||
|
||||
for (auto& p : participants_) {
|
||||
if ((ret = p.second->socket->sendto(p.second->address, (uint8_t *)frame, len, 0)) != RTP_OK) {
|
||||
LOG_ERROR("sendto() failed!");
|
||||
}
|
||||
|
||||
update_rtcp_bandwidth(len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::rtcp::generate_sender_report()
|
||||
{
|
||||
/* No one to generate report for */
|
||||
if (num_receivers_ == 0)
|
||||
return RTP_NOT_READY;
|
||||
|
||||
uvg_rtp::frame::rtcp_sender_frame *frame;
|
||||
|
||||
if ((frame = uvg_rtp::frame::alloc_rtcp_sender_frame(senders_)) == nullptr) {
|
||||
LOG_ERROR("Failed to allocate RTCP Receiver Report frame!");
|
||||
return rtp_errno;
|
||||
}
|
||||
|
||||
size_t ptr = 0;
|
||||
uint64_t timestamp = uvg_rtp::clock::ntp::now();
|
||||
rtp_error_t ret = RTP_OK;
|
||||
|
||||
frame->header.count = senders_;
|
||||
frame->sender_ssrc = ssrc_;
|
||||
frame->s_info.ntp_msw = timestamp >> 32;
|
||||
frame->s_info.ntp_lsw = timestamp & 0xffffffff;
|
||||
frame->s_info.rtp_ts = rtp_ts_start_ + (uvg_rtp::clock::ntp::diff(timestamp, clock_start_)) * clock_rate_ / 1000;
|
||||
frame->s_info.pkt_cnt = sender_stats.sent_pkts;
|
||||
frame->s_info.byte_cnt = sender_stats.sent_bytes;
|
||||
|
||||
LOG_DEBUG("Sender Report from 0x%x has %zu blocks", ssrc_, senders_);
|
||||
|
||||
for (auto& participant : participants_) {
|
||||
if (!participant.second->sender)
|
||||
continue;
|
||||
|
||||
frame->blocks[ptr].ssrc = participant.first;
|
||||
|
||||
if (participant.second->stats.dropped_pkts != 0) {
|
||||
frame->blocks[ptr].fraction =
|
||||
participant.second->stats.received_pkts / participant.second->stats.dropped_pkts;
|
||||
}
|
||||
|
||||
frame->blocks[ptr].lost = participant.second->stats.dropped_pkts;
|
||||
frame->blocks[ptr].last_seq = participant.second->stats.max_seq;
|
||||
frame->blocks[ptr].jitter = participant.second->stats.jitter;
|
||||
frame->blocks[ptr].lsr = participant.second->stats.lsr;
|
||||
|
||||
ptr++;
|
||||
}
|
||||
|
||||
/* Send sender report only if the session contains other senders */
|
||||
if (ptr != 0)
|
||||
ret = uvg_rtp::rtcp::send_sender_report_packet(frame);
|
||||
|
||||
(void)uvg_rtp::frame::dealloc_frame(frame);
|
||||
|
||||
return ret;
|
||||
}
|
Loading…
Reference in New Issue