webrtc支持 rtcp xr(#1796)

metaRTC 播放时,会发送rtcp xr,因此处理rtcp xr 来兼容
This commit is contained in:
夏楚 2022-07-15 11:11:30 +08:00 committed by GitHub
commit 6aa1c239b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 1277 additions and 934 deletions

View File

@ -8,55 +8,67 @@
* may be found in the AUTHORS file in the root of the source tree.
*/
#include <stddef.h>
#include <assert.h>
#include "Rtcp.h"
#include "Util/logger.h"
#include "RtcpFCI.h"
#include "Util/logger.h"
#include <assert.h>
#include <stddef.h>
using namespace std;
using namespace toolkit;
namespace mediakit {
const char *rtcpTypeToStr(RtcpType type){
switch (type){
#define SWITCH_CASE(key, value) case RtcpType::key : return #value "(" #key ")";
const char *rtcpTypeToStr(RtcpType type) {
switch (type) {
#define SWITCH_CASE(key, value) \
case RtcpType::key: \
return #value "(" #key ")";
RTCP_PT_MAP(SWITCH_CASE)
#undef SWITCH_CASE
default: return "unknown rtcp pt";
default:
return "unknown rtcp pt";
}
}
const char *sdesTypeToStr(SdesType type){
switch (type){
#define SWITCH_CASE(key, value) case SdesType::key : return #value "(" #key ")";
const char *sdesTypeToStr(SdesType type) {
switch (type) {
#define SWITCH_CASE(key, value) \
case SdesType::key: \
return #value "(" #key ")";
SDES_TYPE_MAP(SWITCH_CASE)
#undef SWITCH_CASE
default: return "unknown source description type";
default:
return "unknown source description type";
}
}
const char *psfbTypeToStr(PSFBType type) {
switch (type){
#define SWITCH_CASE(key, value) case PSFBType::key : return #value "(" #key ")";
switch (type) {
#define SWITCH_CASE(key, value) \
case PSFBType::key: \
return #value "(" #key ")";
PSFB_TYPE_MAP(SWITCH_CASE)
#undef SWITCH_CASE
default: return "unknown payload-specific fb message fmt type";
default:
return "unknown payload-specific fb message fmt type";
}
}
const char *rtpfbTypeToStr(RTPFBType type) {
switch (type){
#define SWITCH_CASE(key, value) case RTPFBType::key : return #value "(" #key ")";
switch (type) {
#define SWITCH_CASE(key, value) \
case RTPFBType::key: \
return #value "(" #key ")";
RTPFB_TYPE_MAP(SWITCH_CASE)
#undef SWITCH_CASE
default: return "unknown transport layer feedback messages fmt type";
default:
return "unknown transport layer feedback messages fmt type";
}
}
static size_t alignSize(size_t bytes) {
return (size_t) ((bytes + 3) >> 2) << 2;
return (size_t)((bytes + 3) >> 2) << 2;
}
static void setupHeader(RtcpHeader *rtcp, RtcpType type, size_t report_count, size_t total_bytes) {
@ -65,16 +77,16 @@ static void setupHeader(RtcpHeader *rtcp, RtcpType type, size_t report_count, si
if (report_count > 0x1F) {
throw std::invalid_argument(StrPrinter << "rtcp report_count最大赋值为31,当前为:" << report_count);
}
//items总个数
// items总个数
rtcp->report_count = report_count;
rtcp->pt = (uint8_t) type;
rtcp->pt = (uint8_t)type;
rtcp->setSize(total_bytes);
}
static void setupPadding(RtcpHeader *rtcp, size_t padding_size) {
if (padding_size) {
rtcp->padding = 1;
((uint8_t *) rtcp)[rtcp->getSize() - 1] = padding_size & 0xFF;
((uint8_t *)rtcp)[rtcp->getSize() - 1] = padding_size & 0xFF;
} else {
rtcp->padding = 0;
}
@ -91,110 +103,125 @@ string RtcpHeader::dumpHeader() const {
printer << "padding:" << padding << "\r\n";
}
switch ((RtcpType) pt) {
case RtcpType::RTCP_RTPFB : {
printer << "report_count:" << rtpfbTypeToStr((RTPFBType) report_count) << "\r\n";
switch ((RtcpType)pt) {
case RtcpType::RTCP_RTPFB: {
printer << "report_count:" << rtpfbTypeToStr((RTPFBType)report_count) << "\r\n";
break;
}
case RtcpType::RTCP_PSFB : {
printer << "report_count:" << psfbTypeToStr((PSFBType) report_count) << "\r\n";
case RtcpType::RTCP_PSFB: {
printer << "report_count:" << psfbTypeToStr((PSFBType)report_count) << "\r\n";
break;
}
default : {
default: {
printer << "report_count:" << report_count << "\r\n";
break;
}
}
printer << "pt:" << rtcpTypeToStr((RtcpType) pt) << "\r\n";
printer << "pt:" << rtcpTypeToStr((RtcpType)pt) << "\r\n";
printer << "size:" << getSize() << "\r\n";
printer << "--------\r\n";
return std::move(printer);
}
string RtcpHeader::dumpString() const {
switch ((RtcpType) pt) {
switch ((RtcpType)pt) {
case RtcpType::RTCP_SR: {
RtcpSR *rtcp = (RtcpSR *) this;
RtcpSR *rtcp = (RtcpSR *)this;
return rtcp->dumpString();
}
case RtcpType::RTCP_RR: {
RtcpRR *rtcp = (RtcpRR *) this;
RtcpRR *rtcp = (RtcpRR *)this;
return rtcp->dumpString();
}
case RtcpType::RTCP_SDES: {
RtcpSdes *rtcp = (RtcpSdes *) this;
RtcpSdes *rtcp = (RtcpSdes *)this;
return rtcp->dumpString();
}
case RtcpType::RTCP_RTPFB:
case RtcpType::RTCP_PSFB: {
RtcpFB *rtcp = (RtcpFB *) this;
RtcpFB *rtcp = (RtcpFB *)this;
return rtcp->dumpString();
}
case RtcpType::RTCP_BYE: {
RtcpBye *rtcp = (RtcpBye *) this;
RtcpBye *rtcp = (RtcpBye *)this;
return rtcp->dumpString();
}
default: return StrPrinter << dumpHeader() << hexdump((char *)this + sizeof(*this), getSize() - sizeof(*this));
default:
return StrPrinter << dumpHeader() << hexdump((char *)this + sizeof(*this), getSize() - sizeof(*this));
}
}
size_t RtcpHeader::getSize() const {
//加上rtcp头长度
// 加上rtcp头长度
return (1 + ntohs(length)) << 2;
}
size_t RtcpHeader::getPaddingSize() const{
size_t RtcpHeader::getPaddingSize() const {
if (!padding) {
return 0;
}
return ((uint8_t *) this)[getSize() - 1];
return ((uint8_t *)this)[getSize() - 1];
}
void RtcpHeader::setSize(size_t size) {
//不包含rtcp头的长度
length = htons((uint16_t) ((size >> 2) - 1));
// 不包含rtcp头的长度
length = htons((uint16_t)((size >> 2) - 1));
}
void RtcpHeader::net2Host(size_t len) {
switch ((RtcpType) pt) {
switch ((RtcpType)pt) {
case RtcpType::RTCP_SR: {
RtcpSR *sr = (RtcpSR *) this;
RtcpSR *sr = (RtcpSR *)this;
sr->net2Host(len);
break;
}
case RtcpType::RTCP_RR: {
RtcpRR *rr = (RtcpRR *) this;
RtcpRR *rr = (RtcpRR *)this;
rr->net2Host(len);
break;
}
case RtcpType::RTCP_SDES: {
RtcpSdes *sdes = (RtcpSdes *) this;
RtcpSdes *sdes = (RtcpSdes *)this;
sdes->net2Host(len);
break;
}
case RtcpType::RTCP_RTPFB:
case RtcpType::RTCP_PSFB: {
RtcpFB *fb = (RtcpFB *) this;
RtcpFB *fb = (RtcpFB *)this;
fb->net2Host(len);
break;
}
case RtcpType::RTCP_BYE: {
RtcpBye *bye = (RtcpBye *) this;
RtcpBye *bye = (RtcpBye *)this;
bye->net2Host(len);
break;
}
default: throw std::runtime_error(StrPrinter << "未处理的rtcp包:" << rtcpTypeToStr((RtcpType) this->pt));
case RtcpType::RTCP_XR: {
RtcpXRRRTR *xr = (RtcpXRRRTR *)this;
if (xr->bt == 4) {
xr->net2Host(len);
// TraceL<<xr->dumpString();
} else if (xr->bt == 5) {
RtcpXRDLRR *dlrr = (RtcpXRDLRR *)this;
dlrr->net2Host(len);
TraceL << dlrr->dumpString();
} else {
throw std::runtime_error(StrPrinter << "rtcp xr bt " << xr->bt << " not support");
}
break;
}
default:
throw std::runtime_error(StrPrinter << "未处理的rtcp包:" << rtcpTypeToStr((RtcpType)this->pt));
}
}
@ -202,10 +229,10 @@ vector<RtcpHeader *> RtcpHeader::loadFromBytes(char *data, size_t len) {
vector<RtcpHeader *> ret;
ssize_t remain = len;
char *ptr = data;
while (remain > (ssize_t) sizeof(RtcpHeader)) {
RtcpHeader *rtcp = (RtcpHeader *) ptr;
while (remain > (ssize_t)sizeof(RtcpHeader)) {
RtcpHeader *rtcp = (RtcpHeader *)ptr;
auto rtcp_len = rtcp->getSize();
if (remain < (ssize_t) rtcp_len) {
if (remain < (ssize_t)rtcp_len) {
WarnL << "非法的rtcp包,声明的长度超过实际数据长度";
break;
}
@ -213,7 +240,7 @@ vector<RtcpHeader *> RtcpHeader::loadFromBytes(char *data, size_t len) {
rtcp->net2Host(rtcp_len);
ret.emplace_back(rtcp);
} catch (std::exception &ex) {
//不能处理的rtcp包或者无法解析的rtcp包忽略掉
// 不能处理的rtcp包或者无法解析的rtcp包忽略掉
WarnL << ex.what() << ",长度为:" << rtcp_len;
}
ptr += rtcp_len;
@ -224,19 +251,13 @@ vector<RtcpHeader *> RtcpHeader::loadFromBytes(char *data, size_t len) {
class BufferRtcp : public Buffer {
public:
BufferRtcp(std::shared_ptr<RtcpHeader> rtcp) {
_rtcp = std::move(rtcp);
}
BufferRtcp(std::shared_ptr<RtcpHeader> rtcp) { _rtcp = std::move(rtcp); }
~BufferRtcp() override {}
char *data() const override {
return (char *) _rtcp.get();
}
char *data() const override { return (char *)_rtcp.get(); }
size_t size() const override {
return _rtcp->getSize();
}
size_t size() const override { return _rtcp->getSize(); }
private:
std::shared_ptr<RtcpHeader> _rtcp;
@ -251,36 +272,34 @@ Buffer::Ptr RtcpHeader::toBuffer(std::shared_ptr<RtcpHeader> rtcp) {
std::shared_ptr<RtcpSR> RtcpSR::create(size_t item_count) {
auto real_size = sizeof(RtcpSR) - sizeof(ReportItem) + item_count * sizeof(ReportItem);
auto bytes = alignSize(real_size);
auto ptr = (RtcpSR *) new char[bytes];
auto ptr = (RtcpSR *)new char[bytes];
setupHeader(ptr, RtcpType::RTCP_SR, item_count, bytes);
setupPadding(ptr, bytes - real_size);
return std::shared_ptr<RtcpSR>(ptr, [](RtcpSR *ptr) {
delete[] (char *) ptr;
});
return std::shared_ptr<RtcpSR>(ptr, [](RtcpSR *ptr) { delete[] (char *)ptr; });
}
string RtcpSR::getNtpStamp() const {
struct timeval tv;
tv.tv_sec = ntpmsw - 0x83AA7E80;
tv.tv_usec = (decltype(tv.tv_usec)) (ntplsw / ((double) (((uint64_t) 1) << 32) * 1.0e-6));
tv.tv_usec = (decltype(tv.tv_usec))(ntplsw / ((double)(((uint64_t)1) << 32) * 1.0e-6));
return LogChannel::printTime(tv);
}
uint64_t RtcpSR::getNtpUnixStampMS() const {
if (ntpmsw < 0x83AA7E80) {
//ntp时间戳起始时间为1900年但是utc时间戳起始时间为1970年两者相差0x83AA7E80秒
//ntp时间戳不得早于1970年否则无法转换为utc时间戳
// ntp时间戳起始时间为1900年但是utc时间戳起始时间为1970年两者相差0x83AA7E80秒
// ntp时间戳不得早于1970年否则无法转换为utc时间戳
return 0;
}
struct timeval tv;
tv.tv_sec = ntpmsw - 0x83AA7E80;
tv.tv_usec = (decltype(tv.tv_usec)) (ntplsw / ((double) (((uint64_t) 1) << 32) * 1.0e-6));
tv.tv_usec = (decltype(tv.tv_usec))(ntplsw / ((double)(((uint64_t)1) << 32) * 1.0e-6));
return 1000 * tv.tv_sec + tv.tv_usec / 1000;
}
void RtcpSR::setNtpStamp(struct timeval tv) {
ntpmsw = htonl(tv.tv_sec + 0x83AA7E80); /* 0x83AA7E80 is the number of seconds from 1900 to 1970 */
ntplsw = htonl((uint32_t) ((double) tv.tv_usec * (double) (((uint64_t) 1) << 32) * 1.0e-6));
ntplsw = htonl((uint32_t)((double)tv.tv_usec * (double)(((uint64_t)1) << 32) * 1.0e-6));
}
void RtcpSR::setNtpStamp(uint64_t unix_stamp_ms) {
@ -300,7 +319,7 @@ string RtcpSR::dumpString() const {
printer << "rtpts:" << rtpts << "\r\n";
printer << "packet_count:" << packet_count << "\r\n";
printer << "octet_count:" << octet_count << "\r\n";
auto items = ((RtcpSR *) this)->getItemList();
auto items = ((RtcpSR *)this)->getItemList();
auto i = 0;
for (auto &item : items) {
printer << "---- item:" << i++ << " ----\r\n";
@ -310,16 +329,18 @@ string RtcpSR::dumpString() const {
}
#define CHECK_MIN_SIZE(size, kMinSize) \
if (size < kMinSize) { \
throw std::out_of_range(StrPrinter << rtcpTypeToStr((RtcpType)pt) << " 长度不足:" << size << " < " << kMinSize); \
}
if (size < kMinSize) { \
throw std::out_of_range( \
StrPrinter << rtcpTypeToStr((RtcpType)pt) << " 长度不足:" << size << " < " << kMinSize); \
}
#define CHECK_REPORT_COUNT(item_count) \
/*修正个数防止getItemList时内存越界*/ \
if (report_count != item_count) { \
WarnL << rtcpTypeToStr((RtcpType)pt) << " report_count 字段不正确,已修正为:" << (int)report_count << " -> " << item_count; \
/*修正个数防止getItemList时内存越界*/ \
if (report_count != item_count) { \
WarnL << rtcpTypeToStr((RtcpType)pt) << " report_count 字段不正确,已修正为:" << (int)report_count << " -> " \
<< item_count; \
report_count = item_count; \
}
}
void RtcpSR::net2Host(size_t size) {
static const size_t kMinSize = sizeof(RtcpSR) - sizeof(items);
@ -334,7 +355,7 @@ void RtcpSR::net2Host(size_t size) {
ReportItem *ptr = &items;
int item_count = 0;
for (int i = 0; i < (int) report_count && (char *) (ptr) + sizeof(ReportItem) <= (char *) (this) + size; ++i) {
for (int i = 0; i < (int)report_count && (char *)(ptr) + sizeof(ReportItem) <= (char *)(this) + size; ++i) {
ptr->net2Host();
++ptr;
++item_count;
@ -345,7 +366,7 @@ void RtcpSR::net2Host(size_t size) {
vector<ReportItem *> RtcpSR::getItemList() {
vector<ReportItem *> ret;
ReportItem *ptr = &items;
for (int i = 0; i < (int) report_count; ++i) {
for (int i = 0; i < (int)report_count; ++i) {
ret.emplace_back(ptr);
++ptr;
}
@ -382,19 +403,17 @@ void ReportItem::net2Host() {
std::shared_ptr<RtcpRR> RtcpRR::create(size_t item_count) {
auto real_size = sizeof(RtcpRR) - sizeof(ReportItem) + item_count * sizeof(ReportItem);
auto bytes = alignSize(real_size);
auto ptr = (RtcpRR *) new char[bytes];
auto ptr = (RtcpRR *)new char[bytes];
setupHeader(ptr, RtcpType::RTCP_RR, item_count, bytes);
setupPadding(ptr, bytes - real_size);
return std::shared_ptr<RtcpRR>(ptr, [](RtcpRR *ptr) {
delete[] (char *) ptr;
});
return std::shared_ptr<RtcpRR>(ptr, [](RtcpRR *ptr) { delete[] (char *)ptr; });
}
string RtcpRR::dumpString() const {
_StrPrinter printer;
printer << RtcpHeader::dumpHeader();
printer << "ssrc:" << ssrc << "\r\n";
auto items = ((RtcpRR *) this)->getItemList();
auto items = ((RtcpRR *)this)->getItemList();
auto i = 0;
for (auto &item : items) {
printer << "---- item:" << i++ << " ----\r\n";
@ -410,7 +429,7 @@ void RtcpRR::net2Host(size_t size) {
ReportItem *ptr = &items;
int item_count = 0;
for (int i = 0; i < (int) report_count && (char *) (ptr) + sizeof(ReportItem) <= (char *) (this) + size; ++i) {
for (int i = 0; i < (int)report_count && (char *)(ptr) + sizeof(ReportItem) <= (char *)(this) + size; ++i) {
ptr->net2Host();
++ptr;
++item_count;
@ -421,7 +440,7 @@ void RtcpRR::net2Host(size_t size) {
vector<ReportItem *> RtcpRR::getItemList() {
vector<ReportItem *> ret;
ReportItem *ptr = &items;
for (int i = 0; i < (int) report_count; ++i) {
for (int i = 0; i < (int)report_count; ++i) {
ret.emplace_back(ptr);
++ptr;
}
@ -445,8 +464,8 @@ size_t SdesChunk::minSize() {
string SdesChunk::dumpString() const {
_StrPrinter printer;
printer << "ssrc:" << ssrc << "\r\n";
printer << "type:" << sdesTypeToStr((SdesType) type) << "\r\n";
printer << "txt_len:" << (int) txt_len << "\r\n";
printer << "type:" << sdesTypeToStr((SdesType)type) << "\r\n";
printer << "txt_len:" << (int)txt_len << "\r\n";
printer << "text:" << (txt_len ? string(text, txt_len) : "") << "\r\n";
return std::move(printer);
}
@ -456,32 +475,30 @@ string SdesChunk::dumpString() const {
std::shared_ptr<RtcpSdes> RtcpSdes::create(const std::vector<string> &item_text) {
size_t item_total_size = 0;
for (auto &text : item_text) {
//统计所有SdesChunk对象占用的空间
// 统计所有SdesChunk对象占用的空间
item_total_size += alignSize(SdesChunk::minSize() + (0xFF & text.size()));
}
auto real_size = sizeof(RtcpSdes) - sizeof(SdesChunk) + item_total_size;
auto bytes = alignSize(real_size);
auto ptr = (RtcpSdes *) new char[bytes];
auto ptr = (RtcpSdes *)new char[bytes];
memset(ptr, 0x00, bytes);
auto item_ptr = &ptr->chunks;
for (auto &text : item_text) {
item_ptr->txt_len = (0xFF & text.size());
//确保赋值\0为RTCP_SDES_END
// 确保赋值\0为RTCP_SDES_END
memcpy(item_ptr->text, text.data(), item_ptr->txt_len + 1);
item_ptr = (SdesChunk *) ((char *) item_ptr + item_ptr->totalBytes());
item_ptr = (SdesChunk *)((char *)item_ptr + item_ptr->totalBytes());
}
setupHeader(ptr, RtcpType::RTCP_SDES, item_text.size(), bytes);
setupPadding(ptr, bytes - real_size);
return std::shared_ptr<RtcpSdes>(ptr, [](RtcpSdes *ptr) {
delete[] (char *) ptr;
});
return std::shared_ptr<RtcpSdes>(ptr, [](RtcpSdes *ptr) { delete[] (char *)ptr; });
}
string RtcpSdes::dumpString() const {
_StrPrinter printer;
printer << RtcpHeader::dumpHeader();
auto items = ((RtcpSdes *) this)->getChunkList();
auto items = ((RtcpSdes *)this)->getChunkList();
auto i = 0;
for (auto &item : items) {
printer << "---- item:" << i++ << " ----\r\n";
@ -495,9 +512,9 @@ void RtcpSdes::net2Host(size_t size) {
CHECK_MIN_SIZE(size, kMinSize);
SdesChunk *ptr = &chunks;
int item_count = 0;
for (int i = 0; i < (int) report_count && (char *) (ptr) + SdesChunk::minSize() <= (char *) (this) + size; ++i) {
for (int i = 0; i < (int)report_count && (char *)(ptr) + SdesChunk::minSize() <= (char *)(this) + size; ++i) {
ptr->net2Host();
ptr = (SdesChunk *) ((char *) ptr + ptr->totalBytes());
ptr = (SdesChunk *)((char *)ptr + ptr->totalBytes());
++item_count;
}
CHECK_REPORT_COUNT(item_count);
@ -506,9 +523,9 @@ void RtcpSdes::net2Host(size_t size) {
vector<SdesChunk *> RtcpSdes::getChunkList() {
vector<SdesChunk *> ret;
SdesChunk *ptr = &chunks;
for (int i = 0; i < (int) report_count; ++i) {
for (int i = 0; i < (int)report_count; ++i) {
ret.emplace_back(ptr);
ptr = (SdesChunk *) ((char *) ptr + ptr->totalBytes());
ptr = (SdesChunk *)((char *)ptr + ptr->totalBytes());
}
return ret;
}
@ -521,31 +538,29 @@ std::shared_ptr<RtcpFB> RtcpFB::create_l(RtcpType type, int fmt, const void *fci
}
auto real_size = sizeof(RtcpFB) + fci_len;
auto bytes = alignSize(real_size);
auto ptr = (RtcpFB *) new char[bytes];
auto ptr = (RtcpFB *)new char[bytes];
if (fci && fci_len) {
memcpy((char *) ptr + sizeof(RtcpFB), fci, fci_len);
memcpy((char *)ptr + sizeof(RtcpFB), fci, fci_len);
}
setupHeader(ptr, type, fmt, bytes);
setupPadding(ptr, bytes - real_size);
return std::shared_ptr<RtcpFB>((RtcpFB *) ptr, [](RtcpFB *ptr) {
delete[] (char *) ptr;
});
return std::shared_ptr<RtcpFB>((RtcpFB *)ptr, [](RtcpFB *ptr) { delete[] (char *)ptr; });
}
std::shared_ptr<RtcpFB> RtcpFB::create(PSFBType fmt, const void *fci, size_t fci_len) {
return RtcpFB::create_l(RtcpType::RTCP_PSFB, (int) fmt, fci, fci_len);
return RtcpFB::create_l(RtcpType::RTCP_PSFB, (int)fmt, fci, fci_len);
}
std::shared_ptr<RtcpFB> RtcpFB::create(RTPFBType fmt, const void *fci, size_t fci_len) {
return RtcpFB::create_l(RtcpType::RTCP_RTPFB, (int) fmt, fci, fci_len);
return RtcpFB::create_l(RtcpType::RTCP_RTPFB, (int)fmt, fci, fci_len);
}
const void *RtcpFB::getFciPtr() const {
return (uint8_t *) &ssrc_media + sizeof(ssrc_media);
return (uint8_t *)&ssrc_media + sizeof(ssrc_media);
}
size_t RtcpFB::getFciSize() const {
auto fci_len = (ssize_t) getSize() - getPaddingSize() - sizeof(RtcpFB);
auto fci_len = (ssize_t)getSize() - getPaddingSize() - sizeof(RtcpFB);
CHECK(fci_len >= 0);
return fci_len;
}
@ -555,58 +570,60 @@ string RtcpFB::dumpString() const {
printer << RtcpHeader::dumpHeader();
printer << "ssrc:" << ssrc << "\r\n";
printer << "ssrc_media:" << ssrc_media << "\r\n";
switch ((RtcpType) pt) {
case RtcpType::RTCP_PSFB : {
switch ((PSFBType) report_count) {
case PSFBType::RTCP_PSFB_SLI : {
switch ((RtcpType)pt) {
case RtcpType::RTCP_PSFB: {
switch ((PSFBType)report_count) {
case PSFBType::RTCP_PSFB_SLI: {
auto &fci = getFci<FCI_SLI>();
printer << "fci:" << psfbTypeToStr((PSFBType) report_count) << " " << fci.dumpString();
printer << "fci:" << psfbTypeToStr((PSFBType)report_count) << " " << fci.dumpString();
break;
}
case PSFBType::RTCP_PSFB_PLI : {
case PSFBType::RTCP_PSFB_PLI: {
getFciSize();
printer << "fci:" << psfbTypeToStr((PSFBType) report_count);
printer << "fci:" << psfbTypeToStr((PSFBType)report_count);
break;
}
case PSFBType::RTCP_PSFB_FIR : {
case PSFBType::RTCP_PSFB_FIR: {
auto &fci = getFci<FCI_FIR>();
printer << "fci:" << psfbTypeToStr((PSFBType) report_count) << " " << fci.dumpString();
printer << "fci:" << psfbTypeToStr((PSFBType)report_count) << " " << fci.dumpString();
break;
}
case PSFBType::RTCP_PSFB_REMB : {
case PSFBType::RTCP_PSFB_REMB: {
auto &fci = getFci<FCI_REMB>();
printer << "fci:" << psfbTypeToStr((PSFBType) report_count) << " " << fci.dumpString();
break;
}
default:{
printer << "fci:" << psfbTypeToStr((PSFBType) report_count) << " " << hexdump(getFciPtr(), getFciSize());
break;
}
}
break;
}
case RtcpType::RTCP_RTPFB : {
switch ((RTPFBType) report_count) {
case RTPFBType::RTCP_RTPFB_NACK : {
auto &fci = getFci<FCI_NACK>();
printer << "fci:" << rtpfbTypeToStr((RTPFBType) report_count) << " " << fci.dumpString();
break;
}
case RTPFBType::RTCP_RTPFB_TWCC : {
auto &fci = getFci<FCI_TWCC>();
printer << "fci:" << rtpfbTypeToStr((RTPFBType) report_count) << " " << fci.dumpString(getFciSize());
printer << "fci:" << psfbTypeToStr((PSFBType)report_count) << " " << fci.dumpString();
break;
}
default: {
printer << "fci:" << rtpfbTypeToStr((RTPFBType) report_count) << " " << hexdump(getFciPtr(), getFciSize());
printer << "fci:" << psfbTypeToStr((PSFBType)report_count) << " " << hexdump(getFciPtr(), getFciSize());
break;
}
}
break;
}
default: /*不可达*/ assert(0); break;
case RtcpType::RTCP_RTPFB: {
switch ((RTPFBType)report_count) {
case RTPFBType::RTCP_RTPFB_NACK: {
auto &fci = getFci<FCI_NACK>();
printer << "fci:" << rtpfbTypeToStr((RTPFBType)report_count) << " " << fci.dumpString();
break;
}
case RTPFBType::RTCP_RTPFB_TWCC: {
auto &fci = getFci<FCI_TWCC>();
printer << "fci:" << rtpfbTypeToStr((RTPFBType)report_count) << " " << fci.dumpString(getFciSize());
break;
}
default: {
printer << "fci:" << rtpfbTypeToStr((RTPFBType)report_count) << " " << hexdump(getFciPtr(), getFciSize());
break;
}
}
break;
}
default: /*不可达*/
assert(0);
break;
}
return std::move(printer);
}
@ -624,24 +641,22 @@ std::shared_ptr<RtcpBye> RtcpBye::create(const std::vector<uint32_t> &ssrcs, con
assert(reason.size() <= 0xFF);
auto real_size = sizeof(RtcpHeader) + sizeof(uint32_t) * ssrcs.size() + 1 + reason.size();
auto bytes = alignSize(real_size);
auto ptr = (RtcpBye *) new char[bytes];
auto ptr = (RtcpBye *)new char[bytes];
setupHeader(ptr, RtcpType::RTCP_BYE, ssrcs.size(), bytes);
setupPadding(ptr, bytes - real_size);
int i = 0;
for (auto ssrc : ssrcs) {
((RtcpBye *) ptr)->ssrc[i++] = htonl(ssrc);
((RtcpBye *)ptr)->ssrc[i++] = htonl(ssrc);
}
if (!reason.empty()) {
uint8_t *reason_len_ptr = (uint8_t *) ptr + sizeof(RtcpHeader) + sizeof(uint32_t) * ssrcs.size();
uint8_t *reason_len_ptr = (uint8_t *)ptr + sizeof(RtcpHeader) + sizeof(uint32_t) * ssrcs.size();
*reason_len_ptr = reason.size() & 0xFF;
memcpy(reason_len_ptr + 1, reason.data(), *reason_len_ptr);
}
return std::shared_ptr<RtcpBye>(ptr, [](RtcpBye *ptr) {
delete[] (char *) ptr;
});
return std::shared_ptr<RtcpBye>(ptr, [](RtcpBye *ptr) { delete[] (char *)ptr; });
}
vector<uint32_t *> RtcpBye::getSSRC() {
@ -654,16 +669,16 @@ vector<uint32_t *> RtcpBye::getSSRC() {
string RtcpBye::getReason() const {
auto *reason_len_ptr = &reason_len + sizeof(ssrc) * (report_count - 1);
if (reason_len_ptr + 1 >= (uint8_t *) this + getSize()) {
if (reason_len_ptr + 1 >= (uint8_t *)this + getSize()) {
return "";
}
return string((char *) reason_len_ptr + 1, *reason_len_ptr);
return string((char *)reason_len_ptr + 1, *reason_len_ptr);
}
string RtcpBye::dumpString() const {
_StrPrinter printer;
printer << RtcpHeader::dumpHeader();
for (auto ssrc : ((RtcpBye *) this)->getSSRC()) {
for (auto ssrc : ((RtcpBye *)this)->getSSRC()) {
printer << "ssrc:" << *ssrc << "\r\n";
}
printer << "reason:" << getReason();
@ -679,18 +694,108 @@ void RtcpBye::net2Host(size_t size) {
ssrc[i] = ntohl(ssrc[i]);
offset += sizeof(ssrc);
}
//修正ssrc个数
// 修正ssrc个数
CHECK_REPORT_COUNT(i);
if (offset < size) {
uint8_t *reason_len_ptr = &reason_len + sizeof(ssrc) * (report_count - 1);
if (reason_len_ptr + 1 + *reason_len_ptr > (uint8_t *) this + size) {
if (reason_len_ptr + 1 + *reason_len_ptr > (uint8_t *)this + size) {
WarnL << "invalid rtcp bye reason length";
//修正reason_len长度
*reason_len_ptr = ((uint8_t *) this + size - reason_len_ptr - 1) & 0xFF;
// 修正reason_len长度
*reason_len_ptr = ((uint8_t *)this + size - reason_len_ptr - 1) & 0xFF;
}
}
}
////////////////////////////////////////////
string RtcpXRRRTR::dumpString() const {
_StrPrinter printer;
printer << RtcpHeader::dumpHeader();
printer << "ssrc :" << ssrc << "\r\n";
printer << "bt :" << (int)bt << "\r\n";
printer << "block_length : " << block_length << "\r\n";
printer << "ntp msw : " << ntpmsw << "\r\n";
printer << "ntp lsw : " << ntplsw << "\r\n";
return std::move(printer);
}
void RtcpXRRRTR::net2Host(size_t size) {
static const size_t kMinSize = sizeof(RtcpHeader);
CHECK_MIN_SIZE(size, kMinSize);
if (size != sizeof(RtcpXRRRTR)) {
throw std::invalid_argument(
StrPrinter << "rtcp xr Receiver Reference Time Report Block must is " << sizeof(RtcpXRRRTR)
<< " actual size " << size);
}
ssrc = ntohl(ssrc);
block_length = ntohs(block_length);
ntpmsw = ntohl(ntpmsw);
ntplsw = ntohl(ntplsw);
}
string RtcpXRDLRRReportItem::dumpString() const {
_StrPrinter printer;
printer << "ssrc :" << ssrc << "\r\n";
printer << "last RR (lrr) :" << lrr << "\r\n";
printer << "delay since last RR (dlrr): " << dlrr << "\r\n";
return std::move(printer);
}
void RtcpXRDLRRReportItem::net2Host() {
ssrc = ntohl(ssrc);
lrr = ntohl(lrr);
dlrr = ntohl(dlrr);
}
std::vector<RtcpXRDLRRReportItem *> RtcpXRDLRR::getItemList() {
auto count = block_length / 3;
RtcpXRDLRRReportItem *ptr = &items;
vector<RtcpXRDLRRReportItem *> ret;
for (int i = 0; i < (int)count; ++i) {
ret.emplace_back(ptr);
++ptr;
}
return ret;
}
string RtcpXRDLRR::dumpString() const {
_StrPrinter printer;
printer << RtcpHeader::dumpHeader();
printer << "ssrc :" << ssrc << "\r\n";
printer << "bt :" << (int)bt << "\r\n";
printer << "block_length : " << block_length << "\r\n";
auto items_list = ((RtcpXRDLRR *)this)->getItemList();
auto i = 0;
for (auto &item : items_list) {
printer << "---- item:" << i++ << " ----\r\n";
printer << item->dumpString();
}
return std::move(printer);
}
void RtcpXRDLRR::net2Host(size_t size) {
static const size_t kMinSize = sizeof(RtcpHeader);
CHECK_MIN_SIZE(size, kMinSize);
ssrc = ntohl(ssrc);
block_length = ntohs(block_length);
auto count = block_length / 3;
for (int i = 0; i < (int)count; ++i) {
RtcpXRDLRRReportItem *ptr = &items;
ptr->net2Host();
ptr++;
}
}
std::shared_ptr<RtcpXRDLRR> RtcpXRDLRR::create(size_t item_count) {
auto real_size = sizeof(RtcpXRDLRR) - sizeof(RtcpXRDLRRReportItem) + item_count * sizeof(RtcpXRDLRRReportItem);
auto bytes = alignSize(real_size);
auto ptr = (RtcpXRDLRR *)new char[bytes];
setupHeader(ptr, RtcpType::RTCP_XR, 0, bytes);
setupPadding(ptr, bytes - real_size);
return std::shared_ptr<RtcpXRDLRR>(ptr, [](RtcpXRDLRR *ptr) { delete[] (char *)ptr; });
}
#if 0
#include "Util/onceToken.h"
@ -706,4 +811,4 @@ static toolkit::onceToken token([](){
});
#endif
}//namespace mediakit
} // namespace mediakit

View File

@ -11,11 +11,11 @@
#ifndef ZLMEDIAKIT_RTCP_H
#define ZLMEDIAKIT_RTCP_H
#include "Common/macros.h"
#include "Network/Buffer.h"
#include "Util/util.h"
#include <stdint.h>
#include <vector>
#include "Util/util.h"
#include "Network/Buffer.h"
#include "Common/macros.h"
namespace mediakit {
@ -23,7 +23,7 @@ namespace mediakit {
#pragma pack(push, 1)
#endif // defined(_WIN32)
//http://www.networksorcery.com/enp/protocol/rtcp.htm
// http://www.networksorcery.com/enp/protocol/rtcp.htm
#define RTCP_PT_MAP(XX) \
XX(RTCP_FIR, 192) \
XX(RTCP_NACK, 193) \
@ -41,7 +41,7 @@ namespace mediakit {
XX(RTCP_RSI, 209) \
XX(RTCP_TOKEN, 210)
//https://tools.ietf.org/html/rfc3550#section-6.5
// https://tools.ietf.org/html/rfc3550#section-6.5
#define SDES_TYPE_MAP(XX) \
XX(RTCP_SDES_END, 0) \
XX(RTCP_SDES_CNAME, 1) \
@ -53,8 +53,8 @@ namespace mediakit {
XX(RTCP_SDES_NOTE, 7) \
XX(RTCP_SDES_PRIVATE, 8)
//https://datatracker.ietf.org/doc/rfc4585/?include_text=1
//6.3. Payload-Specific Feedback Messages
// https://datatracker.ietf.org/doc/rfc4585/?include_text=1
// 6.3. Payload-Specific Feedback Messages
//
// Payload-Specific FB messages are identified by the value PT=PSFB as
// RTCP message type.
@ -80,13 +80,13 @@ namespace mediakit {
XX(RTCP_PSFB_SLI, 2) \
XX(RTCP_PSFB_RPSI, 3) \
XX(RTCP_PSFB_FIR, 4) \
XX(RTCP_PSFB_TSTR, 5)\
XX(RTCP_PSFB_TSTN, 6)\
XX(RTCP_PSFB_TSTR, 5) \
XX(RTCP_PSFB_TSTN, 6) \
XX(RTCP_PSFB_VBCM, 7) \
XX(RTCP_PSFB_REMB, 15)
//https://tools.ietf.org/html/rfc4585#section-6.2
//6.2. Transport Layer Feedback Messages
// https://tools.ietf.org/html/rfc4585#section-6.2
// 6.2. Transport Layer Feedback Messages
//
// Transport layer FB messages are identified by the value RTPFB as RTCP
// message type.
@ -110,28 +110,28 @@ namespace mediakit {
XX(RTCP_RTPFB_TMMBN, 4) \
XX(RTCP_RTPFB_TWCC, 15)
//rtcp类型枚举
// rtcp类型枚举
enum class RtcpType : uint8_t {
#define XX(key, value) key = value,
RTCP_PT_MAP(XX)
#undef XX
};
//sdes类型枚举
// sdes类型枚举
enum class SdesType : uint8_t {
#define XX(key, value) key = value,
SDES_TYPE_MAP(XX)
#undef XX
};
//psfb类型枚举
// psfb类型枚举
enum class PSFBType : uint8_t {
#define XX(key, value) key = value,
PSFB_TYPE_MAP(XX)
#undef XX
};
//rtpfb类型枚举
// rtpfb类型枚举
enum class RTPFBType : uint8_t {
#define XX(key, value) key = value,
RTPFB_TYPE_MAP(XX)
@ -161,26 +161,26 @@ const char *rtpfbTypeToStr(RTPFBType type);
class RtcpHeader {
public:
#if __BYTE_ORDER == __BIG_ENDIAN
//版本号固定为2
uint32_t version: 2;
//padding固定为0
uint32_t padding: 1;
//reception report count
uint32_t report_count: 5;
// 版本号固定为2
uint32_t version : 2;
// padding固定为0
uint32_t padding : 1;
// reception report count
uint32_t report_count : 5;
#else
//reception report count
uint32_t report_count: 5;
//padding末尾是否有追加填充
uint32_t padding: 1;
//版本号固定为2
uint32_t version: 2;
// reception report count
uint32_t report_count : 5;
// padding末尾是否有追加填充
uint32_t padding : 1;
// 版本号固定为2
uint32_t version : 2;
#endif
//rtcp类型,RtcpType
uint32_t pt: 8;
// rtcp类型,RtcpType
uint32_t pt : 8;
private:
//长度
uint32_t length: 16;
// 长度
uint32_t length : 16;
public:
/**
@ -222,7 +222,6 @@ public:
void setSize(size_t size);
protected:
/**
*
* 使net2Host转换成主机字节序后才可使用此函数
@ -240,26 +239,26 @@ private:
/////////////////////////////////////////////////////////////////////////////
//ReportBlock
// ReportBlock
class ReportItem {
public:
friend class RtcpSR;
friend class RtcpRR;
uint32_t ssrc;
//Fraction lost
uint32_t fraction: 8;
//Cumulative number of packets lost
uint32_t cumulative: 24;
//Sequence number cycles count
// Fraction lost
uint32_t fraction : 8;
// Cumulative number of packets lost
uint32_t cumulative : 24;
// Sequence number cycles count
uint16_t seq_cycles;
//Highest sequence number received
// Highest sequence number received
uint16_t seq_max;
//Interarrival jitter
// Interarrival jitter
uint32_t jitter;
//Last SR timestamp, NTP timestamp,(ntpmsw & 0xFFFF) << 16 | (ntplsw >> 16) & 0xFFFF)
// Last SR timestamp, NTP timestamp,(ntpmsw & 0xFFFF) << 16 | (ntplsw >> 16) & 0xFFFF)
uint32_t last_sr_stamp;
//Delay since last SR timestamp,expressed in units of 1/65536 seconds
// Delay since last SR timestamp,expressed in units of 1/65536 seconds
uint32_t delay_since_last_sr;
private:
@ -273,7 +272,7 @@ private:
*
*/
void net2Host();
}PACKED;
} PACKED;
/*
* 6.4.1 SR: Sender Report RTCP Packet
@ -329,7 +328,7 @@ public:
uint32_t packet_count;
// sender octet count
uint32_t octet_count;
//可能有很多个
// 可能有很多个
ReportItem items;
public:
@ -358,7 +357,7 @@ public:
* ReportItem对象指针列表
* 使net2Host转换成主机字节序后才可使用此函数
*/
std::vector<ReportItem*> getItemList();
std::vector<ReportItem *> getItemList();
private:
/**
@ -406,13 +405,13 @@ block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
//Receiver Report
// Receiver Report
class RtcpRR : public RtcpHeader {
public:
friend class RtcpHeader;
uint32_t ssrc;
//可能有很多个
// 可能有很多个
ReportItem items;
public:
@ -427,7 +426,7 @@ public:
* ReportItem对象指针列表
* 使net2Host转换成主机字节序后才可使用此函数
*/
std::vector<ReportItem*> getItemList();
std::vector<ReportItem *> getItemList();
private:
/**
@ -475,20 +474,20 @@ SDES items 定义
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
//Source description Chunk
// Source description Chunk
class SdesChunk {
public:
friend class RtcpSdes;
uint32_t ssrc;
//SdesType
// SdesType
uint8_t type;
//text长度股可以为0
// text长度股可以为0
uint8_t txt_len;
//不定长
// 不定长
char text[1];
//最后以RTCP_SDES_END结尾
//只字段为占位字段,不代表真实位置
// 最后以RTCP_SDES_END结尾
// 只字段为占位字段,不代表真实位置
uint8_t end;
public:
@ -515,12 +514,12 @@ private:
void net2Host();
} PACKED;
//Source description
// Source description
class RtcpSdes : public RtcpHeader {
public:
friend class RtcpHeader;
//可能有很多个
// 可能有很多个
SdesChunk chunks;
public:
@ -535,7 +534,7 @@ public:
* SdesChunk对象指针列表
* 使net2Host转换成主机字节序后才可使用此函数
*/
std::vector<SdesChunk*> getChunkList();
std::vector<SdesChunk *> getChunkList();
private:
/**
@ -591,11 +590,11 @@ public:
* @tparam Type
* @return
*/
template<typename Type>
const Type& getFci() const{
template <typename Type>
const Type &getFci() const {
auto fci_data = getFciPtr();
auto fci_len = getFciSize();
Type *fci = (Type *) fci_data;
Type *fci = (Type *)fci_data;
fci->check(fci_len);
return *fci;
}
@ -627,7 +626,7 @@ private:
static std::shared_ptr<RtcpFB> create_l(RtcpType type, int fmt, const void *fci, size_t fci_len);
} PACKED;
//BYE
// BYE
/*
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
@ -687,9 +686,139 @@ private:
void net2Host(size_t size);
} PACKED;
/*
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|reserved | PT=XR=207 | length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SSRC |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
: report blocks :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/*
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| BT=4 | reserved | block length = 2 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NTP timestamp, most significant word |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NTP timestamp, least significant word |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
class RtcpXRRRTR : public RtcpHeader {
public:
friend class RtcpHeader;
uint32_t ssrc;
// 4
uint8_t bt;
uint8_t reserved;
// 2
uint16_t block_length;
// ntp timestamp MSW(in second)
uint32_t ntpmsw;
// ntp timestamp LSW(in picosecond)
uint32_t ntplsw;
private:
/**
*
* 使net2Host转换成主机字节序后才可使用此函数
*/
std::string dumpString() const;
/**
*
* @param size
*/
void net2Host(size_t size);
} PACKED;
/*
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| BT=5 | reserved | block length |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
| SSRC_1 (SSRC of first receiver) | sub-
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
| last RR (LRR) | 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| delay since last RR (DLRR) |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
| SSRC_2 (SSRC of second receiver) | sub-
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
: ... : 2
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*/
class RtcpXRDLRRReportItem {
public:
friend class RtcpXRDLRR;
uint32_t ssrc;
uint32_t lrr;
uint32_t dlrr;
private:
/**
*
* 使net2Host转换成主机字节序后才可使用此函数
*/
std::string dumpString() const;
/**
*
* @param size
*/
void net2Host();
} PACKED;
class RtcpXRDLRR : public RtcpHeader {
public:
friend class RtcpHeader;
uint32_t ssrc;
uint8_t bt;
uint8_t reserved;
uint16_t block_length;
RtcpXRDLRRReportItem items;
/**
* RtcpXRDLRR包RtcpHeader部分()
* @param item_count RtcpXRDLRRReportItem对象个数
* @return RtcpXRDLRR包
*/
static std::shared_ptr<RtcpXRDLRR> create(size_t item_count);
/**
* RtcpXRDLRRReportItem对象指针列表
* 使net2Host转换成主机字节序后才可使用此函数
*/
std::vector<RtcpXRDLRRReportItem *> getItemList();
private:
/**
*
* 使net2Host转换成主机字节序后才可使用此函数
*/
std::string dumpString() const;
/**
*
* @param size
*/
void net2Host(size_t size);
} PACKED;
#if defined(_WIN32)
#pragma pack(pop)
#endif // defined(_WIN32)
} //namespace mediakit
#endif //ZLMEDIAKIT_RTCP_H
} // namespace mediakit
#endif // ZLMEDIAKIT_RTCP_H

View File

@ -14,7 +14,8 @@ using namespace toolkit;
namespace mediakit {
void RtcpContext::onRtp(uint16_t /*seq*/, uint32_t stamp, uint64_t ntp_stamp_ms, uint32_t /*sample_rate*/, size_t bytes) {
void RtcpContext::onRtp(
uint16_t /*seq*/, uint32_t stamp, uint64_t ntp_stamp_ms, uint32_t /*sample_rate*/, size_t bytes) {
++_packets;
_bytes += bytes;
_last_rtp_stamp = stamp;
@ -45,12 +46,16 @@ Buffer::Ptr RtcpContext::createRtcpRR(uint32_t rtcp_ssrc, uint32_t rtp_ssrc) {
throw std::runtime_error("没有实现, rtp发送者尝试发送rr包");
}
Buffer::Ptr RtcpContext::createRtcpXRDLRR(uint32_t rtcp_ssrc, uint32_t rtp_ssrc) {
throw std::runtime_error("没有实现, rtp发送者尝试发送xr dlrr包");
}
////////////////////////////////////////////////////////////////////////////////////
void RtcpContextForSend::onRtcp(RtcpHeader *rtcp) {
switch ((RtcpType) rtcp->pt) {
switch ((RtcpType)rtcp->pt) {
case RtcpType::RTCP_RR: {
auto rtcp_rr = (RtcpRR *) rtcp;
auto rtcp_rr = (RtcpRR *)rtcp;
for (auto item : rtcp_rr->getItemList()) {
if (!item->last_sr_stamp) {
continue;
@ -59,20 +64,34 @@ void RtcpContextForSend::onRtcp(RtcpHeader *rtcp) {
if (it == _sender_report_ntp.end()) {
continue;
}
//发送sr到收到rr之间的时间戳增量
// 发送sr到收到rr之间的时间戳增量
auto ms_inc = getCurrentMillisecond() - it->second;
//rtp接收端收到sr包后回复rr包的延时已转换为毫秒
auto delay_ms = (uint64_t) item->delay_since_last_sr * 1000 / 65536;
auto rtt = (int) (ms_inc - delay_ms);
// rtp接收端收到sr包后回复rr包的延时已转换为毫秒
auto delay_ms = (uint64_t)item->delay_since_last_sr * 1000 / 65536;
auto rtt = (int)(ms_inc - delay_ms);
if (rtt >= 0) {
//rtt不可能小于0
// rtt不可能小于0
_rtt[item->ssrc] = rtt;
//InfoL << "ssrc:" << item->ssrc << ",rtt:" << rtt;
// InfoL << "ssrc:" << item->ssrc << ",rtt:" << rtt;
}
}
break;
}
default: break;
case RtcpType::RTCP_XR: {
auto rtcp_xr = (RtcpXRRRTR *)rtcp;
if (rtcp_xr->bt == 4) {
_xr_xrrtr_recv_last_rr[rtcp_xr->ssrc]
= ((rtcp_xr->ntpmsw & 0xFFFF) << 16) | ((rtcp_xr->ntplsw >> 16) & 0xFFFF);
_xr_rrtr_recv_sys_stamp[rtcp_xr->ssrc] = getCurrentMillisecond();
} else if (rtcp_xr->bt == 5) {
TraceL << "for sender not recive dlrr";
} else {
TraceL << "not support xr bt " << rtcp_xr->bt;
}
break;
}
default:
break;
}
}
@ -89,55 +108,85 @@ Buffer::Ptr RtcpContextForSend::createRtcpSR(uint32_t rtcp_ssrc) {
rtcp->setNtpStamp(_last_ntp_stamp_ms);
rtcp->rtpts = htonl(_last_rtp_stamp);
rtcp->ssrc = htonl(rtcp_ssrc);
rtcp->packet_count = htonl((uint32_t) _packets);
rtcp->octet_count = htonl((uint32_t) _bytes);
rtcp->packet_count = htonl((uint32_t)_packets);
rtcp->octet_count = htonl((uint32_t)_bytes);
//记录上次发送的sender report信息用于后续统计rtt
// 记录上次发送的sender report信息用于后续统计rtt
auto last_sr_lsr = ((ntohl(rtcp->ntpmsw) & 0xFFFF) << 16) | ((ntohl(rtcp->ntplsw) >> 16) & 0xFFFF);
_sender_report_ntp[last_sr_lsr] = getCurrentMillisecond();
if (_sender_report_ntp.size() >= 5) {
//删除最早的sr rtcp
// 删除最早的sr rtcp
_sender_report_ntp.erase(_sender_report_ntp.begin());
}
return RtcpHeader::toBuffer(std::move(rtcp));
}
toolkit::Buffer::Ptr RtcpContextForSend::createRtcpXRDLRR(uint32_t rtcp_ssrc, uint32_t rtp_ssrc) {
auto rtcp = RtcpXRDLRR::create(1);
rtcp->bt = 5;
rtcp->reserved = 0;
rtcp->block_length = htons(3);
rtcp->ssrc = htonl(rtcp_ssrc);
rtcp->items.ssrc = htonl(rtp_ssrc);
if (_xr_xrrtr_recv_last_rr.find(rtp_ssrc) == _xr_xrrtr_recv_last_rr.end()) {
rtcp->items.lrr = 0;
WarnL;
} else {
rtcp->items.lrr = htonl(_xr_xrrtr_recv_last_rr[rtp_ssrc]);
}
if (_xr_rrtr_recv_sys_stamp.find(rtp_ssrc) == _xr_rrtr_recv_sys_stamp.end()) {
rtcp->items.dlrr = 0;
WarnL;
} else {
// now - Last SR time,单位毫秒
auto delay = getCurrentMillisecond() - _xr_rrtr_recv_sys_stamp[rtp_ssrc];
// in units of 1/65536 seconds
auto dlsr = (uint32_t)(delay / 1000.0f * 65536);
rtcp->items.dlrr = htonl(dlsr);
}
return RtcpHeader::toBuffer(std::move(rtcp));
}
////////////////////////////////////////////////////////////////////////////////////
void RtcpContextForRecv::onRtp(uint16_t seq, uint32_t stamp, uint64_t ntp_stamp_ms, uint32_t sample_rate, size_t bytes) {
void RtcpContextForRecv::onRtp(
uint16_t seq, uint32_t stamp, uint64_t ntp_stamp_ms, uint32_t sample_rate, size_t bytes) {
{
//接收者才做复杂的统计运算
// 接收者才做复杂的统计运算
auto sys_stamp = getCurrentMillisecond();
if (_last_rtp_sys_stamp) {
//计算时间戳抖动值
double diff = double((int64_t(sys_stamp) - int64_t(_last_rtp_sys_stamp)) * (sample_rate / double(1000.0))
// 计算时间戳抖动值
double diff = double(
(int64_t(sys_stamp) - int64_t(_last_rtp_sys_stamp)) * (sample_rate / double(1000.0))
- (int64_t(stamp) - int64_t(_last_rtp_stamp)));
if (diff < 0) {
diff = -diff;
}
//抖动单位为采样次数
// 抖动单位为采样次数
_jitter += (diff - _jitter) / 16.0;
} else {
_jitter = 0;
}
if (_last_rtp_seq > 0xFF00 && seq < 0xFF && (!_seq_cycles || _packets - _last_cycle_packets > 0x1FFF)) {
//上次seq大于0xFF00且本次seq小于0xFF
//且未发生回环或者距离上次回环间隔超过0x1FFF个包则认为回环
// 上次seq大于0xFF00且本次seq小于0xFF
// 且未发生回环或者距离上次回环间隔超过0x1FFF个包则认为回环
++_seq_cycles;
_last_cycle_packets = _packets;
_seq_max = seq;
} else if (seq > _seq_max) {
//本次回环前最大seq
// 本次回环前最大seq
_seq_max = seq;
}
if (!_seq_base) {
//记录第一个rtp的seq
// 记录第一个rtp的seq
_seq_base = seq;
} else if (!_seq_cycles && seq < _seq_base) {
//未发生回环那么取最新的seq为基准seq
// 未发生回环那么取最新的seq为基准seq
_seq_base = seq;
}
@ -148,9 +197,9 @@ void RtcpContextForRecv::onRtp(uint16_t seq, uint32_t stamp, uint64_t ntp_stamp_
}
void RtcpContextForRecv::onRtcp(RtcpHeader *rtcp) {
switch ((RtcpType) rtcp->pt) {
switch ((RtcpType)rtcp->pt) {
case RtcpType::RTCP_SR: {
auto rtcp_sr = (RtcpSR *) rtcp;
auto rtcp_sr = (RtcpSR *)rtcp;
/**
last SR timestamp (LSR): 32 bits
The middle 32 bits out of 64 in the NTP timestamp (as explained in
@ -162,7 +211,8 @@ void RtcpContextForRecv::onRtcp(RtcpHeader *rtcp) {
_last_sr_ntp_sys = getCurrentMillisecond();
break;
}
default: break;
default:
break;
}
}
@ -192,7 +242,7 @@ Buffer::Ptr RtcpContextForRecv::createRtcpRR(uint32_t rtcp_ssrc, uint32_t rtp_ss
auto rtcp = RtcpRR::create(1);
rtcp->ssrc = htonl(rtcp_ssrc);
ReportItem *item = (ReportItem *) &rtcp->items;
ReportItem *item = (ReportItem *)&rtcp->items;
item->ssrc = htonl(rtp_ssrc);
uint8_t fraction = 0;
@ -211,9 +261,9 @@ Buffer::Ptr RtcpContextForRecv::createRtcpRR(uint32_t rtcp_ssrc, uint32_t rtp_ss
// now - Last SR time,单位毫秒
auto delay = getCurrentMillisecond() - _last_sr_ntp_sys;
// in units of 1/65536 seconds
auto dlsr = (uint32_t) (delay / 1000.0f * 65536);
auto dlsr = (uint32_t)(delay / 1000.0f * 65536);
item->delay_since_last_sr = htonl(_last_sr_lsr ? dlsr : 0);
return RtcpHeader::toBuffer(rtcp);
}
}//namespace mediakit
} // namespace mediakit

View File

@ -11,9 +11,9 @@
#ifndef ZLMEDIAKIT_RTCPCONTEXT_H
#define ZLMEDIAKIT_RTCPCONTEXT_H
#include <stdint.h>
#include <stddef.h>
#include "Rtcp.h"
#include <stddef.h>
#include <stdint.h>
namespace mediakit {
@ -55,6 +55,13 @@ public:
*/
virtual toolkit::Buffer::Ptr createRtcpSR(uint32_t rtcp_ssrc);
/**
* @brief xr的dlrr包rtt
*
* @return toolkit::Buffer::Ptr
*/
virtual toolkit::Buffer::Ptr createRtcpXRDLRR(uint32_t rtcp_ssrc, uint32_t rtp_ssrc);
/**
* RR rtcp包
* @param rtcp_ssrc rtcp的ssrc
@ -74,11 +81,11 @@ public:
virtual size_t geLostInterval();
protected:
//收到或发送的rtp的字节数
// 收到或发送的rtp的字节数
size_t _bytes = 0;
//收到或发送的rtp的个数
// 收到或发送的rtp的个数
size_t _packets = 0;
//上次的rtp时间戳,毫秒
// 上次的rtp时间戳,毫秒
uint32_t _last_rtp_stamp = 0;
uint64_t _last_ntp_stamp_ms = 0;
};
@ -86,8 +93,11 @@ protected:
class RtcpContextForSend : public RtcpContext {
public:
toolkit::Buffer::Ptr createRtcpSR(uint32_t rtcp_ssrc) override;
void onRtcp(RtcpHeader *rtcp) override;
toolkit::Buffer::Ptr createRtcpXRDLRR(uint32_t rtcp_ssrc, uint32_t rtp_ssrc) override;
/**
* rtt
* @param ssrc rtp ssrc
@ -96,8 +106,11 @@ public:
uint32_t getRtt(uint32_t ssrc) const;
private:
std::map<uint32_t/*ssrc*/, uint32_t/*rtt*/> _rtt;
std::map<uint32_t/*last_sr_lsr*/, uint64_t/*ntp stamp*/> _sender_report_ntp;
std::map<uint32_t /*ssrc*/, uint32_t /*rtt*/> _rtt;
std::map<uint32_t /*last_sr_lsr*/, uint64_t /*ntp stamp*/> _sender_report_ntp;
std::map<uint32_t /*ssrc*/, uint64_t /*xr rrtr sys stamp*/> _xr_rrtr_recv_sys_stamp;
std::map<uint32_t /*ssrc*/, uint32_t /*last rr */> _xr_xrrtr_recv_last_rr;
};
class RtcpContextForRecv : public RtcpContext {
@ -111,29 +124,29 @@ public:
void onRtcp(RtcpHeader *rtcp) override;
private:
//时间戳抖动值
// 时间戳抖动值
double _jitter = 0;
//第一个seq的值
// 第一个seq的值
uint16_t _seq_base = 0;
//rtp最大seq
// rtp最大seq
uint16_t _seq_max = 0;
//rtp回环次数
// rtp回环次数
uint16_t _seq_cycles = 0;
//上次回环发生时记录的rtp包数
// 上次回环发生时记录的rtp包数
size_t _last_cycle_packets = 0;
//上次的seq
// 上次的seq
uint16_t _last_rtp_seq = 0;
//上次的rtp的系统时间戳(毫秒)用于统计抖动
// 上次的rtp的系统时间戳(毫秒)用于统计抖动
uint64_t _last_rtp_sys_stamp = 0;
//上次统计的丢包总数
// 上次统计的丢包总数
size_t _last_lost = 0;
//上次统计应收rtp包总数
// 上次统计应收rtp包总数
size_t _last_expected = 0;
//上次收到sr包时计算出的Last SR timestamp
// 上次收到sr包时计算出的Last SR timestamp
uint32_t _last_sr_lsr = 0;
//上次收到sr时的系统时间戳,单位毫秒
// 上次收到sr时的系统时间戳,单位毫秒
uint64_t _last_sr_ntp_sys = 0;
};
}//namespace mediakit
#endif //ZLMEDIAKIT_RTCPCONTEXT_H
} // namespace mediakit
#endif // ZLMEDIAKIT_RTCPCONTEXT_H

View File

@ -16,16 +16,16 @@ using namespace toolkit;
namespace mediakit {
void FCI_SLI::check(size_t size){
void FCI_SLI::check(size_t size) {
CHECK(size >= kSize);
}
FCI_SLI::FCI_SLI(uint16_t first, uint16_t number, uint8_t pic_id) {
//13 bits
// 13 bits
first &= 0x1FFF;
//13 bits
// 13 bits
number &= 0x1FFF;
//6 bits
// 6 bits
pic_id &= 0x3F;
data = (first << 19) | (number << 6) | pic_id;
data = htonl(data);
@ -49,19 +49,19 @@ string FCI_SLI::dumpString() const {
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void FCI_FIR::check(size_t size){
void FCI_FIR::check(size_t size) {
CHECK(size >= kSize);
}
uint32_t FCI_FIR::getSSRC() const{
uint32_t FCI_FIR::getSSRC() const {
return ntohl(ssrc);
}
uint8_t FCI_FIR::getSeq() const{
uint8_t FCI_FIR::getSeq() const {
return seq_number;
}
uint32_t FCI_FIR::getReserved() const{
uint32_t FCI_FIR::getReserved() const {
return (reserved[0] << 16) | (reserved[1] << 8) | reserved[2];
}
@ -81,7 +81,7 @@ FCI_FIR::FCI_FIR(uint32_t ssrc, uint8_t seq_number, uint32_t reserved) {
static const char kRembMagic[] = "REMB";
void FCI_REMB::check(size_t size){
void FCI_REMB::check(size_t size) {
CHECK(size >= kSize);
CHECK(memcmp(magic, kRembMagic, sizeof(magic)) == 0);
auto num_ssrc = bitrate[0];
@ -93,7 +93,7 @@ string FCI_REMB::create(const vector<uint32_t> &ssrcs, uint32_t bitrate) {
CHECK(ssrcs.size() > 0 && ssrcs.size() <= 0xFF);
string ret;
ret.resize(kSize + ssrcs.size() * 4);
FCI_REMB *thiz = (FCI_REMB *) ret.data();
FCI_REMB *thiz = (FCI_REMB *)ret.data();
memcpy(thiz->magic, kRembMagic, sizeof(magic));
/* bitrate --> BR Exp/BR Mantissa */
@ -101,7 +101,7 @@ string FCI_REMB::create(const vector<uint32_t> &ssrcs, uint32_t bitrate) {
uint8_t exp = 0;
uint32_t mantissa = 0;
for (b = 0; b < 32; b++) {
if (bitrate <= ((uint32_t) 0x3FFFF << b)) {
if (bitrate <= ((uint32_t)0x3FFFF << b)) {
exp = b;
break;
}
@ -110,16 +110,16 @@ string FCI_REMB::create(const vector<uint32_t> &ssrcs, uint32_t bitrate) {
b = 31;
}
mantissa = bitrate >> b;
//Num SSRC (8 bits)
// Num SSRC (8 bits)
thiz->bitrate[0] = ssrcs.size() & 0xFF;
//BR Exp (6 bits)/BR Mantissa (18 bits)
thiz->bitrate[1] = (uint8_t) ((exp << 2) + ((mantissa >> 16) & 0x03));
//BR Mantissa (18 bits)
thiz->bitrate[2] = (uint8_t) (mantissa >> 8);
//BR Mantissa (18 bits)
thiz->bitrate[3] = (uint8_t) (mantissa);
// BR Exp (6 bits)/BR Mantissa (18 bits)
thiz->bitrate[1] = (uint8_t)((exp << 2) + ((mantissa >> 16) & 0x03));
// BR Mantissa (18 bits)
thiz->bitrate[2] = (uint8_t)(mantissa >> 8);
// BR Mantissa (18 bits)
thiz->bitrate[3] = (uint8_t)(mantissa);
//设置ssrc列表
// 设置ssrc列表
int i = 0;
for (auto ssrc : ssrcs) {
thiz->ssrc_feedback[i++] = htonl(ssrc);
@ -149,7 +149,7 @@ vector<uint32_t> FCI_REMB::getSSRC() {
string FCI_REMB::dumpString() const {
_StrPrinter printer;
printer << "bitrate:" << getBitRate() << ", ssrc:";
for (auto &ssrc : ((FCI_REMB *) this)->getSSRC()) {
for (auto &ssrc : ((FCI_REMB *)this)->getSSRC()) {
printer << ssrc << " ";
}
return std::move(printer);
@ -171,7 +171,7 @@ FCI_NACK::FCI_NACK(uint16_t pid_h, const vector<bool> &type) {
pid = htons(pid_h);
}
void FCI_NACK::check(size_t size){
void FCI_NACK::check(size_t size) {
CHECK(size >= kSize);
}
@ -186,7 +186,7 @@ uint16_t FCI_NACK::getBlp() const {
vector<bool> FCI_NACK::getBitArray() const {
vector<bool> ret;
ret.resize(kBitSize + 1);
//nack第一个包丢包
// nack第一个包丢包
ret[0] = true;
auto blp_h = getBlp();
@ -220,25 +220,25 @@ public:
// |T| S | Run Length |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#if __BYTE_ORDER == __BIG_ENDIAN
uint16_t type: 1;
uint16_t symbol: 2;
uint16_t run_length_high: 5;
uint16_t type : 1;
uint16_t symbol : 2;
uint16_t run_length_high : 5;
#else
// Run Length 高5位
uint16_t run_length_high: 5;
//参考SymbolStatus定义
uint16_t symbol: 2;
//固定为0
uint16_t type: 1;
uint16_t run_length_high : 5;
// 参考SymbolStatus定义
uint16_t symbol : 2;
// 固定为0
uint16_t type : 1;
#endif
// Run Length 低8位
uint16_t run_length_low: 8;
uint16_t run_length_low : 8;
//获取Run Length
// 获取Run Length
uint16_t getRunLength() const;
//构造函数
// 构造函数
RunLengthChunk(SymbolStatus status, uint16_t run_length);
//打印本对象
// 打印本对象
string dumpString() const;
} PACKED;
@ -254,7 +254,7 @@ uint16_t RunLengthChunk::getRunLength() const {
return run_length_high << 8 | run_length_low;
}
string RunLengthChunk::dumpString() const{
string RunLengthChunk::dumpString() const {
_StrPrinter printer;
printer << "run length chunk, symbol:" << (int)symbol << ", run length:" << getRunLength();
return std::move(printer);
@ -271,30 +271,30 @@ public:
// |T|S| symbol list |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#if __BYTE_ORDER == __BIG_ENDIAN
uint16_t type: 1;
uint16_t symbol: 1;
uint16_t symbol_list_high: 6;
uint16_t type : 1;
uint16_t symbol : 1;
uint16_t symbol_list_high : 6;
#else
// symbol_list 高6位
uint16_t symbol_list_high: 6;
//symbol_list中元素是1个还是2个bit
uint16_t symbol: 1;
//固定为1
uint16_t type: 1;
uint16_t symbol_list_high : 6;
// symbol_list中元素是1个还是2个bit
uint16_t symbol : 1;
// 固定为1
uint16_t type : 1;
#endif
// symbol_list 低8位
uint16_t symbol_list_low: 8;
uint16_t symbol_list_low : 8;
//获取symbollist
// 获取symbollist
vector<SymbolStatus> getSymbolList() const;
//构造函数
// 构造函数
StatusVecChunk(bool symbol_bit, const vector<SymbolStatus> &status);
//打印本对象
// 打印本对象
string dumpString() const;
} PACKED;
StatusVecChunk::StatusVecChunk(bool symbol_bit, const vector<SymbolStatus> &status) {
CHECK( status.size() << symbol_bit <= 14);
CHECK(status.size() << symbol_bit <= 14);
uint16_t value = 0;
type = 1;
symbol = symbol_bit;
@ -303,31 +303,31 @@ StatusVecChunk::StatusVecChunk(bool symbol_bit, const vector<SymbolStatus> &stat
CHECK(item <= SymbolStatus::reserved);
if (!symbol) {
CHECK(item <= SymbolStatus::small_delta);
value |= (int) item << i;
value |= (int)item << i;
--i;
} else {
value |= (int) item << (i - 1);
value |= (int)item << (i - 1);
i -= 2;
}
}
symbol_list_low = value & 0xFF;
symbol_list_high = (value >> 8 ) & 0x3F;
symbol_list_high = (value >> 8) & 0x3F;
}
vector<SymbolStatus> StatusVecChunk::getSymbolList() const {
CHECK(type == 1);
vector<SymbolStatus> ret;
auto thiz = ntohs(*((uint16_t *) this));
auto thiz = ntohs(*((uint16_t *)this));
if (symbol == 0) {
//s = 0 时表示symbollist的每一个bit能表示一个数据包的到达状态
// s = 0 时表示symbollist的每一个bit能表示一个数据包的到达状态
for (int i = 13; i >= 0; --i) {
SymbolStatus status = (SymbolStatus) ((bool) (thiz & (1 << i)));
SymbolStatus status = (SymbolStatus)((bool)(thiz & (1 << i)));
ret.emplace_back(status);
}
} else {
//s = 1 时表示symbollist每两个bit表示一个数据包的状态
// s = 1 时表示symbollist每两个bit表示一个数据包的状态
for (int i = 12; i >= 0; i -= 2) {
SymbolStatus status = (SymbolStatus) ((thiz & (3 << i)) >> i);
SymbolStatus status = (SymbolStatus)((thiz & (3 << i)) >> i);
ret.emplace_back(status);
}
}
@ -336,17 +336,17 @@ vector<SymbolStatus> StatusVecChunk::getSymbolList() const {
string StatusVecChunk::dumpString() const {
_StrPrinter printer;
printer << "status vector chunk, symbol:" << (int) symbol << ", symbol list:";
printer << "status vector chunk, symbol:" << (int)symbol << ", symbol list:";
auto vec = getSymbolList();
for (auto &item : vec) {
printer << (int) item << " ";
printer << (int)item << " ";
}
return std::move(printer);
}
///////////////////////////////////////////////////////
void FCI_TWCC::check(size_t size){
void FCI_TWCC::check(size_t size) {
CHECK(size >= kSize);
}
@ -365,7 +365,7 @@ uint32_t FCI_TWCC::getReferenceTime() const {
ret |= ref_time[2];
return ret;
}
//3.1.5. Receive Delta
// 3.1.5. Receive Delta
//
// Deltas are represented as multiples of 250us:
//
@ -392,33 +392,33 @@ uint32_t FCI_TWCC::getReferenceTime() const {
// be represented. With a 1200 bytes/packet payload, that amounts to
// 38.4 Mbit/s payload bandwidth.
static int16_t getRecvDelta(SymbolStatus status, uint8_t *&ptr, const uint8_t *end){
static int16_t getRecvDelta(SymbolStatus status, uint8_t *&ptr, const uint8_t *end) {
int16_t delta = 0;
switch (status) {
case SymbolStatus::not_received : {
//丢包, recv delta为0个字节
case SymbolStatus::not_received: {
// 丢包, recv delta为0个字节
break;
}
case SymbolStatus::small_delta : {
case SymbolStatus::small_delta: {
CHECK(ptr + 1 <= end);
//时间戳增量小于256 recv delta为1个字节
// 时间戳增量小于256 recv delta为1个字节
delta = *ptr;
ptr += 1;
break;
}
case SymbolStatus::large_delta : {
case SymbolStatus::large_delta: {
CHECK(ptr + 2 <= end);
//时间戳增量256~65535间recv delta为2个字节
// 时间戳增量256~65535间recv delta为2个字节
delta = *ptr << 8 | *(ptr + 1);
ptr += 2;
break;
}
case SymbolStatus::reserved : {
//没有时间戳
case SymbolStatus::reserved: {
// 没有时间戳
break;
}
default:
//这个逻辑分支不可达到
// 这个逻辑分支不可达到
CHECK(0);
break;
}
@ -427,25 +427,25 @@ static int16_t getRecvDelta(SymbolStatus status, uint8_t *&ptr, const uint8_t *e
FCI_TWCC::TwccPacketStatus FCI_TWCC::getPacketChunkList(size_t total_size) const {
TwccPacketStatus ret;
auto ptr = (uint8_t *) this + kSize;
auto end = (uint8_t *) this + total_size;
auto ptr = (uint8_t *)this + kSize;
auto end = (uint8_t *)this + total_size;
CHECK(ptr < end);
auto seq = getBaseSeq();
auto rtp_count = getPacketCount();
for (uint8_t i = 0; i < rtp_count;) {
CHECK(ptr + RunLengthChunk::kSize <= end);
RunLengthChunk *chunk = (RunLengthChunk *) ptr;
RunLengthChunk *chunk = (RunLengthChunk *)ptr;
if (!chunk->type) {
//RunLengthChunk
// RunLengthChunk
for (auto j = 0; j < chunk->getRunLength(); ++j) {
ret.emplace(seq++, std::make_pair((SymbolStatus) chunk->symbol, 0));
ret.emplace(seq++, std::make_pair((SymbolStatus)chunk->symbol, 0));
if (++i >= rtp_count) {
break;
}
}
} else {
//StatusVecChunk
StatusVecChunk *chunk = (StatusVecChunk *) ptr;
// StatusVecChunk
StatusVecChunk *chunk = (StatusVecChunk *)ptr;
for (auto &symbol : chunk->getSymbolList()) {
ret.emplace(seq++, std::make_pair(symbol, 0));
if (++i >= rtp_count) {
@ -465,23 +465,29 @@ FCI_TWCC::TwccPacketStatus FCI_TWCC::getPacketChunkList(size_t total_size) const
string FCI_TWCC::dumpString(size_t total_size) const {
_StrPrinter printer;
auto map = getPacketChunkList(total_size);
printer << "twcc fci, base_seq:" << getBaseSeq() << ", pkt_status_count:" << getPacketCount() << ", ref time:" << getReferenceTime() << ", fb count:" << (int)fb_pkt_count << "\n";
printer << "twcc fci, base_seq:" << getBaseSeq() << ", pkt_status_count:" << getPacketCount()
<< ", ref time:" << getReferenceTime() << ", fb count:" << (int)fb_pkt_count << "\n";
for (auto &pr : map) {
printer << "rtp seq:" << pr.first <<", packet status:" << (int)(pr.second.first) << ", delta:" << pr.second.second << "\n";
printer << "rtp seq:" << pr.first << ", packet status:" << (int)(pr.second.first)
<< ", delta:" << pr.second.second << "\n";
}
return std::move(printer);
}
static void appendDeltaString(string &delta_str, FCI_TWCC::TwccPacketStatus &status, int count){
static void appendDeltaString(string &delta_str, FCI_TWCC::TwccPacketStatus &status, int count) {
for (auto it = status.begin(); it != status.end() && count--;) {
switch (it->second.first) {
//large delta模式先写高字节再写低字节
case SymbolStatus::large_delta: delta_str.push_back((it->second.second >> 8) & 0xFF);
//small delta模式只写低字节
case SymbolStatus::small_delta: delta_str.push_back(it->second.second & 0xFF); break;
default: break;
// large delta模式先写高字节再写低字节
case SymbolStatus::large_delta:
delta_str.push_back((it->second.second >> 8) & 0xFF);
// small delta模式只写低字节
case SymbolStatus::small_delta:
delta_str.push_back(it->second.second & 0xFF);
break;
default:
break;
}
//移除已经处理过的数据
// 移除已经处理过的数据
it = status.erase(it);
}
}
@ -489,7 +495,7 @@ static void appendDeltaString(string &delta_str, FCI_TWCC::TwccPacketStatus &sta
string FCI_TWCC::create(uint32_t ref_time, uint8_t fb_pkt_count, TwccPacketStatus &status) {
string fci;
fci.resize(FCI_TWCC::kSize);
FCI_TWCC *ptr = (FCI_TWCC *) (fci.data());
FCI_TWCC *ptr = (FCI_TWCC *)(fci.data());
ptr->base_seq = htons(status.begin()->first);
ptr->pkt_status_count = htons(status.size());
ptr->fb_pkt_count = fb_pkt_count;
@ -500,21 +506,21 @@ string FCI_TWCC::create(uint32_t ref_time, uint8_t fb_pkt_count, TwccPacketStatu
string delta_str;
while (!status.empty()) {
{
//第一个rtp的状态
// 第一个rtp的状态
auto symbol = status.begin()->second.first;
int16_t count = 0;
for (auto &pr : status) {
if (pr.second.first != symbol) {
//状态发送变更了本chunk结束
// 状态发送变更了本chunk结束
break;
}
if (++count >= (0xFFFF >> 3)) {
//RunLengthChunk 13个bit表明rtp个数最多可以表述0xFFFF >> 3个rtp状态
// RunLengthChunk 13个bit表明rtp个数最多可以表述0xFFFF >> 3个rtp状态
break;
}
}
if (count >= 7) {
//连续状态相同个数大于6个时使用RunLengthChunk模式比较节省带宽
// 连续状态相同个数大于6个时使用RunLengthChunk模式比较节省带宽
RunLengthChunk chunk(symbol, count);
fci.append((char *)&chunk, RunLengthChunk::kSize);
appendDeltaString(delta_str, status, count);
@ -523,20 +529,20 @@ string FCI_TWCC::create(uint32_t ref_time, uint8_t fb_pkt_count, TwccPacketStatu
}
{
//StatusVecChunk模式
//symbol_list中元素是1个bit
// StatusVecChunk模式
// symbol_list中元素是1个bit
auto symbol = 0;
vector<SymbolStatus> vec;
for (auto &pr : status) {
vec.push_back(pr.second.first);
if (pr.second.first >= SymbolStatus::large_delta) {
//symbol_list中元素是2个bit
// symbol_list中元素是2个bit
symbol = 1;
}
if (vec.size() << symbol >= 14) {
//symbol为0时最多存放14个rtp的状态
//symbol为1时最多存放7个rtp的状态
// symbol为0时最多存放14个rtp的状态
// symbol为1时最多存放7个rtp的状态
break;
}
}
@ -547,9 +553,9 @@ string FCI_TWCC::create(uint32_t ref_time, uint8_t fb_pkt_count, TwccPacketStatu
}
}
//recv delta部分
// recv delta部分
fci.append(delta_str);
return fci;
}
}//namespace mediakit
} // namespace mediakit

View File

@ -11,21 +11,21 @@
#ifndef ZLMEDIAKIT_RTCPFCI_H
#define ZLMEDIAKIT_RTCPFCI_H
#include "Rtcp.h"
#include "Common/config.h"
#include "Rtcp.h"
namespace mediakit {
/////////////////////////////////////////// PSFB ////////////////////////////////////////////////////
//PSFB fmt = 2
//https://tools.ietf.org/html/rfc4585#section-6.3.2.2
// PSFB fmt = 2
// https://tools.ietf.org/html/rfc4585#section-6.3.2.2
// 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
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | First | Number | PictureID |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//First: 13 bits
// First: 13 bits
// The macroblock (MB) address of the first lost macroblock. The MB
// numbering is done such that the macroblock in the upper left
// corner of the picture is considered macroblock number 1 and the
@ -101,8 +101,8 @@ public:
} PACKED;
#endif
//PSFB fmt = 4
//https://tools.ietf.org/html/rfc5104#section-4.3.1.1
// PSFB fmt = 4
// https://tools.ietf.org/html/rfc5104#section-4.3.1.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
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@ -188,8 +188,8 @@ private:
#endif
//PSFB fmt = 15
//https://tools.ietf.org/html/draft-alvestrand-rmcat-remb-03
// PSFB fmt = 15
// https://tools.ietf.org/html/draft-alvestrand-rmcat-remb-03
// 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
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@ -227,9 +227,9 @@ public:
std::vector<uint32_t> getSSRC();
private:
//Unique identifier 'R' 'E' 'M' 'B'
// Unique identifier 'R' 'E' 'M' 'B'
char magic[4];
//Num SSRC (8 bits)/BR Exp (6 bits)/ BR Mantissa (18 bits)
// Num SSRC (8 bits)/BR Exp (6 bits)/ BR Mantissa (18 bits)
uint8_t bitrate[4];
// SSRC feedback (32 bits) Consists of one or more SSRC entries which
// this feedback message applies to.
@ -238,8 +238,8 @@ private:
/////////////////////////////////////////// RTPFB ////////////////////////////////////////////////////
//RTPFB fmt = 1
//https://tools.ietf.org/html/rfc4585#section-6.2.1
// RTPFB fmt = 1
// https://tools.ietf.org/html/rfc4585#section-6.2.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
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@ -255,7 +255,7 @@ public:
void check(size_t size);
uint16_t getPid() const;
uint16_t getBlp() const;
//返回丢包列表总长度17第一个包必丢
// 返回丢包列表总长度17第一个包必丢
// TODO: replace std::bitset
std::vector<bool> getBitArray() const;
std::string dumpString() const;
@ -318,20 +318,20 @@ public:
} PACKED;
#endif
enum class SymbolStatus : uint8_t{
//Packet not received
enum class SymbolStatus : uint8_t {
// Packet not received
not_received = 0,
//Packet received, small delta 所谓small detal是指能用一个字节表示的数值
// Packet received, small delta 所谓small detal是指能用一个字节表示的数值
small_delta = 1,
// Packet received, large ornegative delta large即是能用两个字节表示的数值
large_delta = 2,
//Reserved
// Reserved
reserved = 3
};
//RTPFB fmt = 15
//https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#section-3.1
//https://zhuanlan.zhihu.com/p/206656654
// RTPFB fmt = 15
// https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#section-3.1
// https://zhuanlan.zhihu.com/p/206656654
// 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
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@ -351,14 +351,15 @@ enum class SymbolStatus : uint8_t{
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | recv delta | recv delta | zero padding |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
class FCI_TWCC{
class FCI_TWCC {
public:
static size_t constexpr kSize = 8;
using TwccPacketStatus = std::map<uint16_t/*rtp ext seq*/, std::pair<SymbolStatus, int16_t/*recv delta,单位为250us*/> >;
using TwccPacketStatus
= std::map<uint16_t /*rtp ext seq*/, std::pair<SymbolStatus, int16_t /*recv delta,单位为250us*/>>;
void check(size_t size);
std::string dumpString(size_t total_size) const;
uint16_t getBaseSeq() const;
//单位64ms
// 单位64ms
uint32_t getReferenceTime() const;
uint16_t getPacketCount() const;
TwccPacketStatus getPacketChunkList(size_t total_size) const;
@ -366,15 +367,15 @@ public:
static std::string create(uint32_t ref_time, uint8_t fb_pkt_count, TwccPacketStatus &status);
private:
//base sequence number,基础序号,本次反馈的第一个包的序号;也就是RTP扩展头的序列号
// base sequence number,基础序号,本次反馈的第一个包的序号;也就是RTP扩展头的序列号
uint16_t base_seq;
//packet status count, 包个数,本次反馈包含多少个包的状态;从基础序号开始算
// packet status count, 包个数,本次反馈包含多少个包的状态;从基础序号开始算
uint16_t pkt_status_count;
//reference time,基准时间,绝对时间;计算该包中每个媒体包的到达时间都要基于这个基准时间计算
// reference time,基准时间,绝对时间;计算该包中每个媒体包的到达时间都要基于这个基准时间计算
uint8_t ref_time[3];
//feedback packet count,反馈包号,本包是第几个transport-cc包每次加1 |
// feedback packet count,反馈包号,本包是第几个transport-cc包每次加1 |
uint8_t fb_pkt_count;
} PACKED;
} //namespace mediakit
#endif //ZLMEDIAKIT_RTCPFCI_H
} // namespace mediakit
#endif // ZLMEDIAKIT_RTCPFCI_H

File diff suppressed because it is too large Load Diff