diff --git a/include/frame.hh b/include/frame.hh index 157573f..446034a 100644 --- a/include/frame.hh +++ b/include/frame.hh @@ -9,6 +9,7 @@ #endif #include +#include #include "util.hh" @@ -115,6 +116,12 @@ namespace uvg_rtp { struct rtcp_report_block blocks[1]; }; + struct rtcp_receiver_report { + struct rtcp_header header; + uint32_t ssrc; + std::vector report_blocks; + }; + PACKED_STRUCT(rtcp_receiver_frame) { struct rtcp_header header; uint32_t sender_ssrc; diff --git a/include/rtcp.hh b/include/rtcp.hh index 35001a7..9cf2583 100644 --- a/include/rtcp.hh +++ b/include/rtcp.hh @@ -64,10 +64,10 @@ namespace uvg_rtp { /* Save the latest RTCP packets received from this participant * Users can query these packets using the SSRC of participant */ - uvg_rtp::frame::rtcp_sender_frame *s_frame; - uvg_rtp::frame::rtcp_receiver_frame *r_frame; - uvg_rtp::frame::rtcp_sdes_frame *sdes_frame; - uvg_rtp::frame::rtcp_app_frame *app_frame; + uvg_rtp::frame::rtcp_sender_frame *s_frame; + uvg_rtp::frame::rtcp_receiver_report *r_frame; + uvg_rtp::frame::rtcp_sdes_frame *sdes_frame; + uvg_rtp::frame::rtcp_app_frame *app_frame; }; class rtcp : public runner { @@ -127,10 +127,10 @@ namespace uvg_rtp { * Return nullptr if we haven't received this kind of packet or if "ssrc" doesn't exist * * NOTE: Caller is responsible for deallocating the memory */ - uvg_rtp::frame::rtcp_sender_frame *get_sender_packet(uint32_t ssrc); - uvg_rtp::frame::rtcp_receiver_frame *get_receiver_packet(uint32_t ssrc); - uvg_rtp::frame::rtcp_sdes_frame *get_sdes_packet(uint32_t ssrc); - uvg_rtp::frame::rtcp_app_frame *get_app_packet(uint32_t ssrc); + uvg_rtp::frame::rtcp_sender_frame *get_sender_packet(uint32_t ssrc); + uvg_rtp::frame::rtcp_receiver_report *get_receiver_packet(uint32_t ssrc); + uvg_rtp::frame::rtcp_sdes_frame *get_sdes_packet(uint32_t ssrc); + uvg_rtp::frame::rtcp_app_frame *get_app_packet(uint32_t ssrc); /* create RTCP BYE packet using our own SSRC and send it to all participants */ rtp_error_t terminate_self(); @@ -189,7 +189,7 @@ namespace uvg_rtp { * polling an RTCP packet, user can install a function that is called when * a specific RTCP packet is received. */ rtp_error_t install_sender_hook(void (*hook)(uvg_rtp::frame::rtcp_sender_frame *)); - rtp_error_t install_receiver_hook(void (*hook)(uvg_rtp::frame::rtcp_receiver_frame *)); + rtp_error_t install_receiver_hook(void (*hook)(uvg_rtp::frame::rtcp_receiver_report *)); rtp_error_t install_sdes_hook(void (*hook)(uvg_rtp::frame::rtcp_sdes_frame *)); rtp_error_t install_app_hook(void (*hook)(uvg_rtp::frame::rtcp_app_frame *)); @@ -324,7 +324,7 @@ namespace uvg_rtp { std::vector sockets_; void (*sender_hook_)(uvg_rtp::frame::rtcp_sender_frame *); - void (*receiver_hook_)(uvg_rtp::frame::rtcp_receiver_frame *); + void (*receiver_hook_)(uvg_rtp::frame::rtcp_receiver_report *); void (*sdes_hook_)(uvg_rtp::frame::rtcp_sdes_frame *); void (*app_hook_)(uvg_rtp::frame::rtcp_app_frame *); }; diff --git a/src/rtcp/receiver.cc b/src/rtcp/receiver.cc index f96c133..4b9543e 100644 --- a/src/rtcp/receiver.cc +++ b/src/rtcp/receiver.cc @@ -6,7 +6,7 @@ #define SET_NEXT_FIELD_32(a, p, v) do { *(uint32_t *)&(a)[p] = (v); ptr += 4; } while (0) -uvg_rtp::frame::rtcp_receiver_frame *uvg_rtp::rtcp::get_receiver_packet(uint32_t ssrc) +uvg_rtp::frame::rtcp_receiver_report *uvg_rtp::rtcp::get_receiver_packet(uint32_t ssrc) { if (participants_.find(ssrc) == participants_.end()) return nullptr; @@ -17,7 +17,7 @@ uvg_rtp::frame::rtcp_receiver_frame *uvg_rtp::rtcp::get_receiver_packet(uint32_t return frame; } -rtp_error_t uvg_rtp::rtcp::install_receiver_hook(void (*hook)(uvg_rtp::frame::rtcp_receiver_frame *)) +rtp_error_t uvg_rtp::rtcp::install_receiver_hook(void (*hook)(uvg_rtp::frame::rtcp_receiver_report *)) { if (!hook) return RTP_INVALID_VALUE; @@ -31,53 +31,50 @@ rtp_error_t uvg_rtp::rtcp::handle_receiver_report_packet(uint8_t *packet, size_t if (!packet || !size) return RTP_INVALID_VALUE; - frame->header.length = ntohs(frame->header.length); - frame->sender_ssrc = ntohl(frame->sender_ssrc); + auto frame = new uvg_rtp::frame::rtcp_receiver_report; + + frame->header.version = (packet[0] >> 6) & 0x3f; + frame->header.padding = (packet[0] >> 5) & 0x1; + frame->header.count = packet[0] & 0x1f; + frame->header.length = ntohs(*(uint16_t *)&packet[2]); + frame->ssrc = ntohl(*(uint32_t *)&packet[4]); /* 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 (!is_participant(frame->ssrc)) { + LOG_WARN("Got a Receiver Report from an unknown participant"); + add_participant(frame->ssrc); } - if (frame->header.count == 0) { + if (!frame->header.count) { 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); + /* Deallocate previous frame from the buffer if it exists, it's going to get overwritten */ + if (participants_[frame->ssrc]->r_frame) + delete participants_[frame->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(frame->blocks[i].lost); - cpy_frame->blocks[i].last_seq = ntohl(frame->blocks[i].last_seq); - cpy_frame->blocks[i].jitter = ntohl(frame->blocks[i].jitter); - cpy_frame->blocks[i].lsr = ntohl(frame->blocks[i].lsr); - cpy_frame->blocks[i].dlsr = ntohl(frame->blocks[i].dlsr); + uvg_rtp::frame::rtcp_report_block report; - 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"); + report.ssrc = ntohl(*(uint32_t *)&packet[(i * 24) + 8 + 0]); + report.lost = ntohl(*(uint32_t *)&packet[(i * 24) + 8 + 4]); + report.last_seq = ntohl(*(uint32_t *)&packet[(i * 24) + 8 + 8]); + report.jitter = ntohl(*(uint32_t *)&packet[(i * 24) + 8 + 12]); + report.lsr = ntohl(*(uint32_t *)&packet[(i * 24) + 8 + 16]); + report.dlsr = ntohl(*(uint32_t *)&packet[(i * 24) + 8 + 20]); + + frame->report_blocks.push_back(report); } if (receiver_hook_) - receiver_hook_(cpy_frame); + receiver_hook_(frame); else - participants_[frame->sender_ssrc]->r_frame = cpy_frame; + participants_[frame->ssrc]->r_frame = frame; return RTP_OK; }