From 5db61547079e3d5049f309aa0b97ff967d26f4a6 Mon Sep 17 00:00:00 2001 From: xia-chu <771730766@qq.com> Date: Thu, 22 Apr 2021 11:43:33 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0TWCC=E9=83=A8=E5=88=86?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Rtcp/RtcpFCI.cpp | 78 ++++++++++++++++++++++++++++++++++++ src/Rtcp/RtcpFCI.h | 87 +++++++++++++++++++++++++++++++++++++++++ tests/test_rtcp_fci.cpp | 23 +++++++++++ 3 files changed, 188 insertions(+) diff --git a/src/Rtcp/RtcpFCI.cpp b/src/Rtcp/RtcpFCI.cpp index 44d22055..61a4cd16 100644 --- a/src/Rtcp/RtcpFCI.cpp +++ b/src/Rtcp/RtcpFCI.cpp @@ -167,5 +167,83 @@ string FCI_NACK::dumpString() const { return std::move(printer); } +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +RunLengthChunk::RunLengthChunk(SymbolStatus status, uint16_t run_length) { + type = 0; + symbol = (uint8_t)status & 0x03; + run_length_high = (run_length >> 8) & 0x1F; + run_length_low = run_length & 0xFF; +} + +uint16_t RunLengthChunk::getRunLength() const { + CHECK(type == 0); + return run_length_high << 8 | run_length_low; +} + +string RunLengthChunk::dumpString() const{ + _StrPrinter printer; + printer << "run length chunk, symbol:" << (int)symbol << ", run length:" << getRunLength(); + return std::move(printer); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +StatusVecChunk::StatusVecChunk(const vector &status) { + uint16_t value = 0; + type = 1; + if (status.size() == 14) { + symbol = 0; + } else if (status.size() == 7) { + symbol = 1; + } else { + //非法 + CHECK(0); + } + int i = 13; + for (auto &item : status) { + CHECK(item <= SymbolStatus::reserved); + if (!symbol) { + CHECK(item <= SymbolStatus::small_delta); + value |= (int) item << i; + --i; + } else { + value |= (int) item << (i - 1); + i -= 2; + } + } + symbol_list_low = value & 0xFF; + symbol_list_high = (value >> 8 ) & 0x1F; +} + +vector StatusVecChunk::getSymbolList() const { + CHECK(type == 1); + vector ret; + auto thiz = ntohs(*((uint16_t *) this)); + if (symbol == 0) { + //s = 0 时,表示symbollist的每一个bit能表示一个数据包的到达状态 + for (int i = 13; i >= 0; --i) { + SymbolStatus status = (SymbolStatus) ((bool) (thiz & (1 << i))); + ret.emplace_back(status); + } + } else { + //s = 1 时,表示symbollist每两个bit表示一个数据包的状态 + for (int i = 12; i >= 0; i -= 2) { + SymbolStatus status = (SymbolStatus) ((thiz & (3 << i)) >> i); + ret.emplace_back(status); + } + } + return ret; +} + +string StatusVecChunk::dumpString() const { + _StrPrinter printer; + printer << "status vector chunk, symbol:" << (int) symbol << ", symbol list:"; + auto vec = getSymbolList(); + for (auto &item : vec) { + printer << (int) item << " "; + } + 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 ed216149..3eedfa6c 100644 --- a/src/Rtcp/RtcpFCI.h +++ b/src/Rtcp/RtcpFCI.h @@ -222,6 +222,7 @@ public: class FCI_NACK { public: static constexpr size_t kBitSize = 16; + static constexpr size_t kSize = 4; // The PID field is used to specify a lost packet. The PID field // refers to the RTP sequence number of the lost packet. @@ -259,6 +260,8 @@ public: // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ class FCI_TMMBR { public: + static size_t constexpr kSize = 8; + //SSRC (32 bits): The SSRC value of the media sender that is // requested to obey the new maximum bit rate. uint32_t ssrc; @@ -315,8 +318,92 @@ public: // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | recv delta | recv delta | zero padding | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +enum class SymbolStatus : uint8_t{ + //Packet not received + not_received = 0, + //Packet received, small delta (所谓small detal是指能用一个字节表示的数值) + small_delta = 1, + // Packet received, large ornegative delta (large即是能用两个字节表示的数值) + large_delta = 2, + //Reserved + reserved = 3 +}; + +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 | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +#if __BYTE_ORDER == __BIG_ENDIAN + 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; +#endif + // Run Length 低8位 + uint16_t run_length_low: 8; + + //获取Run Length + uint16_t getRunLength() const; + //构造函数 + RunLengthChunk(SymbolStatus status, uint16_t run_length); + + string dumpString() const; +} PACKED; + +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 | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +#if __BYTE_ORDER == __BIG_ENDIAN + 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; +#endif + // symbol_list 低8位 + uint16_t symbol_list_low: 8; + + //获取symbollist + vector getSymbolList() const; + //构造函数 + StatusVecChunk(const vector &status); + + string dumpString() const; +} PACKED; + class FCI_TWCC{ public: + static size_t constexpr kSize = 12; + + //base sequence number,基础序号,本次反馈的第一个包的序号;也就是RTP扩展头的序列号 + uint16_t base_seq; + //packet status count, 包个数,本次反馈包含多少个包的状态;从基础序号开始算 + uint16_t pkt_status_count; + //reference time,基准时间,绝对时间;计算该包中每个媒体包的到达时间都要基于这个基准时间计算 + uint8_t ref_time[3]; + //feedback packet count,反馈包号,本包是第几个transport-cc包,每次加1 | + uint8_t fb_pkt_count; } PACKED; diff --git a/tests/test_rtcp_fci.cpp b/tests/test_rtcp_fci.cpp index d8fd1eca..aecc821d 100644 --- a/tests/test_rtcp_fci.cpp +++ b/tests/test_rtcp_fci.cpp @@ -42,5 +42,28 @@ int main() { nack.net2Host(); InfoL << nack.dumpString(); } + { + RunLengthChunk chunk(SymbolStatus::large_delta, 8024); + InfoL << hexdump(&chunk, RunLengthChunk::kSize); + InfoL << chunk.dumpString(); + } + + auto lam = [](const initializer_list &lst){ + vector ret; + for(auto &num : lst){ + ret.emplace_back((SymbolStatus)num); + } + return ret; + }; + { + StatusVecChunk chunk(lam({0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1})); + InfoL << hexdump(&chunk, StatusVecChunk::kSize); + InfoL << chunk.dumpString(); + } + { + StatusVecChunk chunk(lam({0, 1, 2, 3, 0, 1, 2})); + InfoL << hexdump(&chunk, StatusVecChunk::kSize); + InfoL << chunk.dumpString(); + } return 0; }