diff --git a/src/Rtcp/Rtcp.cpp b/src/Rtcp/Rtcp.cpp index a74ec4a7..35853e80 100644 --- a/src/Rtcp/Rtcp.cpp +++ b/src/Rtcp/Rtcp.cpp @@ -144,8 +144,8 @@ void RtcpHeader::net2Host(size_t len){ } case RtcpType::RTCP_RTPFB: { - //todo 支持rtcp-fb相关功能 - net2Host(); + RtcpPli *pli = (RtcpPli *)this; + pli->net2Host(len); break; } default: throw std::runtime_error(StrPrinter << "未处理的rtcp包:" << rtcpTypeToStr((RtcpType) this->pt)); diff --git a/src/Rtcp/RtcpFCI.cpp b/src/Rtcp/RtcpFCI.cpp index 61a4cd16..eec9e7f9 100644 --- a/src/Rtcp/RtcpFCI.cpp +++ b/src/Rtcp/RtcpFCI.cpp @@ -246,4 +246,92 @@ string StatusVecChunk::dumpString() const { return std::move(printer); } +/////////////////////////////////////////////////////// + +void FCI_TWCC::net2Host(size_t total_size) { + CHECK(total_size >= kSize); + base_seq = ntohs(base_seq); + pkt_status_count = ntohs(pkt_status_count); +} + +uint32_t FCI_TWCC::getReferenceTime() const { + uint32_t ret = 0; + ret |= ref_time[0] << 16; + ret |= ref_time[1] << 8; + ret |= ref_time[2]; + return ret; +} + +static uint16_t getRecvDelta(SymbolStatus status, uint8_t *&ptr, const uint8_t *end){ + uint16_t delta = 0; + switch (status) { + case SymbolStatus::not_received : { + //丢包, recv delta为0个字节 + 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; + } + default: + //这个逻辑分支不可达到 + CHECK(0); + break; + } + return delta; +} + +map > FCI_TWCC::getPacketChunkList(size_t total_size) const { + map > ret; + auto ptr = (uint8_t *) this + kSize; + auto end = (uint8_t *) this + total_size; + CHECK(ptr < end); + auto seq = base_seq; + auto stamp = getReferenceTime(); + + for (uint8_t i = 0; i < pkt_status_count;) { + CHECK(ptr + RunLengthChunk::kSize <= end) + RunLengthChunk *chunk = (RunLengthChunk *) ptr; + if (!chunk->type) { + //RunLengthChunk + ptr += RunLengthChunk::kSize; + for (auto j = 0; j < chunk->getRunLength(); ++j) { + ret.emplace(seq++, std::make_pair((SymbolStatus) chunk->symbol, stamp)); + stamp += getRecvDelta((SymbolStatus) chunk->symbol, ptr, end); + ++i; + } + } else { + //StatusVecChunk + StatusVecChunk *chunk = (StatusVecChunk *) ptr; + ptr += StatusVecChunk::kSize; + for (auto &symbol : chunk->getSymbolList()) { + ret.emplace(seq++, std::make_pair(symbol, stamp)); + stamp += getRecvDelta(symbol, ptr, end); + ++i; + } + } + } + return ret; +} + +string FCI_TWCC::dumpString(size_t total_size) const { + _StrPrinter printer; + auto map = getPacketChunkList(total_size); + for (auto &pr : map) { + printer << " seq:" << pr.first <<", packet status:" << (int)(pr.second.first) << ", stamp:" << pr.second.second << "\n"; + } + return std::move(printer); +} + }//namespace mediakit \ No newline at end of file diff --git a/src/Rtcp/RtcpFCI.h b/src/Rtcp/RtcpFCI.h index 3eedfa6c..8df51f32 100644 --- a/src/Rtcp/RtcpFCI.h +++ b/src/Rtcp/RtcpFCI.h @@ -296,29 +296,6 @@ public: } PACKED; -//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 | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - enum class SymbolStatus : uint8_t{ //Packet not received not_received = 0, @@ -333,11 +310,11 @@ enum class SymbolStatus : uint8_t{ class RunLengthChunk { public: static size_t constexpr kSize = 2; - // 0 1 - // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // |T| S | Run Length | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // 0 1 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // |T| S | Run Length | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ #if __BYTE_ORDER == __BIG_ENDIAN uint16_t type: 1; uint16_t symbol: 2; @@ -364,11 +341,11 @@ public: class StatusVecChunk { public: static size_t constexpr kSize = 2; - // 0 1 - // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // |T| S | Run Length | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // 0 1 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // |T|S| symbol list | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ #if __BYTE_ORDER == __BIG_ENDIAN uint16_t type: 1; uint16_t symbol: 1; @@ -392,9 +369,31 @@ public: string dumpString() const; } PACKED; +//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 = 12; + static size_t constexpr kSize = 8; //base sequence number,基础序号,本次反馈的第一个包的序号;也就是RTP扩展头的序列号 uint16_t base_seq; @@ -405,6 +404,11 @@ public: //feedback packet count,反馈包号,本包是第几个transport-cc包,每次加1 | uint8_t fb_pkt_count; + void net2Host(size_t total_size); + uint32_t getReferenceTime() const; + map > getPacketChunkList(size_t total_size) const; + string dumpString(size_t total_size) const; + } PACKED; } //namespace mediakit diff --git a/webrtc/WebRtcTransport.cpp b/webrtc/WebRtcTransport.cpp index 9a58fb21..d37e5a88 100644 --- a/webrtc/WebRtcTransport.cpp +++ b/webrtc/WebRtcTransport.cpp @@ -501,6 +501,8 @@ private: function _on_before_sort; }; +#include "RTCP/RtcpFCI.h" + void WebRtcTransportImp::onRtcp(const char *buf, size_t len) { _bytes_usage += len; auto rtcps = RtcpHeader::loadFromBytes((char *) buf, len); @@ -546,6 +548,20 @@ void WebRtcTransportImp::onRtcp(const char *buf, size_t len) { //todo 支持pli等更多类型的rtcp break; } + case RtcpType::RTCP_RTPFB: { + //todo 测试打印twcc + RtcpPli *rtpfb = (RtcpPli *)rtcp; + auto fci = (uint8_t *)rtpfb + sizeof (RtcpPli); + if(rtpfb->report_count == 15){ + //TWCC + FCI_TWCC *twcc = (FCI_TWCC *) (fci); + auto fci_size = rtpfb->getSize() - 12; + InfoL << hexdump(fci, fci_size); + twcc->net2Host(fci_size); + InfoL << "\n" << twcc->dumpString(fci_size); + } + break; + } default: break; } }