Add initial implementation of RTCP

Currently the timing of RTCP packets is not accurate and
Sender/Receiver Reports contain non-canonical information.

Support for SDES/APP/BYE packets is missing

Support for actually using the RTCP information (ie. an API for the user) is missing
This commit is contained in:
Aaro Altonen 2019-06-17 12:23:30 +03:00
parent 9970af92c9
commit 788a9f84cd
8 changed files with 660 additions and 23 deletions

View File

@ -24,6 +24,10 @@ kvz_rtp::connection::connection(bool reader):
kvz_rtp::connection::~connection()
{
if (rtcp_) {
rtcp_->terminate();
delete rtcp_;
}
}
void kvz_rtp::connection::set_payload(rtp_format_t fmt)
@ -76,34 +80,59 @@ void kvz_rtp::connection::inc_rtp_sequence(size_t n)
rtp_sequence_ += n;
}
void kvz_rtp::connection::inc_rtp_sequence()
{
rtp_sequence_++;
}
void kvz_rtp::connection::inc_processed_bytes(size_t n)
{
processed_bytes_ += n;
rtcp_->sender_inc_processed_bytes(n);
}
void kvz_rtp::connection::inc_overhead_bytes(size_t n)
{
overhead_bytes_ += n;
rtcp_->sender_inc_overhead_bytes(n);
}
void kvz_rtp::connection::inc_total_bytes(size_t n)
{
total_bytes_ += n;
rtcp_->sender_inc_total_bytes(n);
}
void kvz_rtp::connection::inc_processed_pkts(size_t n)
{
processed_pkts_ += n;
rtcp_->sender_inc_processed_pkts(n);
}
void kvz_rtp::connection::inc_processed_pkts()
{
processed_pkts_++;
rtcp_->sender_inc_processed_pkts(1);
}
void kvz_rtp::connection::inc_rtp_sequence()
void kvz_rtp::connection::inc_processed_bytes(uint32_t ssrc, size_t n)
{
rtp_sequence_++;
rtcp_->receiver_inc_processed_bytes(ssrc, n);
}
void kvz_rtp::connection::inc_overhead_bytes(uint32_t ssrc, size_t n)
{
rtcp_->receiver_inc_overhead_bytes(ssrc, n);
}
void kvz_rtp::connection::inc_total_bytes(uint32_t ssrc, size_t n)
{
rtcp_->receiver_inc_total_bytes(ssrc, n);
}
void kvz_rtp::connection::inc_processed_pkts(uint32_t ssrc, size_t n)
{
rtcp_->receiver_inc_processed_pkts(ssrc, n);
}
void kvz_rtp::connection::inc_processed_pkts(uint32_t ssrc)
{
rtcp_->receiver_inc_processed_pkts(ssrc, 1);
}
void kvz_rtp::connection::fill_rtp_header(uint8_t *buffer, uint32_t timestamp)
@ -118,3 +147,13 @@ void kvz_rtp::connection::fill_rtp_header(uint8_t *buffer, uint32_t timestamp)
*(uint32_t *)&buffer[4] = htonl(timestamp);
*(uint32_t *)&buffer[8] = htonl(rtp_ssrc_);
}
rtp_error_t kvz_rtp::connection::create_rtcp(std::string dst_addr, int dst_port, int src_port)
{
if ((rtcp_ = new kvz_rtp::rtcp(dst_addr, dst_port, src_port, reader_)) == nullptr) {
LOG_ERROR("Failed to allocate RTCP instance!");
return RTP_MEMORY_ERROR;
}
return rtcp_->start();
}

View File

@ -13,12 +13,12 @@
#include <vector>
#include "frame.hh"
#include "rtcp.hh"
#include "socket.hh"
#include "util.hh"
namespace kvz_rtp {
class connection {
public:
connection(bool reader);
virtual ~connection();
@ -35,18 +35,26 @@ namespace kvz_rtp {
void set_payload(rtp_format_t fmt);
void set_ssrc(uint32_t ssrc);
/* functions for increasing various RTP statistics
/* Functions for increasing various RTP statistics
* Overloaded functions without parameters increase the counter by 1
*
* overloaded functions without parameters increase the counter by 1*/
* Functions that take SSRC are for updating receiver statistics
*
* TODO: jitter! */
void inc_rtp_sequence(size_t n);
void inc_processed_bytes(size_t n);
void inc_overhead_bytes(size_t n);
void inc_total_bytes(size_t n);
void inc_processed_pkts(size_t n);
void inc_processed_pkts();
void inc_rtp_sequence();
void inc_processed_bytes(uint32_t ssrc, size_t n);
void inc_overhead_bytes(uint32_t ssrc, size_t n);
void inc_total_bytes(uint32_t ssrc, size_t n);
void inc_processed_pkts(uint32_t ssrc, size_t n);
void inc_processed_pkts(uint32_t ssrc);
/* config set and get */
void set_config(void *config);
void *get_config();
@ -55,11 +63,20 @@ namespace kvz_rtp {
* caller must make sure that the buffer is at least 12 bytes long */
void fill_rtp_header(uint8_t *buffer, uint32_t timestamp);
/* Create RTCP instance for this connection
*
* This instance listens to src_port for incoming RTCP reports and sends
* repots about this session to dst_addr:dst_port every N seconds (see RFC 3550) */
rtp_error_t create_rtcp(std::string dst_addr, int dst_port, int src_port);
rtp_error_t add_rtcp_participant(kvz_rtp::connection *conn);
protected:
void *config_;
uint32_t id_;
kvz_rtp::socket socket_;
kvz_rtp::rtcp *rtcp_;
private:
bool reader_;
@ -68,12 +85,5 @@ namespace kvz_rtp {
uint16_t rtp_sequence_;
uint8_t rtp_payload_;
uint32_t rtp_ssrc_;
/* statistics for RTCP reports */
size_t processed_bytes_;
size_t overhead_bytes_;
size_t total_bytes_;
size_t processed_pkts_;
size_t dropped_pkts_;
};
};

View File

@ -57,9 +57,9 @@ namespace kvz_rtp {
PACKED_STRUCT(rtcp_sender_info) {
uint32_t ntp_msw;
uint32_t ntp_lsw;
uint32_t rtp_timestamp;
uint32_t pkt_count;
uint32_t byte_count;
uint32_t rtp_ts;
uint32_t pkt_cnt;
uint32_t byte_cnt;
};
PACKED_STRUCT(rtcp_report_block) {

View File

@ -105,7 +105,6 @@ rtp_error_t kvz_rtp::context::destroy_writer(kvz_rtp::writer *writer)
{
conns_.erase(writer->get_ssrc());
/* TODO: rtcp bye */
delete writer;
return RTP_OK;
}
@ -114,7 +113,6 @@ rtp_error_t kvz_rtp::context::destroy_reader(kvz_rtp::reader *reader)
{
conns_.erase(reader->get_ssrc());
/* TODO: rtcp bye */
delete reader;
return RTP_OK;
}

View File

@ -166,6 +166,11 @@ void kvz_rtp::reader::frame_receiver(kvz_rtp::reader *reader)
frame->payload_len = nread - kvz_rtp::frame::HEADER_SIZE_RTP;
frame->total_len = nread;
reader->inc_processed_bytes(frame->ssrc, frame->total_len);
reader->inc_overhead_bytes(frame->ssrc, kvz_rtp::frame::HEADER_SIZE_RTP); /* TODO: this is not accurate! */
reader->inc_total_bytes(frame->ssrc, frame->total_len);
reader->inc_processed_pkts(frame->ssrc, 1);
if (!frame->data) {
LOG_ERROR("Failed to allocate buffer for RTP frame!");
continue;

421
src/rtcp.cc Normal file
View File

@ -0,0 +1,421 @@
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/time.h>
#endif
#include <iostream>
#include "debug.hh"
#include "rtcp.hh"
#include "util.hh"
kvz_rtp::rtcp::rtcp():
tp_(0), tc_(0), tn_(0), pmembers_(0),
members_(0), senders_(0), rtcp_bandwidth_(0),
we_sent_(0), avg_rtcp_pkt_pize_(0), initial_(true),
active_(false), send_addr_(""), send_port_(0), recv_port_(0),
socket_(), num_receivers_(0)
{
cname_ = "hello"; //generate_cname();
}
kvz_rtp::rtcp::rtcp(std::string dst_addr, int dst_port, bool receiver):
rtcp()
{
send_addr_ = dst_addr;
send_port_ = dst_port;
receiver_ = receiver;
}
kvz_rtp::rtcp::rtcp(std::string dst_addr, int dst_port, int src_port, bool receiver):
rtcp(dst_addr, dst_port, receiver)
{
recv_port_ = src_port;
}
kvz_rtp::rtcp::~rtcp()
{
}
rtp_error_t kvz_rtp::rtcp::start()
{
if (send_addr_ == "" || send_port_ == 0) {
LOG_ERROR("Invalid values given (%s, %d), cannot create RTCP instance", send_addr_.c_str(), send_port_);
return RTP_INVALID_VALUE;
}
rtp_error_t ret;
if ((ret = socket_.init(AF_INET, SOCK_DGRAM, 0)) != RTP_OK)
return ret;
/* if the receive port was given, this RTCP instance
* is expecting status reports to that port and should bind the socket to it */
if (recv_port_ != 0) {
int enable = 1;
if ((ret = socket_.setsockopt(SOL_SOCKET, SO_REUSEADDR, (const char *)&enable, sizeof(int))) != RTP_OK)
return ret;
/* Set read timeout (5s for now)
*
* TODO: this doesn't btw work...
*
* This means that the socket is listened for 5s at a time and after the timeout,
* Send Report is sent to all participants */
struct timeval tv;
tv.tv_sec = 3;
tv.tv_usec = 0;
if ((ret = socket_.setsockopt(SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))) != RTP_OK)
return ret;
LOG_DEBUG("Binding to port %d (source port)", recv_port_);
if ((ret = socket_.bind(AF_INET, INADDR_ANY, recv_port_)) != RTP_OK)
return ret;
}
socket_.set_sockaddr(socket_.create_sockaddr(AF_INET, send_addr_, send_port_));
active_ = true;
if ((runner_ = new std::thread(rtcp_runner, this)) == nullptr) {
active_ = false;
LOG_ERROR("Failed to create RTCP thread!");
return RTP_MEMORY_ERROR;
}
runner_->detach();
return RTP_OK;
}
rtp_error_t kvz_rtp::rtcp::terminate()
{
/* when the member count is less than 50,
* we can just send the BYE message and destroy the session */
if (members_ < 50) {
active_ = false;
goto end;
}
tp_ = tc_;
members_ = 1;
pmembers_ = 1;
initial_ = true;
we_sent_ = false;
senders_ = 0;
active_ = false;
end:
/* free all receiver statistic structs */
for (auto& i : receiver_stats_) {
delete i.second;
}
return RTP_OK;
}
bool kvz_rtp::rtcp::active() const
{
return active_;
}
bool kvz_rtp::rtcp::receiver() const
{
return receiver_;
}
kvz_rtp::socket& kvz_rtp::rtcp::get_socket()
{
return socket_;
}
void kvz_rtp::rtcp::sender_inc_processed_bytes(size_t n)
{
sender_stats_.processed_bytes += n;
}
void kvz_rtp::rtcp::sender_inc_overhead_bytes(size_t n)
{
sender_stats_.overhead_bytes += n;
}
void kvz_rtp::rtcp::sender_inc_total_bytes(size_t n)
{
sender_stats_.total_bytes += n;
}
void kvz_rtp::rtcp::sender_inc_processed_pkts(size_t n)
{
sender_stats_.processed_pkts += n;
}
void kvz_rtp::rtcp::check_sender(uint32_t ssrc)
{
if (receiver_stats_.find(ssrc) == receiver_stats_.end()) {
LOG_INFO("First RTP packet from 0x%x", ssrc);
receiver_stats_[ssrc] = new struct statistics;
num_receivers_++;
}
}
void kvz_rtp::rtcp::receiver_inc_processed_bytes(uint32_t sender_ssrc, size_t n)
{
check_sender(sender_ssrc);
receiver_stats_[sender_ssrc]->processed_bytes += n;
}
void kvz_rtp::rtcp::receiver_inc_overhead_bytes(uint32_t sender_ssrc, size_t n)
{
check_sender(sender_ssrc);
receiver_stats_[sender_ssrc]->overhead_bytes += n;
}
void kvz_rtp::rtcp::receiver_inc_total_bytes(uint32_t sender_ssrc, size_t n)
{
check_sender(sender_ssrc);
receiver_stats_[sender_ssrc]->total_bytes += n;
}
void kvz_rtp::rtcp::receiver_inc_processed_pkts(uint32_t sender_ssrc, size_t n)
{
check_sender(sender_ssrc);
receiver_stats_[sender_ssrc]->processed_pkts += n;
}
rtp_error_t kvz_rtp::rtcp::generate_sender_report()
{
return RTP_OK;
LOG_INFO("Generating sender report...");
kvz_rtp::frame::rtcp_sender_frame *frame;
if ((frame = kvz_rtp::frame::alloc_rtcp_sender_frame(num_receivers_)) == nullptr) {
LOG_ERROR("Failed to allocate RTCP Receiver Report frame!");
return rtp_errno;
}
size_t ptr = 0;
rtp_error_t ret = RTP_OK;
uint64_t timestamp = tv_to_ntp();
frame->s_info.ntp_msw = timestamp >> 32;
frame->s_info.ntp_lsw = timestamp & 0xffffffff;
frame->s_info.rtp_ts = 3; /* TODO: what timestamp is this? */
frame->s_info.pkt_cnt = sender_stats_.processed_pkts;
frame->s_info.byte_cnt = sender_stats_.processed_bytes;
for (auto& receiver : receiver_stats_) {
frame->blocks[ptr].ssrc = receiver.first;
if (receiver.second->dropped_pkts) {
frame->blocks[ptr].fraction_lost =
receiver.second->processed_pkts / receiver.second->dropped_pkts;
}
frame->blocks[ptr].cumulative_pkt_lost = receiver.second->dropped_pkts;
frame->blocks[ptr].highest_seq_recved = 222; // TODO ???
frame->blocks[ptr].interraival_jitter = 333; // TODO ???
frame->blocks[ptr].delay_since_last_sr = 555; // TODO ???
frame->blocks[ptr].last_sr = 444; // TODO ???
ptr++;
}
ret = socket_.sendto((uint8_t *)frame, frame->header.length, 0, NULL);
kvz_rtp::frame::dealloc_frame(frame);
return ret;
}
rtp_error_t kvz_rtp::rtcp::generate_receiver_report()
{
LOG_INFO("Generating receiver report...");
kvz_rtp::frame::rtcp_receiver_frame *frame;
if ((frame = kvz_rtp::frame::alloc_rtcp_receiver_frame(num_receivers_)) == nullptr) {
LOG_ERROR("Failed to allocate RTCP Receiver Report frame!");
return rtp_errno;
}
rtp_error_t ret = RTP_OK;
size_t ptr = 0;
for (auto& receiver : receiver_stats_) {
frame->blocks[ptr].ssrc = receiver.first;
if (receiver.second->dropped_pkts) {
frame->blocks[ptr].fraction_lost =
receiver.second->processed_pkts / receiver.second->dropped_pkts;
}
frame->blocks[ptr].cumulative_pkt_lost = receiver.second->dropped_pkts;
frame->blocks[ptr].highest_seq_recved = 222; // TODO ???
frame->blocks[ptr].interraival_jitter = 333; // TODO ???
frame->blocks[ptr].delay_since_last_sr = 555; // TODO ???
frame->blocks[ptr].last_sr = 444; // TODO ???
ptr++;
}
ret = socket_.sendto((uint8_t *)frame, frame->header.length, 0, NULL);
kvz_rtp::frame::dealloc_frame(frame);
return ret;
}
rtp_error_t kvz_rtp::rtcp::generate_report()
{
if (receiver_)
return generate_receiver_report();
return generate_sender_report();
}
rtp_error_t kvz_rtp::rtcp::handle_sender_packet(kvz_rtp::frame::rtcp_sender_frame *report)
{
if (!report)
return RTP_INVALID_VALUE;
if (report->header.report_cnt == 0) {
LOG_ERROR("Receiver report cannot have 0 report blocks!");
return RTP_INVALID_VALUE;
}
/* TODO: what are we supposed to with this report? */
return RTP_OK;
}
rtp_error_t kvz_rtp::rtcp::handle_receiver_packet(kvz_rtp::frame::rtcp_receiver_frame *report)
{
if (!report)
return RTP_INVALID_VALUE;
if (report->header.report_cnt == 0) {
LOG_ERROR("Receiver report cannot have 0 report blocks!");
return RTP_INVALID_VALUE;
}
/* TODO: what are we supposed to with this report? */
return RTP_OK;
}
rtp_error_t kvz_rtp::rtcp::handle_sdes_packet(kvz_rtp::frame::rtcp_sdes_frame *sdes)
{
(void)sdes;
return RTP_OK;
}
rtp_error_t kvz_rtp::rtcp::handle_bye_packet(kvz_rtp::frame::rtcp_bye_frame *bye)
{
(void)bye;
return RTP_OK;
}
rtp_error_t kvz_rtp::rtcp::handle_app_packet(kvz_rtp::frame::rtcp_app_frame *app)
{
(void)app;
return RTP_OK;
}
rtp_error_t kvz_rtp::rtcp::handle_incoming_packet(uint8_t *buffer, size_t size)
{
kvz_rtp::frame::rtcp_header *header = (kvz_rtp::frame::rtcp_header *)buffer;
if (header->version != 2) {
LOG_ERROR("Invalid header version (%u)", header->version);
return RTP_INVALID_VALUE;
}
if (header->padding != 0) {
LOG_ERROR("Cannot handle padded packets!");
return RTP_INVALID_VALUE;
}
if (header->pkt_type > kvz_rtp::frame::FRAME_TYPE_BYE ||
header->pkt_type < kvz_rtp::frame::FRAME_TYPE_SR) {
LOG_ERROR("Invalid packet type (%u)!", header->pkt_type);
return RTP_INVALID_VALUE;
}
rtp_error_t ret;
switch (header->pkt_type) {
case kvz_rtp::frame::FRAME_TYPE_SR:
ret = handle_sender_packet((kvz_rtp::frame::rtcp_sender_frame *)buffer);
break;
case kvz_rtp::frame::FRAME_TYPE_RR:
ret = handle_receiver_packet((kvz_rtp::frame::rtcp_receiver_frame *)buffer);
break;
case kvz_rtp::frame::FRAME_TYPE_SDES:
/* ret = handle_sender_packet((kvz_rtp::frame::rtcp_sender_frame *)buffer); */
break;
case kvz_rtp::frame::FRAME_TYPE_BYE:
/* ret = handle_sender_packet((kvz_rtp::frame::rtcp_sender_frame *)buffer); */
break;
case kvz_rtp::frame::FRAME_TYPE_APP:
/* ret = handle_app_packet((kvz_rtp::frame::rtcp_sender_frame *)buffer); */
break;
}
return ret;
}
void kvz_rtp::rtcp::rtcp_runner(kvz_rtp::rtcp *rtcp)
{
LOG_INFO("RTCP instance created!");
int nread;
uint8_t buffer[MAX_PACKET];
kvz_rtp::socket socket = rtcp->get_socket();
rtp_error_t ret;
while (rtcp->active()) {
ret = socket.recvfrom(buffer, MAX_PACKET, 0, &nread);
if (ret == RTP_OK && nread > 0) {
(void)rtcp->handle_incoming_packet(buffer, (size_t)nread);
} else if (ret == RTP_INTERRUPTED) {
/* do nothing */
} else {
LOG_ERROR("recvfrom failed, %d", ret);
}
if ((ret = rtcp->generate_report()) != RTP_OK) {
LOG_ERROR("Failed to send RTCP status report!");
}
}
/* TODO: send bye */
}
uint64_t kvz_rtp::rtcp::tv_to_ntp()
{
static const uint64_t EPOCH = 2208988800ULL;
static const uint64_t NTP_SCALE_FRAC = 4294967296ULL;
static struct timeval tv;
gettimeofday(&tv, NULL);
uint64_t tv_ntp, tv_usecs;
tv_ntp = tv.tv_sec + EPOCH;
tv_usecs = (NTP_SCALE_FRAC * tv.tv_usec) / 1000000UL;
return (tv_ntp << 32) | tv_usecs;
}

161
src/rtcp.hh Normal file
View File

@ -0,0 +1,161 @@
#pragma once
#include <map>
#include <thread>
#include <vector>
#include "frame.hh"
#include "socket.hh"
#include "util.hh"
namespace kvz_rtp {
class connection;
class rtcp {
public:
rtcp();
rtcp(std::string dst_addr, int dst_port, bool receiver);
rtcp(std::string dst_addr, int dst_port, int src_port, bool receiver);
~rtcp();
/* start the RTCP runner thread
*
* return RTP_OK on success and RTP_MEMORY_ERROR if the allocation fails */
rtp_error_t start();
/* End the RTCP session and send RTCP BYE to all participants
*
* return RTP_OK on success */
rtp_error_t terminate();
/* return true if the connection is still considered active
* and RTCP transmissions should continue */
bool active() const;
/* 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
* Return RTP_OK on success and RTP_ERROR on error */
rtp_error_t generate_report();
/* Handle different kinds of incoming packets
*
* Currently nothing's done with valid packets, at some point an API for
* querying these repots is implemented
*
* Return RTP_OK on success and RTP_ERROR on error */
rtp_error_t handle_sender_packet(kvz_rtp::frame::rtcp_sender_frame *sender_report);
rtp_error_t handle_receiver_packet(kvz_rtp::frame::rtcp_receiver_frame *receiver_report);
rtp_error_t handle_sdes_packet(kvz_rtp::frame::rtcp_sdes_frame *sdes);
rtp_error_t handle_bye_packet(kvz_rtp::frame::rtcp_bye_frame *bye);
rtp_error_t handle_app_packet(kvz_rtp::frame::rtcp_app_frame *app);
/* Handle incoming RTCP packet (first make sure it's a valid RTCP packet)
* This function will call one of the above functions internally
*
* Return RTP_OK on success and RTP_ERROR on error */
rtp_error_t handle_incoming_packet(uint8_t *buffer, size_t size);
/* Return reference to kvz_rtp::socket of the RTCP instance
* Used by the rtcp_runner to listen to incoming */
kvz_rtp::socket& get_socket();
/* 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
*
* Return RTP_OK on success and RTP_ERROR on error */
rtp_error_t add_participant(kvz_rtp::connection *conn);
/* Functions for updating various RTP sender statistics */
void sender_inc_processed_bytes(size_t n);
void sender_inc_overhead_bytes(size_t n);
void sender_inc_total_bytes(size_t n);
void sender_inc_processed_pkts(size_t n);
void receiver_inc_processed_bytes(uint32_t sender_ssrc, size_t n);
void receiver_inc_overhead_bytes(uint32_t sender_ssrc, size_t n);
void receiver_inc_total_bytes(uint32_t sender_ssrc, size_t n);
void receiver_inc_processed_pkts(uint32_t sender_ssrc, size_t n);
private:
static void rtcp_runner(rtcp *rtcp);
/* convert struct timeval format to NTP format */
uint64_t tv_to_ntp();
/* 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
* from this sender and if not, create new entry to receiver_stats_ map */
void check_sender(uint32_t ssrc);
/* 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();
rtp_error_t generate_receiver_report();
std::thread *runner_;
std::string cname_;
bool receiver_;
/* TODO: time_t?? */
size_t tp_; /* the last time an RTCP packet was transmitted */
size_t tc_; /* the current time */
size_t tn_; /* the next scheduled transmission time of an RTCP packet */
size_t pmembers_; /* the estimated number of session members at the time tn was last recomputed */
size_t members_; /* the most current estimate for the number of session members */
size_t senders_; /* the most current estimate for the number of senders in the session */
/* The target RTCP bandwidth, i.e., the total bandwidth
* that will be used for RTCP packets by all members of this session,
* in octets per second. This will be a specified fraction of the
* "session bandwidth" parameter supplied to the application at startup. */
size_t rtcp_bandwidth_;
/* Flag that is true if the application has sent data since
* the 2nd previous RTCP report was transmitted. */
bool we_sent_;
/* The average compound RTCP packet size, in octets,
* over all RTCP packets sent and received by this participant. The
* size includes lower-layer transport and network protocol headers
* (e.g., UDP and IP) as explained in Section 6.2 */
size_t avg_rtcp_pkt_pize_;
/* Flag that is true if the application has not yet sent an RTCP packet. */
bool initial_;
/* Flag that is true if the connection is still considered open.
* When clients decided to leave, he calls rtcp->terminate()
* which stops the rtcp runner and RTCP BYE message to all participants */
bool active_;
/* send_addr_:send_port_ is used for sending reports to remote
* recv_port_ is used for receiving reports */
std::string send_addr_;
int send_port_;
int recv_port_;
kvz_rtp::socket socket_;
/* TODO: is there any use for this?? */
std::vector<kvz_rtp::connection *> participant_;
struct statistics {
size_t processed_bytes;
size_t overhead_bytes;
size_t total_bytes;
size_t processed_pkts;
size_t dropped_pkts;
};
/* statistics for RTCP Sender and Receiver Reports */
struct statistics sender_stats_;
std::map<uint32_t, struct statistics *> receiver_stats_;
size_t num_receivers_;
};
};

View File

@ -139,6 +139,9 @@ rtp_error_t kvz_rtp::socket::recvfrom(uint8_t *buf, size_t buf_len, int flags, i
::recvfrom(socket_, buf, buf_len, flags, (struct sockaddr *)&from_addr, (socklen_t *)&from_addr_size);
if (ret == -1) {
if (errno == EAGAIN)
return RTP_INTERRUPTED;
LOG_ERROR("recvfrom failed: %s", strerror(errno));
return RTP_GENERIC_ERROR;
}