From 602b475a3c6de008e7ede65cb5767d4e05a5b4fc Mon Sep 17 00:00:00 2001 From: xiongguangjie Date: Tue, 12 Jul 2022 19:26:17 +0800 Subject: [PATCH] for rtc send can receive rtcp xr, player can calculate rtt , for metaRTC player send rtcp xr --- src/Rtcp/Rtcp.cpp | 107 ++++++++++++++++++++++++++++- src/Rtcp/Rtcp.h | 134 +++++++++++++++++++++++++++++++++++++ src/Rtcp/RtcpContext.cpp | 44 ++++++++++++ src/Rtcp/RtcpContext.h | 14 ++++ webrtc/WebRtcTransport.cpp | 17 +++++ 5 files changed, 315 insertions(+), 1 deletion(-) diff --git a/src/Rtcp/Rtcp.cpp b/src/Rtcp/Rtcp.cpp index ea6533d3..19abb51e 100644 --- a/src/Rtcp/Rtcp.cpp +++ b/src/Rtcp/Rtcp.cpp @@ -193,7 +193,20 @@ void RtcpHeader::net2Host(size_t len) { bye->net2Host(len); break; } - + case RtcpType::RTCP_XR:{ + RtcpXRRRTR* xr = (RtcpXRRRTR*)this; + if(xr->bt == 4){ + xr->net2Host(len); + //TraceL<dumpString(); + }else if(xr->bt == 5){ + RtcpXRDLRR* dlrr = (RtcpXRDLRR*)this; + dlrr->net2Host(len); + TraceL<dumpString(); + }else{ + throw std::runtime_error(StrPrinter << "rtcp xr bt " << xr->bt<<" not support"); + } + break; + } default: throw std::runtime_error(StrPrinter << "未处理的rtcp包:" << rtcpTypeToStr((RtcpType) this->pt)); } } @@ -691,6 +704,98 @@ void RtcpBye::net2Host(size_t size) { } } } +//////////////////////////////////////////// +string RtcpXRRRTR::dumpString() const { + _StrPrinter printer; + printer << RtcpHeader::dumpHeader(); + printer << "ssrc :" < RtcpXRDLRR::getItemList(){ + auto count = block_length/3; + RtcpXRDLRRReportItem *ptr = &items; + vector 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 :" <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::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(ptr, [](RtcpXRDLRR *ptr) { + delete[] (char *) ptr; + }); +} #if 0 #include "Util/onceToken.h" diff --git a/src/Rtcp/Rtcp.h b/src/Rtcp/Rtcp.h index 29a334e6..223b9c59 100644 --- a/src/Rtcp/Rtcp.h +++ b/src/Rtcp/Rtcp.h @@ -687,6 +687,140 @@ 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 create(size_t item_count); + + /** + * 获取RtcpXRDLRRReportItem对象指针列表 + * 使用net2Host转换成主机字节序后才可使用此函数 + */ + std::vector getItemList(); + +private: + /** + * 打印字段详情 + * 使用net2Host转换成主机字节序后才可使用此函数 + */ + std::string dumpString() const; + + /** + * 网络字节序转换为主机字节序 + * @param size 字节长度,防止内存越界 + */ + void net2Host(size_t size); + +}PACKED; + + #if defined(_WIN32) #pragma pack(pop) #endif // defined(_WIN32) diff --git a/src/Rtcp/RtcpContext.cpp b/src/Rtcp/RtcpContext.cpp index f7795405..23abbb91 100644 --- a/src/Rtcp/RtcpContext.cpp +++ b/src/Rtcp/RtcpContext.cpp @@ -45,6 +45,10 @@ 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) { @@ -72,6 +76,18 @@ void RtcpContextForSend::onRtcp(RtcpHeader *rtcp) { } 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 "<bt; + } + break; + } default: break; } } @@ -103,6 +119,34 @@ Buffer::Ptr RtcpContextForSend::createRtcpSR(uint32_t rtcp_ssrc) { 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) { diff --git a/src/Rtcp/RtcpContext.h b/src/Rtcp/RtcpContext.h index 59341b05..2ed936f8 100644 --- a/src/Rtcp/RtcpContext.h +++ b/src/Rtcp/RtcpContext.h @@ -55,6 +55,14 @@ 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 @@ -86,8 +94,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 @@ -98,6 +109,9 @@ public: private: std::map _rtt; std::map _sender_report_ntp; + + std::map _xr_rrtr_recv_sys_stamp; + std::map _xr_xrrtr_recv_last_rr; }; class RtcpContextForRecv : public RtcpContext { diff --git a/webrtc/WebRtcTransport.cpp b/webrtc/WebRtcTransport.cpp index 42025238..5850cfb6 100644 --- a/webrtc/WebRtcTransport.cpp +++ b/webrtc/WebRtcTransport.cpp @@ -774,6 +774,23 @@ void WebRtcTransportImp::onRtcp(const char *buf, size_t len) { } break; } + case RtcpType::RTCP_XR:{ + RtcpXRRRTR* xr = (RtcpXRRRTR *) rtcp; + if(xr->bt != 4){ + break; + } + auto it = _ssrc_to_track.find(xr->ssrc); + if (it == _ssrc_to_track.end()) { + WarnL << "未识别的 rtcp包:" << rtcp->dumpString(); + return; + } + auto &track = it->second; + track->rtcp_context_send->onRtcp(rtcp); + auto xrdlrr = track->rtcp_context_send->createRtcpXRDLRR(track->answer_ssrc_rtp,track->answer_ssrc_rtp); + sendRtcpPacket(xrdlrr->data(), xrdlrr->size(), true); + + break; + } default: break; } }