mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-10-31 08:39:34 +08:00
commit
6aa1c239b8
@ -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";
|
||||
break;
|
||||
}
|
||||
case RtcpType::RTCP_PSFB : {
|
||||
printer << "report_count:" << psfbTypeToStr((PSFBType) report_count) << "\r\n";
|
||||
break;
|
||||
}
|
||||
default : {
|
||||
printer << "report_count:" << report_count << "\r\n";
|
||||
break;
|
||||
}
|
||||
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";
|
||||
break;
|
||||
}
|
||||
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) {
|
||||
case RtcpType::RTCP_SR: {
|
||||
RtcpSR *rtcp = (RtcpSR *) this;
|
||||
return rtcp->dumpString();
|
||||
}
|
||||
switch ((RtcpType)pt) {
|
||||
case RtcpType::RTCP_SR: {
|
||||
RtcpSR *rtcp = (RtcpSR *)this;
|
||||
return rtcp->dumpString();
|
||||
}
|
||||
|
||||
case RtcpType::RTCP_RR: {
|
||||
RtcpRR *rtcp = (RtcpRR *) this;
|
||||
return rtcp->dumpString();
|
||||
}
|
||||
case RtcpType::RTCP_RR: {
|
||||
RtcpRR *rtcp = (RtcpRR *)this;
|
||||
return rtcp->dumpString();
|
||||
}
|
||||
|
||||
case RtcpType::RTCP_SDES: {
|
||||
RtcpSdes *rtcp = (RtcpSdes *) this;
|
||||
return rtcp->dumpString();
|
||||
}
|
||||
case RtcpType::RTCP_SDES: {
|
||||
RtcpSdes *rtcp = (RtcpSdes *)this;
|
||||
return rtcp->dumpString();
|
||||
}
|
||||
|
||||
case RtcpType::RTCP_RTPFB:
|
||||
case RtcpType::RTCP_PSFB: {
|
||||
RtcpFB *rtcp = (RtcpFB *) this;
|
||||
return rtcp->dumpString();
|
||||
}
|
||||
case RtcpType::RTCP_RTPFB:
|
||||
case RtcpType::RTCP_PSFB: {
|
||||
RtcpFB *rtcp = (RtcpFB *)this;
|
||||
return rtcp->dumpString();
|
||||
}
|
||||
|
||||
case RtcpType::RTCP_BYE: {
|
||||
RtcpBye *rtcp = (RtcpBye *) this;
|
||||
return rtcp->dumpString();
|
||||
}
|
||||
case RtcpType::RTCP_BYE: {
|
||||
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) {
|
||||
case RtcpType::RTCP_SR: {
|
||||
RtcpSR *sr = (RtcpSR *) this;
|
||||
sr->net2Host(len);
|
||||
break;
|
||||
}
|
||||
switch ((RtcpType)pt) {
|
||||
case RtcpType::RTCP_SR: {
|
||||
RtcpSR *sr = (RtcpSR *)this;
|
||||
sr->net2Host(len);
|
||||
break;
|
||||
}
|
||||
|
||||
case RtcpType::RTCP_RR: {
|
||||
RtcpRR *rr = (RtcpRR *) this;
|
||||
rr->net2Host(len);
|
||||
break;
|
||||
}
|
||||
case RtcpType::RTCP_RR: {
|
||||
RtcpRR *rr = (RtcpRR *)this;
|
||||
rr->net2Host(len);
|
||||
break;
|
||||
}
|
||||
|
||||
case RtcpType::RTCP_SDES: {
|
||||
RtcpSdes *sdes = (RtcpSdes *) this;
|
||||
sdes->net2Host(len);
|
||||
break;
|
||||
}
|
||||
case RtcpType::RTCP_SDES: {
|
||||
RtcpSdes *sdes = (RtcpSdes *)this;
|
||||
sdes->net2Host(len);
|
||||
break;
|
||||
}
|
||||
|
||||
case RtcpType::RTCP_RTPFB:
|
||||
case RtcpType::RTCP_PSFB: {
|
||||
RtcpFB *fb = (RtcpFB *) this;
|
||||
fb->net2Host(len);
|
||||
break;
|
||||
}
|
||||
case RtcpType::RTCP_RTPFB:
|
||||
case RtcpType::RTCP_PSFB: {
|
||||
RtcpFB *fb = (RtcpFB *)this;
|
||||
fb->net2Host(len);
|
||||
break;
|
||||
}
|
||||
|
||||
case RtcpType::RTCP_BYE: {
|
||||
RtcpBye *bye = (RtcpBye *) this;
|
||||
bye->net2Host(len);
|
||||
break;
|
||||
case RtcpType::RTCP_BYE: {
|
||||
RtcpBye *bye = (RtcpBye *)this;
|
||||
bye->net2Host(len);
|
||||
break;
|
||||
}
|
||||
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");
|
||||
}
|
||||
|
||||
default: throw std::runtime_error(StrPrinter << "未处理的rtcp包:" << rtcpTypeToStr((RtcpType) this->pt));
|
||||
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";
|
||||
@ -309,17 +328,19 @@ string RtcpSR::dumpString() const {
|
||||
return std::move(printer);
|
||||
}
|
||||
|
||||
#define CHECK_MIN_SIZE(size, kMinSize) \
|
||||
if (size < kMinSize) { \
|
||||
throw std::out_of_range(StrPrinter << rtcpTypeToStr((RtcpType)pt) << " 长度不足:" << size << " < " << kMinSize); \
|
||||
}
|
||||
#define CHECK_MIN_SIZE(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; \
|
||||
report_count = item_count; \
|
||||
}
|
||||
#define CHECK_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 : {
|
||||
auto &fci = getFci<FCI_SLI>();
|
||||
printer << "fci:" << psfbTypeToStr((PSFBType) report_count) << " " << fci.dumpString();
|
||||
break;
|
||||
}
|
||||
case PSFBType::RTCP_PSFB_PLI : {
|
||||
getFciSize();
|
||||
printer << "fci:" << psfbTypeToStr((PSFBType) report_count);
|
||||
break;
|
||||
}
|
||||
|
||||
case PSFBType::RTCP_PSFB_FIR : {
|
||||
auto &fci = getFci<FCI_FIR>();
|
||||
printer << "fci:" << psfbTypeToStr((PSFBType) report_count) << " " << fci.dumpString();
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
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();
|
||||
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;
|
||||
}
|
||||
}
|
||||
case PSFBType::RTCP_PSFB_PLI: {
|
||||
getFciSize();
|
||||
printer << "fci:" << psfbTypeToStr((PSFBType)report_count);
|
||||
break;
|
||||
}
|
||||
default: /*不可达*/ assert(0); break;
|
||||
|
||||
case PSFBType::RTCP_PSFB_FIR: {
|
||||
auto &fci = getFci<FCI_FIR>();
|
||||
printer << "fci:" << psfbTypeToStr((PSFBType)report_count) << " " << fci.dumpString();
|
||||
break;
|
||||
}
|
||||
|
||||
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());
|
||||
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
|
421
src/Rtcp/Rtcp.h
421
src/Rtcp/Rtcp.h
@ -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,115 +23,115 @@ namespace mediakit {
|
||||
#pragma pack(push, 1)
|
||||
#endif // defined(_WIN32)
|
||||
|
||||
//http://www.networksorcery.com/enp/protocol/rtcp.htm
|
||||
#define RTCP_PT_MAP(XX) \
|
||||
XX(RTCP_FIR, 192) \
|
||||
XX(RTCP_NACK, 193) \
|
||||
XX(RTCP_SMPTETC, 194) \
|
||||
XX(RTCP_IJ, 195) \
|
||||
XX(RTCP_SR, 200) \
|
||||
XX(RTCP_RR, 201) \
|
||||
XX(RTCP_SDES, 202) \
|
||||
XX(RTCP_BYE, 203) \
|
||||
XX(RTCP_APP, 204) \
|
||||
XX(RTCP_RTPFB, 205) \
|
||||
XX(RTCP_PSFB, 206) \
|
||||
XX(RTCP_XR, 207) \
|
||||
XX(RTCP_AVB, 208) \
|
||||
XX(RTCP_RSI, 209) \
|
||||
XX(RTCP_TOKEN, 210)
|
||||
// http://www.networksorcery.com/enp/protocol/rtcp.htm
|
||||
#define RTCP_PT_MAP(XX) \
|
||||
XX(RTCP_FIR, 192) \
|
||||
XX(RTCP_NACK, 193) \
|
||||
XX(RTCP_SMPTETC, 194) \
|
||||
XX(RTCP_IJ, 195) \
|
||||
XX(RTCP_SR, 200) \
|
||||
XX(RTCP_RR, 201) \
|
||||
XX(RTCP_SDES, 202) \
|
||||
XX(RTCP_BYE, 203) \
|
||||
XX(RTCP_APP, 204) \
|
||||
XX(RTCP_RTPFB, 205) \
|
||||
XX(RTCP_PSFB, 206) \
|
||||
XX(RTCP_XR, 207) \
|
||||
XX(RTCP_AVB, 208) \
|
||||
XX(RTCP_RSI, 209) \
|
||||
XX(RTCP_TOKEN, 210)
|
||||
|
||||
//https://tools.ietf.org/html/rfc3550#section-6.5
|
||||
#define SDES_TYPE_MAP(XX) \
|
||||
XX(RTCP_SDES_END, 0) \
|
||||
XX(RTCP_SDES_CNAME, 1) \
|
||||
XX(RTCP_SDES_NAME, 2) \
|
||||
XX(RTCP_SDES_EMAIL, 3) \
|
||||
XX(RTCP_SDES_PHONE, 4) \
|
||||
XX(RTCP_SDES_LOC, 5) \
|
||||
XX(RTCP_SDES_TOOL, 6) \
|
||||
XX(RTCP_SDES_NOTE, 7) \
|
||||
XX(RTCP_SDES_PRIVATE, 8)
|
||||
// https://tools.ietf.org/html/rfc3550#section-6.5
|
||||
#define SDES_TYPE_MAP(XX) \
|
||||
XX(RTCP_SDES_END, 0) \
|
||||
XX(RTCP_SDES_CNAME, 1) \
|
||||
XX(RTCP_SDES_NAME, 2) \
|
||||
XX(RTCP_SDES_EMAIL, 3) \
|
||||
XX(RTCP_SDES_PHONE, 4) \
|
||||
XX(RTCP_SDES_LOC, 5) \
|
||||
XX(RTCP_SDES_TOOL, 6) \
|
||||
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.
|
||||
// Payload-Specific FB messages are identified by the value PT=PSFB as
|
||||
// RTCP message type.
|
||||
//
|
||||
// Three payload-specific FB messages are defined so far plus an
|
||||
// application layer FB message. They are identified by means of the
|
||||
// FMT parameter as follows:
|
||||
// Three payload-specific FB messages are defined so far plus an
|
||||
// application layer FB message. They are identified by means of the
|
||||
// FMT parameter as follows:
|
||||
//
|
||||
// 0: unassigned
|
||||
// 1: Picture Loss Indication (PLI)
|
||||
// 2: Slice Loss Indication (SLI)
|
||||
// 3: Reference Picture Selection Indication (RPSI)
|
||||
// 4: FIR https://tools.ietf.org/html/rfc5104#section-4.3.1.1
|
||||
// 5: TSTR https://tools.ietf.org/html/rfc5104#section-4.3.2.1
|
||||
// 6: TSTN https://tools.ietf.org/html/rfc5104#section-4.3.2.1
|
||||
// 7: VBCM https://tools.ietf.org/html/rfc5104#section-4.3.4.1
|
||||
// 8-14: unassigned
|
||||
// 15: REMB / Application layer FB (AFB) message, https://tools.ietf.org/html/draft-alvestrand-rmcat-remb-03
|
||||
// 16-30: unassigned
|
||||
// 31: reserved for future expansion of the sequence number space
|
||||
#define PSFB_TYPE_MAP(XX) \
|
||||
XX(RTCP_PSFB_PLI, 1) \
|
||||
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_VBCM, 7) \
|
||||
XX(RTCP_PSFB_REMB, 15)
|
||||
// 0: unassigned
|
||||
// 1: Picture Loss Indication (PLI)
|
||||
// 2: Slice Loss Indication (SLI)
|
||||
// 3: Reference Picture Selection Indication (RPSI)
|
||||
// 4: FIR https://tools.ietf.org/html/rfc5104#section-4.3.1.1
|
||||
// 5: TSTR https://tools.ietf.org/html/rfc5104#section-4.3.2.1
|
||||
// 6: TSTN https://tools.ietf.org/html/rfc5104#section-4.3.2.1
|
||||
// 7: VBCM https://tools.ietf.org/html/rfc5104#section-4.3.4.1
|
||||
// 8-14: unassigned
|
||||
// 15: REMB / Application layer FB (AFB) message, https://tools.ietf.org/html/draft-alvestrand-rmcat-remb-03
|
||||
// 16-30: unassigned
|
||||
// 31: reserved for future expansion of the sequence number space
|
||||
#define PSFB_TYPE_MAP(XX) \
|
||||
XX(RTCP_PSFB_PLI, 1) \
|
||||
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_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.
|
||||
// Transport layer FB messages are identified by the value RTPFB as RTCP
|
||||
// message type.
|
||||
//
|
||||
// A single general purpose transport layer FB message is defined in
|
||||
// this document: Generic NACK. It is identified by means of the FMT
|
||||
// parameter as follows:
|
||||
// A single general purpose transport layer FB message is defined in
|
||||
// this document: Generic NACK. It is identified by means of the FMT
|
||||
// parameter as follows:
|
||||
//
|
||||
// 0: unassigned
|
||||
// 1: Generic NACK
|
||||
// 2: reserved https://tools.ietf.org/html/rfc5104#section-4.2
|
||||
// 3: TMMBR https://tools.ietf.org/html/rfc5104#section-4.2.1.1
|
||||
// 4: TMMBN https://tools.ietf.org/html/rfc5104#section-4.2.2.1
|
||||
// 5-14: unassigned
|
||||
// 15 transport-cc https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01
|
||||
// 16-30: unassigned
|
||||
// 31: reserved for future expansion of the identifier number space
|
||||
#define RTPFB_TYPE_MAP(XX) \
|
||||
XX(RTCP_RTPFB_NACK, 1) \
|
||||
XX(RTCP_RTPFB_TMMBR, 3) \
|
||||
XX(RTCP_RTPFB_TMMBN, 4) \
|
||||
XX(RTCP_RTPFB_TWCC, 15)
|
||||
// 0: unassigned
|
||||
// 1: Generic NACK
|
||||
// 2: reserved https://tools.ietf.org/html/rfc5104#section-4.2
|
||||
// 3: TMMBR https://tools.ietf.org/html/rfc5104#section-4.2.1.1
|
||||
// 4: TMMBN https://tools.ietf.org/html/rfc5104#section-4.2.2.1
|
||||
// 5-14: unassigned
|
||||
// 15 transport-cc https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01
|
||||
// 16-30: unassigned
|
||||
// 31: reserved for future expansion of the identifier number space
|
||||
#define RTPFB_TYPE_MAP(XX) \
|
||||
XX(RTCP_RTPFB_NACK, 1) \
|
||||
XX(RTCP_RTPFB_TMMBR, 3) \
|
||||
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,13 +357,13 @@ public:
|
||||
* 获取ReportItem对象指针列表
|
||||
* 使用net2Host转换成主机字节序后才可使用此函数
|
||||
*/
|
||||
std::vector<ReportItem*> getItemList();
|
||||
std::vector<ReportItem *> getItemList();
|
||||
|
||||
private:
|
||||
/**
|
||||
* 打印字段详情
|
||||
* 使用net2Host转换成主机字节序后才可使用此函数
|
||||
*/
|
||||
* 打印字段详情
|
||||
* 使用net2Host转换成主机字节序后才可使用此函数
|
||||
*/
|
||||
std::string dumpString() const;
|
||||
|
||||
/**
|
||||
@ -406,13 +405,13 @@ block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
|
||||
//Receiver Report
|
||||
// Receiver Report
|
||||
class RtcpRR : public RtcpHeader {
|
||||
public:
|
||||
friend class RtcpHeader;
|
||||
|
||||
uint32_t ssrc;
|
||||
//可能有很多个
|
||||
// 可能有很多个
|
||||
ReportItem items;
|
||||
|
||||
public:
|
||||
@ -420,14 +419,14 @@ public:
|
||||
* 创建RR包,只赋值了RtcpHeader部分
|
||||
* @param item_count ReportItem对象个数
|
||||
* @return RR包
|
||||
*/
|
||||
*/
|
||||
static std::shared_ptr<RtcpRR> create(size_t item_count);
|
||||
|
||||
/**
|
||||
* 获取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:
|
||||
@ -511,16 +510,16 @@ private:
|
||||
|
||||
/**
|
||||
* 网络字节序转换为主机字节序
|
||||
*/
|
||||
*/
|
||||
void net2Host();
|
||||
} PACKED;
|
||||
|
||||
//Source description
|
||||
// Source description
|
||||
class RtcpSdes : public RtcpHeader {
|
||||
public:
|
||||
friend class RtcpHeader;
|
||||
|
||||
//可能有很多个
|
||||
// 可能有很多个
|
||||
SdesChunk chunks;
|
||||
|
||||
public:
|
||||
@ -535,13 +534,13 @@ public:
|
||||
* 获取SdesChunk对象指针列表
|
||||
* 使用net2Host转换成主机字节序后才可使用此函数
|
||||
*/
|
||||
std::vector<SdesChunk*> getChunkList();
|
||||
std::vector<SdesChunk *> getChunkList();
|
||||
|
||||
private:
|
||||
/**
|
||||
* 打印字段详情
|
||||
* 使用net2Host转换成主机字节序后才可使用此函数
|
||||
*/
|
||||
* 打印字段详情
|
||||
* 使用net2Host转换成主机字节序后才可使用此函数
|
||||
*/
|
||||
std::string dumpString() const;
|
||||
|
||||
/**
|
||||
@ -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;
|
||||
}
|
||||
@ -612,9 +611,9 @@ public:
|
||||
|
||||
private:
|
||||
/**
|
||||
* 打印字段详情
|
||||
* 使用net2Host转换成主机字节序后才可使用此函数
|
||||
*/
|
||||
* 打印字段详情
|
||||
* 使用net2Host转换成主机字节序后才可使用此函数
|
||||
*/
|
||||
std::string dumpString() const;
|
||||
|
||||
/**
|
||||
@ -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
|
||||
@ -675,9 +674,9 @@ public:
|
||||
|
||||
private:
|
||||
/**
|
||||
* 打印字段详情
|
||||
* 使用net2Host转换成主机字节序后才可使用此函数
|
||||
*/
|
||||
* 打印字段详情
|
||||
* 使用net2Host转换成主机字节序后才可使用此函数
|
||||
*/
|
||||
std::string dumpString() const;
|
||||
|
||||
/**
|
||||
@ -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
|
||||
|
@ -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,34 +46,52 @@ 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) {
|
||||
case RtcpType::RTCP_RR: {
|
||||
auto rtcp_rr = (RtcpRR *) rtcp;
|
||||
for (auto item : rtcp_rr->getItemList()) {
|
||||
if (!item->last_sr_stamp) {
|
||||
continue;
|
||||
}
|
||||
auto it = _sender_report_ntp.find(item->last_sr_stamp);
|
||||
if (it == _sender_report_ntp.end()) {
|
||||
continue;
|
||||
}
|
||||
//发送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);
|
||||
if (rtt >= 0) {
|
||||
//rtt不可能小于0
|
||||
_rtt[item->ssrc] = rtt;
|
||||
//InfoL << "ssrc:" << item->ssrc << ",rtt:" << rtt;
|
||||
}
|
||||
switch ((RtcpType)rtcp->pt) {
|
||||
case RtcpType::RTCP_RR: {
|
||||
auto rtcp_rr = (RtcpRR *)rtcp;
|
||||
for (auto item : rtcp_rr->getItemList()) {
|
||||
if (!item->last_sr_stamp) {
|
||||
continue;
|
||||
}
|
||||
auto it = _sender_report_ntp.find(item->last_sr_stamp);
|
||||
if (it == _sender_report_ntp.end()) {
|
||||
continue;
|
||||
}
|
||||
// 发送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);
|
||||
if (rtt >= 0) {
|
||||
// rtt不可能小于0
|
||||
_rtt[item->ssrc] = rtt;
|
||||
// InfoL << "ssrc:" << item->ssrc << ",rtt:" << rtt;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
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))
|
||||
- (int64_t(stamp) - int64_t(_last_rtp_stamp)));
|
||||
// 计算时间戳抖动值
|
||||
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,21 +197,22 @@ void RtcpContextForRecv::onRtp(uint16_t seq, uint32_t stamp, uint64_t ntp_stamp_
|
||||
}
|
||||
|
||||
void RtcpContextForRecv::onRtcp(RtcpHeader *rtcp) {
|
||||
switch ((RtcpType) rtcp->pt) {
|
||||
case RtcpType::RTCP_SR: {
|
||||
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
|
||||
Section 4) received as part of the most recent RTCP sender report
|
||||
(SR) packet from source SSRC_n. If no SR has been received yet,
|
||||
the field is set to zero.
|
||||
*/
|
||||
_last_sr_lsr = ((rtcp_sr->ntpmsw & 0xFFFF) << 16) | ((rtcp_sr->ntplsw >> 16) & 0xFFFF);
|
||||
_last_sr_ntp_sys = getCurrentMillisecond();
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
switch ((RtcpType)rtcp->pt) {
|
||||
case RtcpType::RTCP_SR: {
|
||||
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
|
||||
Section 4) received as part of the most recent RTCP sender report
|
||||
(SR) packet from source SSRC_n. If no SR has been received yet,
|
||||
the field is set to zero.
|
||||
*/
|
||||
_last_sr_lsr = ((rtcp_sr->ntpmsw & 0xFFFF) << 16) | ((rtcp_sr->ntplsw >> 16) & 0xFFFF);
|
||||
_last_sr_ntp_sys = getCurrentMillisecond();
|
||||
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
|
@ -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
|
||||
|
@ -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,87 +365,87 @@ 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:
|
||||
// Deltas are represented as multiples of 250us:
|
||||
//
|
||||
// o If the "Packet received, small delta" symbol has been appended to
|
||||
// the status list, an 8-bit unsigned receive delta will be appended
|
||||
// to recv delta list, representing a delta in the range [0, 63.75]
|
||||
// ms.
|
||||
// o If the "Packet received, small delta" symbol has been appended to
|
||||
// the status list, an 8-bit unsigned receive delta will be appended
|
||||
// to recv delta list, representing a delta in the range [0, 63.75]
|
||||
// ms.
|
||||
//
|
||||
// o If the "Packet received, large or negative delta" symbol has been
|
||||
// appended to the status list, a 16-bit signed receive delta will be
|
||||
// appended to recv delta list, representing a delta in the range
|
||||
// [-8192.0, 8191.75] ms.
|
||||
// o If the "Packet received, large or negative delta" symbol has been
|
||||
// appended to the status list, a 16-bit signed receive delta will be
|
||||
// appended to recv delta list, representing a delta in the range
|
||||
// [-8192.0, 8191.75] ms.
|
||||
//
|
||||
// o If the delta exceeds even the larger limits, a new feedback
|
||||
// message must be used, where the 24-bit base receive delta can
|
||||
// cover very large gaps.
|
||||
// o If the delta exceeds even the larger limits, a new feedback
|
||||
// message must be used, where the 24-bit base receive delta can
|
||||
// cover very large gaps.
|
||||
//
|
||||
// The smaller receive delta upper bound of 63.75 ms means that this is
|
||||
// only viable at about 1000/25.5 ~= 16 packets per second and above.
|
||||
// With a packet size of 1200 bytes/packet that amounts to a bitrate of
|
||||
// about 150 kbit/s.
|
||||
// The smaller receive delta upper bound of 63.75 ms means that this is
|
||||
// only viable at about 1000/25.5 ~= 16 packets per second and above.
|
||||
// With a packet size of 1200 bytes/packet that amounts to a bitrate of
|
||||
// about 150 kbit/s.
|
||||
//
|
||||
// The 0.25 ms resolution means that up to 4000 packets per second can
|
||||
// be represented. With a 1200 bytes/packet payload, that amounts to
|
||||
// 38.4 Mbit/s payload bandwidth.
|
||||
// The 0.25 ms resolution means that up to 4000 packets per second can
|
||||
// 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个字节
|
||||
break;
|
||||
}
|
||||
case SymbolStatus::small_delta : {
|
||||
CHECK(ptr + 1 <= end);
|
||||
//时间戳增量小于256, recv delta为1个字节
|
||||
delta = *ptr;
|
||||
ptr += 1;
|
||||
break;
|
||||
}
|
||||
case SymbolStatus::large_delta : {
|
||||
CHECK(ptr + 2 <= end);
|
||||
//时间戳增量256~65535间,recv delta为2个字节
|
||||
delta = *ptr << 8 | *(ptr + 1);
|
||||
ptr += 2;
|
||||
break;
|
||||
}
|
||||
case SymbolStatus::reserved : {
|
||||
//没有时间戳
|
||||
break;
|
||||
}
|
||||
default:
|
||||
//这个逻辑分支不可达到
|
||||
CHECK(0);
|
||||
break;
|
||||
case SymbolStatus::not_received: {
|
||||
// 丢包, recv delta为0个字节
|
||||
break;
|
||||
}
|
||||
case SymbolStatus::small_delta: {
|
||||
CHECK(ptr + 1 <= end);
|
||||
// 时间戳增量小于256, recv delta为1个字节
|
||||
delta = *ptr;
|
||||
ptr += 1;
|
||||
break;
|
||||
}
|
||||
case SymbolStatus::large_delta: {
|
||||
CHECK(ptr + 2 <= end);
|
||||
// 时间戳增量256~65535间,recv delta为2个字节
|
||||
delta = *ptr << 8 | *(ptr + 1);
|
||||
ptr += 2;
|
||||
break;
|
||||
}
|
||||
case SymbolStatus::reserved: {
|
||||
// 没有时间戳
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// 这个逻辑分支不可达到
|
||||
CHECK(0);
|
||||
break;
|
||||
}
|
||||
return delta;
|
||||
}
|
||||
|
||||
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
|
@ -11,37 +11,37 @@
|
||||
#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
|
||||
// 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
|
||||
// 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
|
||||
// number for each macroblock increases from left to right and then
|
||||
// from top to bottom in raster-scan order (such that if there is a
|
||||
// total of N macroblocks in a picture, the bottom right macroblock
|
||||
// is considered macroblock number N).
|
||||
// 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
|
||||
// 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
|
||||
// number for each macroblock increases from left to right and then
|
||||
// from top to bottom in raster-scan order (such that if there is a
|
||||
// total of N macroblocks in a picture, the bottom right macroblock
|
||||
// is considered macroblock number N).
|
||||
//
|
||||
// Number: 13 bits
|
||||
// The number of lost macroblocks, in scan order as discussed above.
|
||||
// Number: 13 bits
|
||||
// The number of lost macroblocks, in scan order as discussed above.
|
||||
//
|
||||
// PictureID: 6 bits
|
||||
// The six least significant bits of the codec-specific identifier
|
||||
// that is used to reference the picture in which the loss of the
|
||||
// macroblock(s) has occurred. For many video codecs, the PictureID
|
||||
// is identical to the Temporal Reference.
|
||||
// PictureID: 6 bits
|
||||
// The six least significant bits of the codec-specific identifier
|
||||
// that is used to reference the picture in which the loss of the
|
||||
// macroblock(s) has occurred. For many video codecs, the PictureID
|
||||
// is identical to the Temporal Reference.
|
||||
class FCI_SLI {
|
||||
public:
|
||||
static size_t constexpr kSize = 4;
|
||||
@ -101,15 +101,15 @@ public:
|
||||
} PACKED;
|
||||
#endif
|
||||
|
||||
//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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | SSRC |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Seq nr. | Reserved |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | SSRC |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Seq nr. | Reserved |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
class FCI_FIR {
|
||||
public:
|
||||
static size_t constexpr kSize = 8;
|
||||
@ -188,34 +188,34 @@ private:
|
||||
|
||||
#endif
|
||||
|
||||
//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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Unique identifier 'R' 'E' 'M' 'B' |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Num SSRC | BR Exp | BR Mantissa |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | SSRC feedback |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | ... |
|
||||
// Num SSRC (8 bits): Number of SSRCs in this message.
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Unique identifier 'R' 'E' 'M' 'B' |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Num SSRC | BR Exp | BR Mantissa |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | SSRC feedback |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | ... |
|
||||
// Num SSRC (8 bits): Number of SSRCs in this message.
|
||||
//
|
||||
// BR Exp (6 bits): The exponential scaling of the mantissa for the
|
||||
// maximum total media bit rate value, ignoring all packet
|
||||
// overhead. The value is an unsigned integer [0..63], as
|
||||
// in RFC 5104 section 4.2.2.1.
|
||||
// BR Exp (6 bits): The exponential scaling of the mantissa for the
|
||||
// maximum total media bit rate value, ignoring all packet
|
||||
// overhead. The value is an unsigned integer [0..63], as
|
||||
// in RFC 5104 section 4.2.2.1.
|
||||
//
|
||||
// BR Mantissa (18 bits): The mantissa of the maximum total media bit
|
||||
// rate (ignoring all packet overhead) that the sender of
|
||||
// the REMB estimates. The BR is the estimate of the
|
||||
// traveled path for the SSRCs reported in this message.
|
||||
// The value is an unsigned integer in number of bits per
|
||||
// second.
|
||||
// BR Mantissa (18 bits): The mantissa of the maximum total media bit
|
||||
// rate (ignoring all packet overhead) that the sender of
|
||||
// the REMB estimates. The BR is the estimate of the
|
||||
// traveled path for the SSRCs reported in this message.
|
||||
// The value is an unsigned integer in number of bits per
|
||||
// second.
|
||||
//
|
||||
// SSRC feedback (32 bits) Consists of one or more SSRC entries which
|
||||
// this feedback message applies to.
|
||||
// SSRC feedback (32 bits) Consists of one or more SSRC entries which
|
||||
// this feedback message applies to.
|
||||
class FCI_REMB {
|
||||
public:
|
||||
static size_t constexpr kSize = 8;
|
||||
@ -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,13 +238,13 @@ private:
|
||||
|
||||
/////////////////////////////////////////// RTPFB ////////////////////////////////////////////////////
|
||||
|
||||
//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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | PID | BLP |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | PID | BLP |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
class FCI_NACK {
|
||||
public:
|
||||
static constexpr size_t kSize = 4;
|
||||
@ -255,8 +255,8 @@ public:
|
||||
void check(size_t size);
|
||||
uint16_t getPid() const;
|
||||
uint16_t getBlp() const;
|
||||
//返回丢包列表,总长度17,第一个包必丢
|
||||
// TODO: replace std::bitset
|
||||
// 返回丢包列表,总长度17,第一个包必丢
|
||||
// TODO: replace std::bitset
|
||||
std::vector<bool> getBitArray() const;
|
||||
std::string dumpString() const;
|
||||
|
||||
@ -318,47 +318,48 @@ 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
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | base sequence number | packet status count |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | reference time | fb pkt. count |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | packet chunk | packet chunk |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// . .
|
||||
// . .
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | packet chunk | recv delta | recv delta |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// . .
|
||||
// . .
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | recv delta | recv delta | zero padding |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
class FCI_TWCC{
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | base sequence number | packet status count |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | reference time | fb pkt. count |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | packet chunk | packet chunk |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// . .
|
||||
// . .
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | packet chunk | recv delta | recv delta |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// . .
|
||||
// . .
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | recv delta | recv delta | zero padding |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
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
Loading…
Reference in New Issue
Block a user