From c1d31790d4f597b30612c372497753c6388cba1d Mon Sep 17 00:00:00 2001 From: dijunkun Date: Tue, 12 Sep 2023 17:30:08 +0800 Subject: [PATCH] Implementation for rtcp sender report --- src/rtcp/rtcp_header.cpp | 20 +++ src/rtcp/rtcp_header.h | 58 +++++++++ src/rtcp/rtcp_packet.h | 171 +------------------------- src/rtcp/rtcp_receiver_report.cpp | 5 + src/rtcp/rtcp_receiver_report.h | 52 ++++++++ src/rtcp/rtcp_report_block.cpp | 5 + src/rtcp/rtcp_report_block.h | 53 ++++++++ src/rtcp/rtcp_sender_report.cpp | 52 ++++++++ src/rtcp/rtcp_sender_report.h | 88 +++++++++++++ src/rtp/rtp_packet.h | 36 +++--- src/rtp/rtp_video_receiver.cpp | 4 + src/rtp/rtp_video_sender.cpp | 89 +++++++++++++- src/rtp/rtp_video_sender.h | 19 ++- src/transmission/ice_transmission.cpp | 10 +- xmake.lua | 12 +- 15 files changed, 470 insertions(+), 204 deletions(-) create mode 100644 src/rtcp/rtcp_header.cpp create mode 100644 src/rtcp/rtcp_header.h create mode 100644 src/rtcp/rtcp_receiver_report.cpp create mode 100644 src/rtcp/rtcp_receiver_report.h create mode 100644 src/rtcp/rtcp_report_block.cpp create mode 100644 src/rtcp/rtcp_report_block.h create mode 100644 src/rtcp/rtcp_sender_report.cpp create mode 100644 src/rtcp/rtcp_sender_report.h diff --git a/src/rtcp/rtcp_header.cpp b/src/rtcp/rtcp_header.cpp new file mode 100644 index 0000000..002dd1b --- /dev/null +++ b/src/rtcp/rtcp_header.cpp @@ -0,0 +1,20 @@ +#include "rtcp_header.h" + +RtcpHeader::RtcpHeader() + : version_(0), padding_(0), count_or_format_(0), length_(0) {} + +RtcpHeader::~RtcpHeader() {} + +int RtcpHeader::Encode(uint8_t version, uint8_t padding, + uint8_t count_or_format, uint8_t payload_type, + uint16_t length, uint8_t* buffer) { + if (!buffer) { + return 0; + } + + buffer[0] = (version << 6) | (padding << 5) | (count_or_format << 4); + buffer[1] = payload_type; + buffer[2] = length >> 8 & 0xFF; + buffer[3] = length & 0xFF; + return 4; +} \ No newline at end of file diff --git a/src/rtcp/rtcp_header.h b/src/rtcp/rtcp_header.h new file mode 100644 index 0000000..2b0cd3f --- /dev/null +++ b/src/rtcp/rtcp_header.h @@ -0,0 +1,58 @@ +#ifndef _RTCP_HEADER_H_ +#define _RTCP_HEADER_H_ + +#include + +// RTCP header +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |V=2|P| RC | PT=SR=200 | length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +#define DEFAULT_RTCP_VERSION 2 +#define DEFAULT_RTCP_HEADER_SIZE 4 + +class RtcpHeader { + public: + typedef enum { + UNKNOWN = 0, + SR = 200, + RR = 201, + SDES = 202, + BYE = 203, + APP = 204 + } PAYLOAD_TYPE; + + public: + RtcpHeader(); + ~RtcpHeader(); + + public: + void SetVerion(uint8_t version) { version_ = version; } + void SetPadding(uint8_t padding) { padding_ = padding; } + void SetCountOrFormat(uint8_t count_or_format) { + count_or_format_ = count_or_format; + } + void SetPayloadType(uint8_t payload_type) { payload_type_ = payload_type; } + void SetLength(uint16_t length) { length_ = length; } + + public: + uint8_t Verion() const { return version_; } + uint8_t Padding() const { return padding_; } + uint8_t CountOrFormat() const { return count_or_format_; } + PAYLOAD_TYPE PayloadType() const { return PAYLOAD_TYPE(payload_type_); } + uint16_t Length() const { return length_; } + + int Encode(uint8_t version, uint8_t padding, uint8_t count_or_format, + uint8_t payload_type, uint16_t length, uint8_t* buffer); + + private: + uint8_t version_ : 2; + uint8_t padding_ : 1; + uint8_t count_or_format_ : 5; + uint8_t payload_type_ : 8; + uint16_t length_ : 16; +}; + +#endif \ No newline at end of file diff --git a/src/rtcp/rtcp_packet.h b/src/rtcp/rtcp_packet.h index 2399cdd..8db0d03 100644 --- a/src/rtcp/rtcp_packet.h +++ b/src/rtcp/rtcp_packet.h @@ -1,74 +1,6 @@ #ifndef _RTCP_PACKET_H_ #define _RTCP_PACKET_H_ -#include - -#include - -// SR -// 0 1 2 3 -// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// |V=2|P| RC | PT=SR=200 | length | header -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | SSRC of sender | -// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -// | NTP timestamp, most significant word | sender -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ info -// | NTP timestamp, least significant word | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | RTP timestamp | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | sender's packet count | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | sender's octet count | -// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -// | SSRC_1 (SSRC of first source) | report -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block -// | fraction lost | cumulative number of packets lost | 1 -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | extended highest sequence number received | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | interarrival jitter | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | last SR (LSR) | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | delay since last SR (DLSR) | -// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -// | SSRC_2 (SSRC of second source) | report -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block -// : ... : 2 -// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -// | profile-specific extensions | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -// RR -// 0 1 2 3 -// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// |V=2|P| RC | PT=RR=201 | length | header -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | SSRC of packet sender | -// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -// | SSRC_1 (SSRC of first source) | report -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block -// | fraction lost | cumulative number of packets lost | 1 -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | extended highest sequence number received | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | interarrival jitter | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | last SR (LSR) | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | delay since last SR (DLSR) | -// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -// | SSRC_2 (SSRC of second source) | report -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block -// : ... : 2 -// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -// | profile-specific extensions | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - class RtcpPacket { public: typedef enum { @@ -78,108 +10,7 @@ class RtcpPacket { SDES = 202, BYE = 203, APP = 204 - } PAYLOAD_TYPE; - - public: - RtcpPacket(); - RtcpPacket(const uint8_t *buffer, size_t size); - RtcpPacket(const RtcpPacket &rtp_packet); - RtcpPacket(RtcpPacket &&rtp_packet); - RtcpPacket &operator=(const RtcpPacket &rtp_packet); - RtcpPacket &operator=(RtcpPacket &&rtp_packet); - - ~RtcpPacket(); - - public: - // Set Header - void SetVerion(uint8_t version) { version_ = version; } - void SetPadding(uint8_t padding) { padding_ = padding; } - void SetReceptionReportCount(uint8_t reception_report_count) { - reception_report_count_ = reception_report_count; - } - void SetPayloadType(PAYLOAD_TYPE payload_type) { - payload_type_ = payload_type; - } - void SetLength(uint16_t length) { length_ = length; } - - public: - typedef struct { - uint8_t v : 2; - uint8_t p : 1; - uint8_t rc : 5; - uint8_t pt : 8; - uint16_t length : 16; - } RTCP_HEADER; - - typedef struct { - uint32_t ssrc_of_sender : 32; - uint64_t ntp_timestamp : 64; - uint32_t rtp_timestamp : 32; - uint32_t total_sent_count : 32; - uint32_t total_payload_sent_count : 32; - } SENDER_INFO; - - typedef struct { - uint32_t ssrc : 32; - uint8_t fraction_lost : 8; - uint32_t cumulative_packets_lost : 24; - uint32_t highest_sequence_number_received : 32; - uint32_t jitter : 32; - uint32_t lsr : 32; - uint32_t dlsr : 32; - } REPORT; - - void SetRtcpHeader(RTCP_HEADER &rtcp_header) { - rtcp_header_.v = rtcp_header.v; - rtcp_header_.p = rtcp_header.p; - rtcp_header_.rc = rtcp_header.rc; - rtcp_header_.pt = rtcp_header.pt; - rtcp_header_.length = rtcp_header.length; - } - - void SetSenderInfo(SENDER_INFO &sender_info) { - sender_info_.ssrc_of_sender = sender_info.ssrc_of_sender; - sender_info_.ntp_timestamp = sender_info.ntp_timestamp; - sender_info_.rtp_timestamp = sender_info.rtp_timestamp; - sender_info_.total_sent_count = sender_info.total_sent_count; - sender_info_.total_payload_sent_count = - sender_info.total_payload_sent_count; - } - - void SetReport(REPORT &report) { - report_.ssrc = report.ssrc; - report_.fraction_lost = report.fraction_lost; - report_.cumulative_packets_lost = report.cumulative_packets_lost; - report_.highest_sequence_number_received = - report.highest_sequence_number_received; - report_.jitter = report.jitter; - report_.lsr = report.lsr; - report_.dlsr = report.dlsr; - } - - public: - const uint8_t *Encode(uint8_t *payload, size_t payload_size); - size_t Decode(uint8_t *payload); - - public: - // Get Header - const uint8_t Verion() { return version_; } - const uint8_t Padding() { return padding_; } - const uint8_t ReceptionReportCount() { return reception_report_count_; } - const PAYLOAD_TYPE PayloadType() { return PAYLOAD_TYPE(payload_type_); } - const uint16_t Length() { return length_; } - - private: - // Header - uint8_t version_ = 0; - uint8_t padding_ = false; - uint8_t reception_report_count_ = 0; - uint8_t payload_type_ = 0; - uint16_t length_ = 0; - - RTCP_HEADER rtcp_header_; - SENDER_INFO sender_info_; - REPORT report_; + } RTCP_TYPE; }; #endif \ No newline at end of file diff --git a/src/rtcp/rtcp_receiver_report.cpp b/src/rtcp/rtcp_receiver_report.cpp new file mode 100644 index 0000000..a341455 --- /dev/null +++ b/src/rtcp/rtcp_receiver_report.cpp @@ -0,0 +1,5 @@ +#include "rtcp_receiver_report.h" + +RtcpReceiverReport::RtcpReceiverReport() {} + +RtcpReceiverReport::~RtcpReceiverReport() {} \ No newline at end of file diff --git a/src/rtcp/rtcp_receiver_report.h b/src/rtcp/rtcp_receiver_report.h new file mode 100644 index 0000000..4794914 --- /dev/null +++ b/src/rtcp/rtcp_receiver_report.h @@ -0,0 +1,52 @@ +#ifndef _RTCP_RECEIVER_REPORT_H_ +#define _RTCP_RECEIVER_REPORT_H_ + +// RR +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |V=2|P| RC | PT=SR=200 | length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | SSRC of packet sender | +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// | SSRC_1 (SSRC of first source) | report +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block +// | fraction lost | cumulative number of packets lost | 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | extended highest sequence number received | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | interarrival jitter | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | last SR (LSR) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | delay since last SR (DLSR) | +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// | SSRC_2 (SSRC of second source) | report +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block +// : ... : 2 +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// | profile-specific extensions | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +#include + +#include "rtcp_header.h" +#include "rtcp_report_block.h" + +#define DEFAULT_SR_SIZE 32 + +class RtcpReceiverReport { + public: + RtcpReceiverReport(); + ~RtcpReceiverReport(); + + public: + const uint8_t *Encode(uint8_t *payload, size_t payload_size); + size_t Decode(uint8_t *payload); + + private: + RtcpHeader rtcp_header_; + std::vector reports_; +}; + +#endif \ No newline at end of file diff --git a/src/rtcp/rtcp_report_block.cpp b/src/rtcp/rtcp_report_block.cpp new file mode 100644 index 0000000..c757ce9 --- /dev/null +++ b/src/rtcp/rtcp_report_block.cpp @@ -0,0 +1,5 @@ +#include "rtcp_report_block.h" + +RtcpReportBlock::RtcpReportBlock() {} + +RtcpReportBlock::~RtcpReportBlock() {} \ No newline at end of file diff --git a/src/rtcp/rtcp_report_block.h b/src/rtcp/rtcp_report_block.h new file mode 100644 index 0000000..8c1c734 --- /dev/null +++ b/src/rtcp/rtcp_report_block.h @@ -0,0 +1,53 @@ +#ifndef _RTCP_REPORT_BLOCK_H_ +#define _RTCP_REPORT_BLOCK_H_ + +// Report block 1 +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | SSRC_1 (SSRC of first source) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | fraction lost | cumulative number of packets lost | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | extended highest sequence number received | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | interarrival jitter | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | last SR (LSR) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | delay since last SR (DLSR) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +#include + +class RtcpReportBlock { + public: + RtcpReportBlock(); + ~RtcpReportBlock(); + + public: + typedef struct { + uint32_t source_ssrc : 32; + uint8_t fraction_lost : 8; + uint32_t cumulative_lost : 24; + uint32_t extended_high_seq_num : 32; + uint32_t jitter : 32; + uint32_t lsr : 32; + uint32_t dlsr : 32; + } REPORT; + + void SetReport(REPORT &report) { + report_.source_ssrc = report.source_ssrc; + report_.fraction_lost = report.fraction_lost; + report_.cumulative_lost = report.cumulative_lost; + report_.extended_high_seq_num = report.extended_high_seq_num; + report_.jitter = report.jitter; + report_.lsr = report.lsr; + report_.dlsr = report.dlsr; + } + + private: + REPORT report_; +}; + +#endif \ No newline at end of file diff --git a/src/rtcp/rtcp_sender_report.cpp b/src/rtcp/rtcp_sender_report.cpp new file mode 100644 index 0000000..fb4c57d --- /dev/null +++ b/src/rtcp/rtcp_sender_report.cpp @@ -0,0 +1,52 @@ +#include "rtcp_sender_report.h" + +RtcpSenderReport::RtcpSenderReport() { + buffer_ = new uint8_t[DEFAULT_SR_SIZE]; + size_ = DEFAULT_SR_SIZE; +} + +RtcpSenderReport::~RtcpSenderReport() { + if (buffer_) { + delete buffer_; + buffer_ = nullptr; + } + + size_ = 0; +} + +const uint8_t *RtcpSenderReport::Encode() { + int pos = + rtcp_header_.Encode(DEFAULT_RTCP_VERSION, 0, DEFAULT_SR_BLOCK_NUM, + RtcpPacket::RTCP_TYPE::SR, DEFAULT_SR_SIZE, buffer_); + + buffer_[pos] = sender_info_.sender_ssrc >> 24 & 0xFF; + buffer_[pos + 1] = sender_info_.sender_ssrc >> 16 & 0xFF; + buffer_[pos + 2] = sender_info_.sender_ssrc >> 8 & 0xFF; + buffer_[pos + 3] = sender_info_.sender_ssrc & 0xFF; + + buffer_[pos + 4] = sender_info_.ntp_ts >> 56 & 0xFF; + buffer_[pos + 5] = sender_info_.ntp_ts >> 48 & 0xFF; + buffer_[pos + 6] = sender_info_.ntp_ts >> 40 & 0xFF; + buffer_[pos + 7] = sender_info_.ntp_ts >> 32 & 0xFF; + buffer_[pos + 8] = sender_info_.ntp_ts >> 24 & 0xFF; + buffer_[pos + 9] = sender_info_.ntp_ts >> 16 & 0xFF; + buffer_[pos + 10] = sender_info_.ntp_ts >> 8 & 0xFF; + buffer_[pos + 11] = sender_info_.ntp_ts & 0xFF; + + buffer_[pos + 12] = sender_info_.rtp_ts >> 24 & 0xFF; + buffer_[pos + 13] = sender_info_.rtp_ts >> 16 & 0xFF; + buffer_[pos + 14] = sender_info_.rtp_ts >> 8 & 0xFF; + buffer_[pos + 15] = sender_info_.rtp_ts & 0xFF; + + buffer_[pos + 16] = sender_info_.sender_packet_count >> 24 & 0xFF; + buffer_[pos + 17] = sender_info_.sender_packet_count >> 16 & 0xFF; + buffer_[pos + 18] = sender_info_.sender_packet_count >> 8 & 0xFF; + buffer_[pos + 19] = sender_info_.sender_packet_count & 0xFF; + + buffer_[pos + 20] = sender_info_.sender_octet_count >> 24 & 0xFF; + buffer_[pos + 21] = sender_info_.sender_octet_count >> 16 & 0xFF; + buffer_[pos + 22] = sender_info_.sender_octet_count >> 8 & 0xFF; + buffer_[pos + 23] = sender_info_.sender_octet_count & 0xFF; + + return buffer_; +} \ No newline at end of file diff --git a/src/rtcp/rtcp_sender_report.h b/src/rtcp/rtcp_sender_report.h new file mode 100644 index 0000000..a48b46d --- /dev/null +++ b/src/rtcp/rtcp_sender_report.h @@ -0,0 +1,88 @@ +#ifndef _RTCP_SENDER_REPORT_H_ +#define _RTCP_SENDER_REPORT_H_ + +// SR +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |V=2|P| RC | PT=SR=200 | length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | SSRC of sender | +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// | NTP timestamp, most significant word | sender +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ info +// | NTP timestamp, least significant word | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | RTP timestamp | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | sender's packet count | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | sender's octet count | +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// | SSRC_1 (SSRC of first source) | report +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block +// | fraction lost | cumulative number of packets lost | 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | extended highest sequence number received | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | interarrival jitter | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | last SR (LSR) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | delay since last SR (DLSR) | +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// | SSRC_2 (SSRC of second source) | report +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block +// : ... : 2 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +#include + +#include "rtcp_header.h" +#include "rtcp_packet.h" +#include "rtcp_report_block.h" + +#define DEFAULT_SR_BLOCK_NUM 1 +#define DEFAULT_SR_SIZE 52 + +class RtcpSenderReport { + public: + RtcpSenderReport(); + ~RtcpSenderReport(); + + public: + typedef struct { + uint32_t sender_ssrc : 32; + uint64_t ntp_ts : 64; + uint32_t rtp_ts : 32; + uint32_t sender_packet_count : 32; + uint32_t sender_octet_count : 32; + } SENDER_INFO; + + void SetSenderInfo(SENDER_INFO &sender_info) { + sender_info_.sender_ssrc = sender_info.sender_ssrc; + sender_info_.ntp_ts = sender_info.ntp_ts; + sender_info_.rtp_ts = sender_info.rtp_ts; + sender_info_.sender_packet_count = sender_info.sender_packet_count; + sender_info_.sender_octet_count = sender_info.sender_octet_count; + } + + public: + const uint8_t *Encode(); + size_t Decode(); + + // Entire RTP buffer + const uint8_t *Buffer() const { return buffer_; } + size_t Size() const { return size_; } + + private: + RtcpHeader rtcp_header_; + SENDER_INFO sender_info_; + std::vector reports_; + + // Entire RTCP buffer + uint8_t *buffer_ = nullptr; + size_t size_ = 0; +}; + +#endif \ No newline at end of file diff --git a/src/rtp/rtp_packet.h b/src/rtp/rtp_packet.h index 04ce623..ade1319 100644 --- a/src/rtp/rtp_packet.h +++ b/src/rtp/rtp_packet.h @@ -141,30 +141,30 @@ class RtpPacket { public: // Get Header - const uint32_t Verion() { return version_; } - const bool HasPadding() { return has_padding_; } - const bool HasExtension() { return has_extension_; } - const bool Marker() { return marker_; } - const PAYLOAD_TYPE PayloadType() { return PAYLOAD_TYPE(payload_type_); } - const uint16_t SequenceNumber() { return sequence_number_; } - const uint32_t Timestamp() { return timestamp_; } - const uint32_t Ssrc() { return ssrc_; } - const std::vector Csrcs() { return csrcs_; }; - const uint16_t ExtensionProfile() { return extension_profile_; } - const uint8_t *ExtensionData() { return extension_data_; } + uint32_t Verion() const { return version_; } + bool HasPadding() const { return has_padding_; } + bool HasExtension() const { return has_extension_; } + bool Marker() const { return marker_; } + PAYLOAD_TYPE PayloadType() const { return PAYLOAD_TYPE(payload_type_); } + uint16_t SequenceNumber() const { return sequence_number_; } + uint32_t Timestamp() const { return timestamp_; } + uint32_t Ssrc() const { return ssrc_; } + std::vector Csrcs() const { return csrcs_; }; + uint16_t ExtensionProfile() const { return extension_profile_; } + const uint8_t *ExtensionData() const { return extension_data_; } // Payload - const uint8_t *Payload() { return payload_; }; - const size_t PayloadSize() { return payload_size_; } + const uint8_t *Payload() const { return payload_; }; + size_t PayloadSize() const { return payload_size_; } // Entire RTP buffer - const uint8_t *Buffer() { return buffer_; } - const size_t Size() { return size_; } + const uint8_t *Buffer() const { return buffer_; } + size_t Size() const { return size_; } // NAL - const NAL_UNIT_TYPE NalUnitType() { return nal_unit_type_; } - const bool FuAStart() { return fu_header_.start; } - const bool FuAEnd() { return fu_header_.end; } + NAL_UNIT_TYPE NalUnitType() const { return nal_unit_type_; } + bool FuAStart() const { return fu_header_.start; } + bool FuAEnd() const { return fu_header_.end; } private: inline void TryToDecodeH264RtpPacket(uint8_t *buffer); diff --git a/src/rtp/rtp_video_receiver.cpp b/src/rtp/rtp_video_receiver.cpp index 402f077..e0a02cc 100644 --- a/src/rtp/rtp_video_receiver.cpp +++ b/src/rtp/rtp_video_receiver.cpp @@ -9,6 +9,10 @@ RtpVideoReceiver::RtpVideoReceiver() {} RtpVideoReceiver::~RtpVideoReceiver() {} void RtpVideoReceiver::InsertRtpPacket(RtpPacket& rtp_packet) { + if (rtp_packet.PayloadType() == 200) { + LOG_ERROR("!!!!!!!!!!!!!!!!!!"); + } + if (!rtp_video_receive_statistics_) { rtp_video_receive_statistics_ = std::make_unique(); diff --git a/src/rtp/rtp_video_sender.cpp b/src/rtp/rtp_video_sender.cpp index 762f07e..26a8582 100644 --- a/src/rtp/rtp_video_sender.cpp +++ b/src/rtp/rtp_video_sender.cpp @@ -4,6 +4,8 @@ #include "log.h" +#define RTCP_INTERVAL 1000 + RtpVideoSender::RtpVideoSender() {} RtpVideoSender::~RtpVideoSender() { rtp_video_send_statistics_->Stop(); } @@ -19,6 +21,88 @@ void RtpVideoSender::Enqueue(std::vector& rtp_packets) { } } +void RtpVideoSender::SetUdpSender( + std::function udp_sender) { + udp_sender_ = udp_sender; +} + +int RtpVideoSender::SendRtpPacket(RtpPacket& rtp_packet) { + if (!udp_sender_) { + LOG_ERROR("udp_sender_ is nullptr"); + return -1; + } + + int ret = 0; + + if (0 != udp_sender_((const char*)rtp_packet.Buffer(), rtp_packet.Size())) { + LOG_ERROR("Send rtp packet failed"); + return -1; + } + + last_send_bytes_ += rtp_packet.Size(); + total_rtp_packets_sent_++; + total_rtp_payload_sent_ += rtp_packet.PayloadSize(); + + if (CheckIsTimeSendRtcpPacket()) { + RtcpSenderReport rtcp_sr; + RtcpSenderReport::SENDER_INFO sender_info; + + auto duration = std::chrono::system_clock::now().time_since_epoch(); + auto seconds = std::chrono::duration_cast(duration); + uint32_t seconds_u32 = static_cast( + std::chrono::duration_cast(duration).count()); + + uint32_t fraction_u32 = static_cast( + std::chrono::duration_cast(duration - seconds) + .count()); + + sender_info.sender_ssrc = 0x00; + sender_info.ntp_ts = (uint64_t)seconds_u32 << 32 | (uint64_t)fraction_u32; + sender_info.rtp_ts = + std::chrono::high_resolution_clock::now().time_since_epoch().count() * + 1000000; + sender_info.sender_packet_count = total_rtp_packets_sent_; + sender_info.sender_octet_count = total_rtp_payload_sent_; + + rtcp_sr.SetSenderInfo(sender_info); + + rtcp_sr.Encode(); + + SendRtcpSR(rtcp_sr); + } + + return 0; +} + +int RtpVideoSender::SendRtcpSR(RtcpSenderReport& rtcp_sr) { + if (!udp_sender_) { + LOG_ERROR("udp_sender_ is nullptr"); + return -1; + } + + if (udp_sender_((const char*)rtcp_sr.Buffer(), rtcp_sr.Size())) { + LOG_ERROR("Send SR failed"); + return -1; + } + + LOG_ERROR("Send SR"); + + return 0; +} + +bool RtpVideoSender::CheckIsTimeSendRtcpPacket() { + auto now_ts = + std::chrono::high_resolution_clock::now().time_since_epoch().count() * + 1000000; + + if (now_ts - last_send_rtcp_packet_ts_ >= RTCP_INTERVAL) { + last_send_rtcp_packet_ts_ = now_ts; + return true; + } else { + return false; + } +} + bool RtpVideoSender::Process() { last_send_bytes_ = 0; @@ -26,10 +110,7 @@ bool RtpVideoSender::Process() { if (!rtp_packe_queue_.isEmpty()) { RtpPacket rtp_packet; rtp_packe_queue_.pop(rtp_packet); - if (rtp_packet_send_func_) { - rtp_packet_send_func_(rtp_packet); - last_send_bytes_ += rtp_packet.Size(); - } + SendRtpPacket(rtp_packet); } if (rtp_video_send_statistics_) { diff --git a/src/rtp/rtp_video_sender.h b/src/rtp/rtp_video_sender.h index fb44784..5f47481 100644 --- a/src/rtp/rtp_video_sender.h +++ b/src/rtp/rtp_video_sender.h @@ -4,6 +4,8 @@ #include #include "ringbuffer.h" +#include "rtcp_packet.h" +#include "rtcp_sender_report.h" #include "rtp_packet.h" #include "rtp_video_send_statistics.h" #include "thread_base.h" @@ -17,21 +19,28 @@ class RtpVideoSender : public ThreadBase { void Enqueue(std::vector &rtp_packets); public: - void SetRtpPacketSendFunc( - std::function rtp_packet_send_func) { - rtp_packet_send_func_ = rtp_packet_send_func; - } + void SetUdpSender( + std::function rtp_packet_send_func); + + private: + int SendRtpPacket(RtpPacket &rtp_packet); + int SendRtcpSR(RtcpSenderReport &rtcp_sr); + + bool CheckIsTimeSendRtcpPacket(); private: bool Process() override; private: - std::function rtp_packet_send_func_ = nullptr; + std::function udp_sender_ = nullptr; RingBuffer rtp_packe_queue_; private: std::unique_ptr rtp_video_send_statistics_ = nullptr; uint32_t last_send_bytes_ = 0; + uint32_t last_send_rtcp_packet_ts_ = 0; + uint32_t total_rtp_packets_sent_ = 0; + uint32_t total_rtp_payload_sent_ = 0; }; #endif \ No newline at end of file diff --git a/src/transmission/ice_transmission.cpp b/src/transmission/ice_transmission.cpp index 5e9aa14..763d2e1 100644 --- a/src/transmission/ice_transmission.cpp +++ b/src/transmission/ice_transmission.cpp @@ -60,11 +60,13 @@ int IceTransmission::InitIceTransmission(std::string &ip, int port) { rtp_video_receiver_->Start(); rtp_video_sender_ = std::make_unique(); - rtp_video_sender_->SetRtpPacketSendFunc([this]( - RtpPacket &rtp_packet) -> void { - if (ice_agent_) { - ice_agent_->Send((const char *)rtp_packet.Buffer(), rtp_packet.Size()); + rtp_video_sender_->SetUdpSender([this](const char *data, size_t size) -> int { + if (!ice_agent_) { + LOG_ERROR("ice_agent_ is nullptr"); + return -1; } + + return ice_agent_->Send(data, size); }); rtp_video_sender_->Start(); diff --git a/xmake.lua b/xmake.lua index fa1a726..259d88b 100644 --- a/xmake.lua +++ b/xmake.lua @@ -58,10 +58,16 @@ target("frame") set_kind("static") add_files("src/frame/*.cpp") add_includedirs("src/frame", {public = true}) - + +target("rtcp") + set_kind("static") + add_deps("log") + add_files("src/rtcp/*.cpp") + add_includedirs("src/rtcp", {public = true}) + target("rtp") set_kind("static") - add_deps("log", "frame", "ringbuffer", "thread") + add_deps("log", "frame", "ringbuffer", "thread", "rtcp") add_files("src/rtp/*.cpp") add_includedirs("src/rtp", {public = true}) @@ -101,7 +107,7 @@ target("qos") target("transmission") set_kind("static") - add_deps("log", "ws", "ice", "qos", "rtp") + add_deps("log", "ws", "ice", "qos", "rtp", "rtcp") add_files("src/transmission/*.cpp") add_packages("asio", "nlohmann_json") add_includedirs("src/ws", "src/ice", "src/qos", {public = true})