115 lines
3.1 KiB
C++
115 lines
3.1 KiB
C++
#ifdef _WIN32
|
|
#else
|
|
#endif
|
|
|
|
#include "rtcp.hh"
|
|
|
|
uvg_rtp::frame::rtcp_sdes_packet *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::install_sdes_hook(void (*hook)(uvg_rtp::frame::rtcp_sdes_packet *))
|
|
{
|
|
if (!hook)
|
|
return RTP_INVALID_VALUE;
|
|
|
|
sdes_hook_ = hook;
|
|
return RTP_OK;
|
|
}
|
|
|
|
rtp_error_t uvg_rtp::rtcp::handle_sdes_packet(uint8_t *packet, size_t size)
|
|
{
|
|
if (!packet || !size)
|
|
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;
|
|
}
|
|
|
|
for (int ptr = 8; ptr < frame->header.length; ) {
|
|
uvg_rtp::frame::rtcp_sdes_item item;
|
|
|
|
item.type = packet[ptr++];
|
|
item.length = packet[ptr++];
|
|
item.data = (void *)new uint8_t[item.length];
|
|
|
|
memcpy(item.data, &packet[ptr], item.length);
|
|
ptr += item.length;
|
|
}
|
|
|
|
if (sdes_hook_)
|
|
sdes_hook_(frame);
|
|
else
|
|
participants_[frame->ssrc]->sdes_frame = frame;
|
|
|
|
return RTP_OK;
|
|
}
|
|
|
|
rtp_error_t uvg_rtp::rtcp::send_sdes_packet(std::vector<uvg_rtp::frame::rtcp_sdes_item>& items)
|
|
{
|
|
if (items.empty()) {
|
|
LOG_ERROR("Cannot send an empty SDES packet!");
|
|
return RTP_INVALID_VALUE;
|
|
}
|
|
|
|
int ptr = 8;
|
|
uint8_t *frame;
|
|
rtp_error_t ret;
|
|
size_t frame_size;
|
|
|
|
frame_size = 4 + 4; /* rtcp header + ssrc */
|
|
frame_size += items.size() * 2; /* sdes item type + length */
|
|
|
|
for (auto& item : items)
|
|
frame_size += item.length;
|
|
|
|
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;
|
|
}
|