Fix RTCP SDES generation/reception code
Operate on a raw block of memory, extract interesting fields from the packet and create user-friendly struct for the SDES packet that can be queried using SSRC Caller must remember to free the memory occupied by the SDES items
This commit is contained in:
parent
29f959d6ad
commit
2807ccc83b
|
@ -138,13 +138,13 @@ namespace uvg_rtp {
|
|||
PACKED_STRUCT(rtcp_sdes_item) {
|
||||
uint8_t type;
|
||||
uint8_t length;
|
||||
uint8_t data[1];
|
||||
void *data;
|
||||
};
|
||||
|
||||
PACKED_STRUCT(rtcp_sdes_frame) {
|
||||
struct rtcp_sdes_packet {
|
||||
struct rtcp_header header;
|
||||
uint32_t sender_ssrc;
|
||||
struct rtcp_sdes_item items[1];
|
||||
uint32_t ssrc;
|
||||
std::vector<rtcp_sdes_item> items;
|
||||
};
|
||||
|
||||
PACKED_STRUCT(rtcp_bye_frame) {
|
||||
|
|
|
@ -66,7 +66,7 @@ namespace uvg_rtp {
|
|||
* Users can query these packets using the SSRC of participant */
|
||||
uvg_rtp::frame::rtcp_sender_report *s_frame;
|
||||
uvg_rtp::frame::rtcp_receiver_report *r_frame;
|
||||
uvg_rtp::frame::rtcp_sdes_frame *sdes_frame;
|
||||
uvg_rtp::frame::rtcp_sdes_packet *sdes_frame;
|
||||
uvg_rtp::frame::rtcp_app_frame *app_frame;
|
||||
};
|
||||
|
||||
|
@ -117,9 +117,7 @@ namespace uvg_rtp {
|
|||
* Return RTP_OK on success
|
||||
* Return RTP_INVALID_VALUE if "frame" is in some way invalid
|
||||
* Return RTP_SEND_ERROR if sending "frame" did not succeed (see socket.hh for details) */
|
||||
rtp_error_t send_sender_report_packet(uvg_rtp::frame::rtcp_sender_frame *frame);
|
||||
rtp_error_t send_receiver_report_packet(uvg_rtp::frame::rtcp_receiver_frame *frame);
|
||||
rtp_error_t send_sdes_packet(uvg_rtp::frame::rtcp_sdes_frame *frame);
|
||||
rtp_error_t send_sdes_packet(std::vector<uvg_rtp::frame::rtcp_sdes_item>& items);
|
||||
rtp_error_t send_bye_packet(uvg_rtp::frame::rtcp_bye_frame *frame);
|
||||
rtp_error_t send_app_packet(uvg_rtp::frame::rtcp_app_frame *frame);
|
||||
|
||||
|
@ -129,7 +127,7 @@ namespace uvg_rtp {
|
|||
* NOTE: Caller is responsible for deallocating the memory */
|
||||
uvg_rtp::frame::rtcp_sender_report *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_sdes_packet *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 */
|
||||
|
@ -190,7 +188,7 @@ namespace uvg_rtp {
|
|||
* a specific RTCP packet is received. */
|
||||
rtp_error_t install_sender_hook(void (*hook)(uvg_rtp::frame::rtcp_sender_report *));
|
||||
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_sdes_hook(void (*hook)(uvg_rtp::frame::rtcp_sdes_packet *));
|
||||
rtp_error_t install_app_hook(void (*hook)(uvg_rtp::frame::rtcp_app_frame *));
|
||||
|
||||
/* Update RTCP-related sender statistics */
|
||||
|
@ -325,7 +323,7 @@ namespace uvg_rtp {
|
|||
|
||||
void (*sender_hook_)(uvg_rtp::frame::rtcp_sender_report *);
|
||||
void (*receiver_hook_)(uvg_rtp::frame::rtcp_receiver_report *);
|
||||
void (*sdes_hook_)(uvg_rtp::frame::rtcp_sdes_frame *);
|
||||
void (*sdes_hook_)(uvg_rtp::frame::rtcp_sdes_packet *);
|
||||
void (*app_hook_)(uvg_rtp::frame::rtcp_app_frame *);
|
||||
};
|
||||
};
|
||||
|
|
104
src/rtcp/sdes.cc
104
src/rtcp/sdes.cc
|
@ -4,7 +4,7 @@
|
|||
|
||||
#include "rtcp.hh"
|
||||
|
||||
uvg_rtp::frame::rtcp_sdes_frame *uvg_rtp::rtcp::get_sdes_packet(uint32_t ssrc)
|
||||
uvg_rtp::frame::rtcp_sdes_packet *uvg_rtp::rtcp::get_sdes_packet(uint32_t ssrc)
|
||||
{
|
||||
if (participants_.find(ssrc) == participants_.end())
|
||||
return nullptr;
|
||||
|
@ -15,7 +15,7 @@ uvg_rtp::frame::rtcp_sdes_frame *uvg_rtp::rtcp::get_sdes_packet(uint32_t ssrc)
|
|||
return frame;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::rtcp::install_sdes_hook(void (*hook)(uvg_rtp::frame::rtcp_sdes_frame *))
|
||||
rtp_error_t uvg_rtp::rtcp::install_sdes_hook(void (*hook)(uvg_rtp::frame::rtcp_sdes_packet *))
|
||||
{
|
||||
if (!hook)
|
||||
return RTP_INVALID_VALUE;
|
||||
|
@ -24,67 +24,91 @@ rtp_error_t uvg_rtp::rtcp::install_sdes_hook(void (*hook)(uvg_rtp::frame::rtcp_s
|
|||
return RTP_OK;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::rtcp::handle_sdes_packet(uint8_t *frame, size_t size)
|
||||
rtp_error_t uvg_rtp::rtcp::handle_sdes_packet(uint8_t *packet, size_t size)
|
||||
{
|
||||
#if 0
|
||||
if (!frame)
|
||||
if (!packet || !size)
|
||||
return RTP_INVALID_VALUE;
|
||||
|
||||
if (frame->header.count == 0) {
|
||||
LOG_ERROR("SDES packet cannot contain 0 fields!");
|
||||
return RTP_INVALID_VALUE;
|
||||
auto frame = new uvg_rtp::frame::rtcp_sdes_packet;
|
||||
|
||||
frame->header.version = (packet[0] >> 6) & 0x3;
|
||||
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]);
|
||||
|
||||
/* Deallocate previous frame from the buffer if it exists, it's going to get overwritten */
|
||||
if (participants_[frame->ssrc]->sdes_frame) {
|
||||
for (auto& item : participants_[frame->ssrc]->sdes_frame->items)
|
||||
delete[] (uint8_t *)item.data;
|
||||
delete participants_[frame->ssrc]->sdes_frame;
|
||||
}
|
||||
|
||||
frame->sender_ssrc = ntohl(frame->sender_ssrc);
|
||||
for (int ptr = 8; ptr < frame->header.length; ) {
|
||||
uvg_rtp::frame::rtcp_sdes_item item;
|
||||
|
||||
/* 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);
|
||||
item.type = packet[ptr++];
|
||||
item.length = packet[ptr++];
|
||||
item.data = (void *)new uint8_t[item.length];
|
||||
|
||||
uint8_t *cpy_frame = new uint8_t[size];
|
||||
memcpy(cpy_frame, frame, size);
|
||||
memcpy(item.data, &packet[ptr], item.length);
|
||||
ptr += item.length;
|
||||
}
|
||||
|
||||
if (sdes_hook_)
|
||||
sdes_hook_((uvg_rtp::frame::rtcp_sdes_frame *)cpy_frame);
|
||||
sdes_hook_(frame);
|
||||
else
|
||||
participants_[frame->sender_ssrc]->sdes_frame = (uvg_rtp::frame::rtcp_sdes_frame *)cpy_frame;
|
||||
#endif
|
||||
participants_[frame->ssrc]->sdes_frame = frame;
|
||||
|
||||
return RTP_OK;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::rtcp::send_sdes_packet(uvg_rtp::frame::rtcp_sdes_frame *frame)
|
||||
rtp_error_t uvg_rtp::rtcp::send_sdes_packet(std::vector<uvg_rtp::frame::rtcp_sdes_item>& items)
|
||||
{
|
||||
if (!frame)
|
||||
if (items.empty()) {
|
||||
LOG_ERROR("Cannot send an empty SDES packet!");
|
||||
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);
|
||||
}
|
||||
|
||||
int ptr = 8;
|
||||
uint8_t *frame;
|
||||
rtp_error_t ret;
|
||||
size_t frame_size;
|
||||
|
||||
for (auto& participant : participants_) {
|
||||
auto p = participant.second;
|
||||
frame_size = 4 + 4; /* rtcp header + ssrc */
|
||||
frame_size += items.size() * 2; /* sdes item type + length */
|
||||
|
||||
if ((ret = p->socket->sendto(p->address, (uint8_t *)frame, len, 0)) != RTP_OK) {
|
||||
LOG_ERROR("sendto() failed!");
|
||||
return ret;
|
||||
}
|
||||
for (auto& item : items)
|
||||
frame_size += item.length;
|
||||
|
||||
update_rtcp_bandwidth(len);
|
||||
if (!(frame = new uint8_t[frame_size])) {
|
||||
LOG_ERROR("Failed to allocate space for RTCP Receiver Report");
|
||||
return RTP_MEMORY_ERROR;
|
||||
}
|
||||
memset(frame, 0, frame_size);
|
||||
|
||||
frame[0] = (2 << 6) | (0 << 5) | num_receivers_;
|
||||
frame[1] = uvg_rtp::frame::RTCP_FT_SDES;
|
||||
|
||||
*(uint16_t *)&frame[2] = htons(frame_size);
|
||||
*(uint32_t *)&frame[4] = htonl(ssrc_);
|
||||
|
||||
for (auto& item : items) {
|
||||
frame[ptr++] = item.type;
|
||||
frame[ptr++] = item.length;
|
||||
memcpy(frame + ptr, item.data, item.length);
|
||||
ptr += item.length;
|
||||
}
|
||||
|
||||
for (auto& p : participants_) {
|
||||
if ((ret = p.second->socket->sendto(p.second->address, frame, frame_size, 0)) != RTP_OK) {
|
||||
LOG_ERROR("sendto() failed!");
|
||||
goto end;
|
||||
}
|
||||
update_rtcp_bandwidth(frame_size);
|
||||
}
|
||||
|
||||
end:
|
||||
delete[] frame;
|
||||
return ret;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue