Create Runner class

Several classes have common active_ and runner_ variables and
stop/start/active routines (such as reader and dispatch).

Create one common class for these to make the interface cleaner
This commit is contained in:
Aaro Altonen 2019-10-24 08:36:54 +03:00
parent bde19e3f7f
commit 0f0a052e54
10 changed files with 366 additions and 347 deletions

View File

@ -50,7 +50,7 @@ kvz_rtp::connection::connection(rtp_format_t fmt, bool reader):
kvz_rtp::connection::~connection()
{
if (rtcp_) {
rtcp_->terminate();
rtcp_->stop();
delete rtcp_;
}

View File

@ -14,6 +14,7 @@
#include "frame.hh"
#include "rtcp.hh"
#include "runner.hh"
#include "socket.hh"
#include "util.hh"
@ -22,104 +23,102 @@ namespace kvz_rtp {
class dispatcher;
class frame_queue;
class connection {
public:
connection(rtp_format_t fmt, bool reader);
virtual ~connection();
class connection : public runner {
public:
connection(rtp_format_t fmt, bool reader);
virtual ~connection();
virtual rtp_error_t start() = 0;
uint16_t get_sequence() const;
uint32_t get_ssrc() const;
uint8_t get_payload() const;
uint16_t get_sequence() const;
uint32_t get_ssrc() const;
uint8_t get_payload() const;
socket& get_socket();
socket_t get_raw_socket();
socket& get_socket();
socket_t get_raw_socket();
void set_payload(rtp_format_t fmt);
void set_ssrc(uint32_t ssrc);
void set_payload(rtp_format_t fmt);
void set_ssrc(uint32_t ssrc);
/* Functions for increasing various RTP statistics
* Overloaded functions without parameters increase the counter by 1
*
* Functions that take SSRC are for updating receiver statistics */
void inc_rtp_sequence(size_t n);
void inc_sent_bytes(size_t n);
void inc_sent_pkts(size_t n);
void inc_sent_pkts();
void inc_rtp_sequence();
/* Functions for increasing various RTP statistics
* Overloaded functions without parameters increase the counter by 1
*
* Functions that take SSRC are for updating receiver statistics */
void inc_rtp_sequence(size_t n);
void inc_sent_bytes(size_t n);
void inc_sent_pkts(size_t n);
void inc_sent_pkts();
void inc_rtp_sequence();
/* See RTCP->update_receiver_stats() for documentation */
rtp_error_t update_receiver_stats(kvz_rtp::frame::rtp_frame *frame);
/* See RTCP->update_receiver_stats() for documentation */
rtp_error_t update_receiver_stats(kvz_rtp::frame::rtp_frame *frame);
/* Config setters and getter, used f.ex. for Opus
*
* Return nullptr if the media doesn't have a config
* Otherwise return void pointer to config (caller must do the cast) */
void set_config(void *config);
void *get_config();
/* Config setters and getter, used f.ex. for Opus
*
* Return nullptr if the media doesn't have a config
* Otherwise return void pointer to config (caller must do the cast) */
void set_config(void *config);
void *get_config();
/* helper function fill the rtp header to allocated buffer,
* caller must make sure that the buffer is at least 12 bytes long */
void fill_rtp_header(uint8_t *buffer);
/* helper function fill the rtp header to allocated buffer,
* caller must make sure that the buffer is at least 12 bytes long */
void fill_rtp_header(uint8_t *buffer);
void update_rtp_sequence(uint8_t *buffer);
void update_rtp_sequence(uint8_t *buffer);
/* Set clock rate for RTP timestamp in Hz
* This must be set, otherwise the timestamps won't be correct */
void set_clock_rate(uint32_t clock_rate);
/* Set clock rate for RTP timestamp in Hz
* This must be set, otherwise the timestamps won't be correct */
void set_clock_rate(uint32_t clock_rate);
/* 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);
/* 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);
/* Get pointer to frame queue
*
* Return pointer to frame queue for writers
* Return nullptr for readers */
kvz_rtp::frame_queue *get_frame_queue();
/* Get pointer to frame queue
*
* Return pointer to frame queue for writers
* Return nullptr for readers */
kvz_rtp::frame_queue *get_frame_queue();
/* Get pointer to dispatcher
*
* Return pointer to dispatcher for medias that use dispatcher
* Return nullptr otherwise */
kvz_rtp::dispatcher *get_dispatcher();
/* Get pointer to dispatcher
*
* Return pointer to dispatcher for medias that use dispatcher
* Return nullptr otherwise */
kvz_rtp::dispatcher *get_dispatcher();
/* Install deallocation hook for the transaction's data payload
*
* When SCD has finished processing the request,
* in deinit_transaction(), it will calls this hook if it has been set. */
void install_dealloc_hook(void (*dealloc_hook)(void *));
/* Install deallocation hook for the transaction's data payload
*
* When SCD has finished processing the request,
* in deinit_transaction(), it will calls this hook if it has been set. */
void install_dealloc_hook(void (*dealloc_hook)(void *));
/* Return pointer to RTCP object if RTCP has been enabled
* Otherwise return nullptr
*
* TODO make this const */
kvz_rtp::rtcp *get_rtcp();
/* Return pointer to RTCP object if RTCP has been enabled
* Otherwise return nullptr
*
* TODO make this const */
kvz_rtp::rtcp *get_rtcp();
protected:
void *config_;
uint32_t id_;
protected:
void *config_;
uint32_t id_;
kvz_rtp::socket socket_;
kvz_rtp::rtcp *rtcp_;
kvz_rtp::socket socket_;
kvz_rtp::rtcp *rtcp_;
private:
bool reader_;
private:
bool reader_;
/* RTP */
uint16_t rtp_sequence_;
uint8_t rtp_payload_;
uint32_t rtp_ssrc_;
uint32_t rtp_timestamp_;
uint64_t wc_start_;
kvz_rtp::clock::hrc::hrc_t wc_start_2;
uint32_t clock_rate_;
/* RTP */
uint16_t rtp_sequence_;
uint8_t rtp_payload_;
uint32_t rtp_ssrc_;
uint32_t rtp_timestamp_;
uint64_t wc_start_;
kvz_rtp::clock::hrc::hrc_t wc_start_2;
uint32_t clock_rate_;
kvz_rtp::frame_queue *fqueue_;
kvz_rtp::frame_queue *fqueue_;
kvz_rtp::dispatcher *dispatcher_;
kvz_rtp::dispatcher *dispatcher_;
};
};

View File

@ -12,6 +12,7 @@ kvz_rtp::dispatcher::dispatcher(kvz_rtp::socket *socket):
kvz_rtp::dispatcher::~dispatcher()
{
delete runner_;
runner_ = nullptr;
}
rtp_error_t kvz_rtp::dispatcher::start()
@ -30,11 +31,6 @@ rtp_error_t kvz_rtp::dispatcher::stop()
return RTP_OK;
}
bool kvz_rtp::dispatcher::active()
{
return active_;
}
std::condition_variable& kvz_rtp::dispatcher::get_cvar()
{
return cv_;

View File

@ -6,6 +6,7 @@
#include "queue.hh"
#include "socket.hh"
#include "runner.hh"
#include "util.hh"
namespace kvz_rtp {
@ -30,15 +31,11 @@ namespace kvz_rtp {
* experiences to very small (<50 us even for large frames [>170 kB]) */
typedef struct transaction transaction_t;
class dispatcher {
class dispatcher : public runner {
public:
dispatcher(kvz_rtp::socket *socket);
~dispatcher();
rtp_error_t start();
rtp_error_t stop();
bool active();
/* Add new transaction to dispatcher's task queue
* The task queue is emptied in FIFO style */
rtp_error_t trigger_send(kvz_rtp::transaction_t *transaction);
@ -62,9 +59,6 @@ namespace kvz_rtp {
std::mutex q_mtx_;
std::queue<kvz_rtp::transaction_t *> tasks_;
bool active_;
std::thread *runner_;
kvz_rtp::socket *socket_;
};
};

View File

@ -12,7 +12,6 @@
kvz_rtp::reader::reader(rtp_format_t fmt, std::string src_addr, int src_port):
connection(fmt, true),
active_(false),
src_addr_(src_addr),
src_port_(src_port),
recv_hook_arg_(nullptr),
@ -106,11 +105,6 @@ kvz_rtp::frame::rtp_frame *kvz_rtp::reader::pull_frame()
return nextFrame;
}
bool kvz_rtp::reader::active()
{
return active_;
}
uint8_t *kvz_rtp::reader::get_recv_buffer() const
{
return recv_buffer_;

View File

@ -16,11 +16,13 @@ namespace kvz_rtp {
/* NOTE: this operation is blocking */
kvz_rtp::frame::rtp_frame *pull_frame();
// open socket and start runner_
/* Open socket, start frame receiver and RTCP
*
* Return RTP_OK on success
* Return RTP_MEMORY_ERROR if memory deallocation failed
* Return RTP_GENERIC_ERROR for any other error */
rtp_error_t start();
bool active();
bool recv_hook_installed();
void recv_hook(kvz_rtp::frame::rtp_frame *frame);
void install_recv_hook(void *arg, void (*hook)(void *arg, kvz_rtp::frame::rtp_frame *));
@ -44,15 +46,11 @@ namespace kvz_rtp {
void return_frame(kvz_rtp::frame::rtp_frame *frame);
private:
// TODO implement ring buffer
bool active_;
// connection-related stuff
std::string src_addr_;
int src_port_;
// receiver thread related stuff
std::thread *runner_;
/* receiver thread related stuff */
uint8_t *recv_buffer_; /* buffer for incoming packet (MAX_PACKET) */
uint32_t recv_buffer_len_; /* buffer length */

View File

@ -23,7 +23,7 @@ kvz_rtp::rtcp::rtcp(uint32_t ssrc, bool receiver):
tp_(0), tc_(0), tn_(0), pmembers_(0),
members_(0), senders_(0), rtcp_bandwidth_(0),
we_sent_(0), avg_rtcp_pkt_pize_(0), rtcp_pkt_count_(0),
initial_(true), active_(false), num_receivers_(0)
initial_(true), num_receivers_(0)
{
ssrc_ = ssrc;
@ -136,7 +136,7 @@ rtp_error_t kvz_rtp::rtcp::start()
return RTP_OK;
}
rtp_error_t kvz_rtp::rtcp::terminate()
rtp_error_t kvz_rtp::rtcp::stop()
{
if (runner_ == nullptr)
goto free_mem;
@ -170,11 +170,6 @@ free_mem:
return RTP_OK;
}
bool kvz_rtp::rtcp::active() const
{
return active_;
}
bool kvz_rtp::rtcp::receiver() const
{
return receiver_;

View File

@ -7,6 +7,7 @@
#include "clock.hh"
#include "frame.hh"
#include "runner.hh"
#include "socket.hh"
#include "util.hh"
@ -21,290 +22,280 @@ namespace kvz_rtp {
const int MAX_MISORDER = 100;
const int MIN_TIMEOUT = 5000;
class rtcp {
public:
rtcp(uint32_t ssrc, bool receiver);
~rtcp();
class rtcp : public runner {
public:
rtcp(uint32_t ssrc, 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();
/* 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();
/* End the RTCP session and send RTCP BYE to all participants
*
* return RTP_OK on success */
rtp_error_t stop();
/* 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;
/* 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();
/* 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
*
* These routines will convert the fields of "frame" from network to host byte order
*
* Currently nothing's done with valid packets, at some point an API for
* querying these reports is implemented
*
* Return RTP_OK on success and RTP_ERROR on error */
rtp_error_t handle_sender_report_packet(kvz_rtp::frame::rtcp_sender_frame *frame, size_t size);
rtp_error_t handle_receiver_report_packet(kvz_rtp::frame::rtcp_receiver_frame *frame, size_t size);
rtp_error_t handle_sdes_packet(kvz_rtp::frame::rtcp_sdes_frame *frame, size_t size);
rtp_error_t handle_bye_packet(kvz_rtp::frame::rtcp_bye_frame *frame, size_t size);
rtp_error_t handle_app_packet(kvz_rtp::frame::rtcp_app_frame *frame, size_t size);
/* Handle different kinds of incoming packets
*
* These routines will convert the fields of "frame" from network to host byte order
*
* Currently nothing's done with valid packets, at some point an API for
* querying these reports is implemented
*
* Return RTP_OK on success and RTP_ERROR on error */
rtp_error_t handle_sender_report_packet(kvz_rtp::frame::rtcp_sender_frame *frame, size_t size);
rtp_error_t handle_receiver_report_packet(kvz_rtp::frame::rtcp_receiver_frame *frame, size_t size);
rtp_error_t handle_sdes_packet(kvz_rtp::frame::rtcp_sdes_frame *frame, size_t size);
rtp_error_t handle_bye_packet(kvz_rtp::frame::rtcp_bye_frame *frame, size_t size);
rtp_error_t handle_app_packet(kvz_rtp::frame::rtcp_app_frame *frame, size_t size);
/* 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);
/* 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);
/* Send "frame" to all participants
*
* These routines will convert all necessary fields to network byte order
*
* 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(kvz_rtp::frame::rtcp_sender_frame *frame);
rtp_error_t send_receiver_report_packet(kvz_rtp::frame::rtcp_receiver_frame *frame);
rtp_error_t send_sdes_packet(kvz_rtp::frame::rtcp_sdes_frame *frame);
rtp_error_t send_bye_packet(kvz_rtp::frame::rtcp_bye_frame *frame);
rtp_error_t send_app_packet(kvz_rtp::frame::rtcp_app_frame *frame);
/* Send "frame" to all participants
*
* These routines will convert all necessary fields to network byte order
*
* 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(kvz_rtp::frame::rtcp_sender_frame *frame);
rtp_error_t send_receiver_report_packet(kvz_rtp::frame::rtcp_receiver_frame *frame);
rtp_error_t send_sdes_packet(kvz_rtp::frame::rtcp_sdes_frame *frame);
rtp_error_t send_bye_packet(kvz_rtp::frame::rtcp_bye_frame *frame);
rtp_error_t send_app_packet(kvz_rtp::frame::rtcp_app_frame *frame);
/* Return the latest RTCP packet received from participant of "ssrc"
* 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 */
kvz_rtp::frame::rtcp_sender_frame *get_sender_packet(uint32_t ssrc);
kvz_rtp::frame::rtcp_receiver_frame *get_receiver_packet(uint32_t ssrc);
kvz_rtp::frame::rtcp_sdes_frame *get_sdes_packet(uint32_t ssrc);
kvz_rtp::frame::rtcp_app_frame *get_app_packet(uint32_t ssrc);
/* Return the latest RTCP packet received from participant of "ssrc"
* 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 */
kvz_rtp::frame::rtcp_sender_frame *get_sender_packet(uint32_t ssrc);
kvz_rtp::frame::rtcp_receiver_frame *get_receiver_packet(uint32_t ssrc);
kvz_rtp::frame::rtcp_sdes_frame *get_sdes_packet(uint32_t ssrc);
kvz_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();
/* create RTCP BYE packet using our own SSRC and send it to all participants */
rtp_error_t terminate_self();
/* TODO: */
std::vector<kvz_rtp::socket>& get_sockets();
/* TODO: */
std::vector<kvz_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
*
* "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,
* (or whether we're even sending anything)
*
* Return RTP_OK on success and RTP_ERROR on error */
rtp_error_t add_participant(std::string dst_addr, int dst_port, int src_port, uint32_t clock_rate);
/* 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
*
* "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,
* (or whether we're even sending anything)
*
* Return RTP_OK on success and RTP_ERROR on error */
rtp_error_t add_participant(std::string dst_addr, int dst_port, int src_port, uint32_t clock_rate);
/* Functions for updating various RTP sender statistics */
void sender_inc_seq_cycle_count();
void sender_inc_sent_pkts(size_t n);
void sender_inc_sent_bytes(size_t n);
void sender_update_stats(kvz_rtp::frame::rtp_frame *frame);
/* Functions for updating various RTP sender statistics */
void sender_inc_seq_cycle_count();
void sender_inc_sent_pkts(size_t n);
void sender_inc_sent_bytes(size_t n);
void sender_update_stats(kvz_rtp::frame::rtp_frame *frame);
void receiver_inc_sent_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_sent_pkts(uint32_t sender_ssrc, size_t n);
void receiver_inc_sent_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_sent_pkts(uint32_t sender_ssrc, size_t n);
/* Update the RTCP statistics regarding this packet
*
* Return RTP_OK if packet is valid
* Return RTP_INVALID_VALUE if SSRCs of remotes have collided or the packet is invalid in some way
* return RTP_SSRC_COLLISION if our own SSRC has collided and we need to reinitialize it */
rtp_error_t receiver_update_stats(kvz_rtp::frame::rtp_frame *frame);
/* Update the RTCP statistics regarding this packet
*
* Return RTP_OK if packet is valid
* Return RTP_INVALID_VALUE if SSRCs of remotes have collided or the packet is invalid in some way
* return RTP_SSRC_COLLISION if our own SSRC has collided and we need to reinitialize it */
rtp_error_t receiver_update_stats(kvz_rtp::frame::rtp_frame *frame);
/* If we've detected that our SSRC has collided with someone else's SSRC, we need to
* generate new random SSRC and reinitialize our own RTCP state.
* RTCP object still has the participants of "last session", we can use their SSRCs
* to detected new collision
*
* Return RTP_OK if reinitialization succeeded
* Return RTP_SSRC_COLLISION if our new SSRC has collided and we need to generate new SSRC */
rtp_error_t reset_rtcp_state(uint32_t ssrc);
/* If we've detected that our SSRC has collided with someone else's SSRC, we need to
* generate new random SSRC and reinitialize our own RTCP state.
* RTCP object still has the participants of "last session", we can use their SSRCs
* to detected new collision
*
* Return RTP_OK if reinitialization succeeded
* Return RTP_SSRC_COLLISION if our new SSRC has collided and we need to generate new SSRC */
rtp_error_t reset_rtcp_state(uint32_t ssrc);
/* Set wallclock reading for t = 0 and random RTP timestamp from where the counting is started
* + clock rate for calculating the correct increment */
void set_sender_ts_info(uint64_t clock_start, uint32_t clock_rate, uint32_t rtp_ts_start);
/* Set wallclock reading for t = 0 and random RTP timestamp from where the counting is started
* + clock rate for calculating the correct increment */
void set_sender_ts_info(uint64_t clock_start, uint32_t clock_rate, uint32_t rtp_ts_start);
/* Return SSRCs of all participants */
std::vector<uint32_t> get_participants();
/* Return SSRCs of all participants */
std::vector<uint32_t> get_participants();
/* TODO: */
rtp_error_t install_sender_hook(void (*hook)(kvz_rtp::frame::rtcp_sender_frame *));
rtp_error_t install_receiver_hook(void (*hook)(kvz_rtp::frame::rtcp_receiver_frame *));
rtp_error_t install_sdes_hook(void (*hook)(kvz_rtp::frame::rtcp_sdes_frame *));
rtp_error_t install_app_hook(void (*hook)(kvz_rtp::frame::rtcp_app_frame *));
/* TODO: */
rtp_error_t install_sender_hook(void (*hook)(kvz_rtp::frame::rtcp_sender_frame *));
rtp_error_t install_receiver_hook(void (*hook)(kvz_rtp::frame::rtcp_receiver_frame *));
rtp_error_t install_sdes_hook(void (*hook)(kvz_rtp::frame::rtcp_sdes_frame *));
rtp_error_t install_app_hook(void (*hook)(kvz_rtp::frame::rtcp_app_frame *));
private:
static void rtcp_runner(rtcp *rtcp);
private:
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
* from this sender and if not, create new entry to receiver_stats_ map */
bool is_participant(uint32_t ssrc);
/* 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 */
bool is_participant(uint32_t ssrc);
/* When we receive an RTP or RTCP packet, we need to check the source address and see if it's
* the same address where we've received packets before.
*
* If the address is new, it means we have detected an SSRC collision and the paket should
* be dropped We also need to check whether this SSRC matches with our own SSRC and if it does
* we need to send RTCP BYE and rejoin to the session */
bool collision_detected(uint32_t ssrc, sockaddr_in& src_addr);
/* When we receive an RTP or RTCP packet, we need to check the source address and see if it's
* the same address where we've received packets before.
*
* If the address is new, it means we have detected an SSRC collision and the paket should
* be dropped We also need to check whether this SSRC matches with our own SSRC and if it does
* we need to send RTCP BYE and rejoin to the session */
bool collision_detected(uint32_t ssrc, sockaddr_in& src_addr);
/* Move participant from initial_peers_ to participants_ */
void add_participant(uint32_t ssrc);
/* Move participant from initial_peers_ to participants_ */
void add_participant(uint32_t ssrc);
/* We've got a message from new source (the SSRC of the frame is not known to us)
* Initialize statistics for the peer and move it to participants_ */
void init_new_participant(kvz_rtp::frame::rtp_frame *frame);
/* We've got a message from new source (the SSRC of the frame is not known to us)
* Initialize statistics for the peer and move it to participants_ */
void init_new_participant(kvz_rtp::frame::rtp_frame *frame);
/* Initialize the RTP Sequence related stuff of peer
* This function assumes that the peer already exists in the participants_ map */
void init_participant_seq(uint32_t ssrc, uint16_t base_seq);
/* Initialize the RTP Sequence related stuff of peer
* This function assumes that the peer already exists in the participants_ map */
void init_participant_seq(uint32_t ssrc, uint16_t base_seq);
/* Update the SSRC's sequence related data in participants_ map
*
* Return RTP_OK if the received packet was OK
* Return RTP_GENERIC_ERROR if it wasn't and
* packet-related statistics should not be updated */
rtp_error_t update_participant_seq(uint32_t ssrc, uint16_t seq);
/* Update the SSRC's sequence related data in participants_ map
*
* Return RTP_OK if the received packet was OK
* Return RTP_GENERIC_ERROR if it wasn't and
* packet-related statistics should not be updated */
rtp_error_t update_participant_seq(uint32_t ssrc, uint16_t seq);
/* Update the RTCP bandwidth variables
*
* "pkt_size" tells how much rtcp_byte_count_
* should be increased before calculating the new average */
void update_rtcp_bandwidth(size_t pkt_size);
/* Update the RTCP bandwidth variables
*
* "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
*
* Return RTP_OK on success and RTP_ERROR on error */
rtp_error_t generate_sender_report();
rtp_error_t generate_receiver_report();
/* 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_;
bool receiver_;
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 */
/* 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_;
/* 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_;
/* 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_;
/* 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_;
/* Number of RTCP packets and bytes sent and received by this participant */
size_t rtcp_pkt_count_;
size_t rtcp_byte_count_;
/* Number of RTCP packets and bytes sent and received by this participant */
size_t rtcp_pkt_count_;
size_t rtcp_byte_count_;
/* Flag that is true if the application has not yet sent an RTCP packet. */
bool initial_;
/* 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_;
/* Copy of our own current SSRC */
uint32_t ssrc_;
/* Copy of our own current SSRC */
uint32_t ssrc_;
/* NTP timestamp associated with initial RTP timestamp (aka t = 0) */
uint64_t clock_start_;
/* NTP timestamp associated with initial RTP timestamp (aka t = 0) */
uint64_t clock_start_;
/* Clock rate of the media ie. how fast does the time increase */
uint32_t clock_rate_;
/* Clock rate of the media ie. how fast does the time increase */
uint32_t clock_rate_;
/* The first value of RTP timestamp (aka t = 0) */
uint32_t rtp_ts_start_;
/* The first value of RTP timestamp (aka t = 0) */
uint32_t rtp_ts_start_;
struct statistics {
/* receiver stats */
uint32_t received_pkts; /* Number of packets received */
uint32_t dropped_pkts; /* Number of dropped RTP packets */
uint32_t received_bytes; /* Number of bytes received excluding RTP Header */
struct statistics {
/* receiver stats */
uint32_t received_pkts; /* Number of packets received */
uint32_t dropped_pkts; /* Number of dropped RTP packets */
uint32_t received_bytes; /* Number of bytes received excluding RTP Header */
/* sender stats */
uint32_t sent_pkts; /* Number of sent RTP packets */
uint32_t sent_bytes; /* Number of sent bytes excluding RTP Header */
/* sender stats */
uint32_t sent_pkts; /* Number of sent RTP packets */
uint32_t sent_bytes; /* Number of sent bytes excluding RTP Header */
uint32_t jitter; /* TODO: */
uint32_t transit; /* TODO: */
uint32_t jitter; /* TODO: */
uint32_t transit; /* TODO: */
/* Receiver clock related stuff */
uint64_t initial_ntp; /* Wallclock reading when the first RTP packet was received */
uint32_t initial_rtp; /* RTP timestamp of the first RTP packet received */
uint32_t clock_rate; /* Rate of the clock (used for jitter calculations) */
/* Receiver clock related stuff */
uint64_t initial_ntp; /* Wallclock reading when the first RTP packet was received */
uint32_t initial_rtp; /* RTP timestamp of the first RTP packet received */
uint32_t clock_rate; /* Rate of the clock (used for jitter calculations) */
uint32_t lsr; /* Middle 32 bits of the 64-bit NTP timestamp of previous SR */
kvz_rtp::clock::hrc::hrc_t sr_ts; /* When the last SR was received (used to calculate delay) */
uint32_t lsr; /* Middle 32 bits of the 64-bit NTP timestamp of previous SR */
kvz_rtp::clock::hrc::hrc_t sr_ts; /* When the last SR was received (used to calculate delay) */
uint16_t max_seq; /* Highest sequence number received */
uint16_t base_seq; /* First sequence number received */
uint16_t bad_seq; /* TODO: */
uint16_t cycles; /* Number of sequence cycles */
};
uint16_t max_seq; /* Highest sequence number received */
uint16_t base_seq; /* First sequence number received */
uint16_t bad_seq; /* TODO: */
uint16_t cycles; /* Number of sequence cycles */
};
struct participant {
kvz_rtp::socket *socket; /* socket associated with this participant */
sockaddr_in address; /* address of the participant */
struct statistics stats; /* RTCP session statistics of the participant */
struct participant {
kvz_rtp::socket *socket; /* socket associated with this participant */
sockaddr_in address; /* address of the participant */
struct statistics stats; /* RTCP session statistics of the participant */
int probation; /* TODO: */
bool sender; /* Sender will create report block for other sender only */
int probation; /* TODO: */
bool sender; /* Sender will create report block for other sender only */
/* Save the latest RTCP packets received from this participant
* Users can query these packets using the SSRC of participant */
kvz_rtp::frame::rtcp_sender_frame *s_frame;
kvz_rtp::frame::rtcp_receiver_frame *r_frame;
kvz_rtp::frame::rtcp_sdes_frame *sdes_frame;
kvz_rtp::frame::rtcp_app_frame *app_frame;
};
/* Save the latest RTCP packets received from this participant
* Users can query these packets using the SSRC of participant */
kvz_rtp::frame::rtcp_sender_frame *s_frame;
kvz_rtp::frame::rtcp_receiver_frame *r_frame;
kvz_rtp::frame::rtcp_sdes_frame *sdes_frame;
kvz_rtp::frame::rtcp_app_frame *app_frame;
};
std::map<uint32_t, struct participant *> participants_;
size_t num_receivers_;
std::map<uint32_t, struct participant *> participants_;
size_t num_receivers_;
/* statistics for RTCP Sender and Receiver Reports */
struct statistics sender_stats;
/* statistics for RTCP Sender and Receiver Reports */
struct statistics sender_stats;
/* TODO: */
std::vector<struct participant *> initial_participants_;
/* TODO: */
std::vector<struct participant *> initial_participants_;
/* Vector of sockets the RTCP runner is listening to
*
* The socket are also stored here (in addition to participants_ map) so they're easier
* to pass to poll when RTCP runner is listening to incoming packets */
std::vector<kvz_rtp::socket> sockets_;
/* Vector of sockets the RTCP runner is listening to
*
* The socket are also stored here (in addition to participants_ map) so they're easier
* to pass to poll when RTCP runner is listening to incoming packets */
std::vector<kvz_rtp::socket> sockets_;
void (*sender_hook_)(kvz_rtp::frame::rtcp_sender_frame *);
void (*receiver_hook_)(kvz_rtp::frame::rtcp_receiver_frame *);
void (*sdes_hook_)(kvz_rtp::frame::rtcp_sdes_frame *);
void (*app_hook_)(kvz_rtp::frame::rtcp_app_frame *);
void (*sender_hook_)(kvz_rtp::frame::rtcp_sender_frame *);
void (*receiver_hook_)(kvz_rtp::frame::rtcp_receiver_frame *);
void (*sdes_hook_)(kvz_rtp::frame::rtcp_sdes_frame *);
void (*app_hook_)(kvz_rtp::frame::rtcp_app_frame *);
};
};

30
src/runner.cc Normal file
View File

@ -0,0 +1,30 @@
#include "runner.hh"
kvz_rtp::runner::runner():
active_(false), runner_(nullptr)
{
}
kvz_rtp::runner::~runner()
{
active_ = false;
if (runner_)
delete runner_;
}
rtp_error_t kvz_rtp::runner::start()
{
active_ = true;
}
rtp_error_t kvz_rtp::runner::stop()
{
active_ = false;
active_ = false;
}
bool kvz_rtp::runner::active()
{
return active_;
}

22
src/runner.hh Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include <thread>
#include "util.hh"
namespace kvz_rtp {
class runner {
public:
runner();
virtual ~runner();
virtual rtp_error_t start();
virtual rtp_error_t stop();
virtual bool active();
protected:
bool active_;
std::thread *runner_;
};
};