diff --git a/src/Rtcp/RtcpFCI.cpp b/src/Rtcp/RtcpFCI.cpp index d0288acf..e03b1043 100644 --- a/src/Rtcp/RtcpFCI.cpp +++ b/src/Rtcp/RtcpFCI.cpp @@ -285,22 +285,16 @@ public: //获取symbollist vector getSymbolList() const; //构造函数 - StatusVecChunk(const vector &status); + StatusVecChunk(bool symbol_bit, const vector &status); //打印本对象 string dumpString() const; } PACKED; -StatusVecChunk::StatusVecChunk(const vector &status) { +StatusVecChunk::StatusVecChunk(bool symbol_bit, const vector &status) { + CHECK((1 + symbol_bit) * status.size() <= 14); uint16_t value = 0; type = 1; - if (status.size() == 14) { - symbol = 0; - } else if (status.size() == 7) { - symbol = 1; - } else { - //非法 - CHECK(0); - } + symbol = symbol_bit; int i = 13; for (auto &item : status) { CHECK(item <= SymbolStatus::reserved); @@ -428,8 +422,8 @@ static int16_t getRecvDelta(SymbolStatus status, uint8_t *&ptr, const uint8_t *e return delta; } -map > FCI_TWCC::getPacketChunkList(size_t total_size) const { - map > ret; +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; CHECK(ptr < end); @@ -475,48 +469,83 @@ string FCI_TWCC::dumpString(size_t total_size) const { return std::move(printer); } -}//namespace mediakit - -#if 1 -using namespace mediakit; -void testFCI() { - { - FCI_SLI fci(8191, 0, 63); - InfoL << hexdump(&fci, FCI_SLI::kSize) << fci.dumpString(); - } - { - FCI_FIR fci(123456, 139, 456789); - InfoL << hexdump(&fci, FCI_FIR::kSize) << fci.dumpString(); - } - { - auto str = FCI_REMB::create({1234, 2345, 5678}, 4 * 1024 * 1024); - FCI_REMB *ptr = (FCI_REMB *) str.data(); - InfoL << hexdump(str.data(), str.size()) << ptr->dumpString(); - } - { - FCI_NACK nack(1234, vector({1, 0, 0, 0, 1, 0, 1, 0, 1, 0})); - InfoL << hexdump(&nack, FCI_NACK::kSize) << nack.dumpString(); - } - - { - RunLengthChunk chunk(SymbolStatus::large_delta, 8024); - InfoL << hexdump(&chunk, RunLengthChunk::kSize) << chunk.dumpString(); - } - - auto lam = [](const initializer_list &lst) { - vector ret; - for (auto &num : lst) { - ret.emplace_back((SymbolStatus) num); +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; } - return ret; - }; - { - StatusVecChunk chunk(lam({0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1})); - InfoL << hexdump(&chunk, StatusVecChunk::kSize) << chunk.dumpString(); - } - { - StatusVecChunk chunk(lam({0, 1, 2, 2, 0, 1, 2})); - InfoL << hexdump(&chunk, StatusVecChunk::kSize) << chunk.dumpString(); + //移除已经处理过的数据 + it = status.erase(it); } } -#endif \ No newline at end of file + +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()); + ptr->base_seq = htons(status.begin()->first); + ptr->pkt_status_count = htons(status.size()); + ptr->fb_pkt_count = fb_pkt_count; + ptr->ref_time[0] = (ref_time >> 16) & 0xFF; + ptr->ref_time[1] = (ref_time >> 8) & 0xFF; + ptr->ref_time[2] = (ref_time >> 0) & 0xFF; + + string delta_str; + while (!status.empty()) { + { + //第一个rtp的状态 + auto symbol = status.begin()->second.first; + int16_t count = 0; + for (auto &pr : status) { + if (++count == (0xFFFF >> 3)) { + //RunLengthChunk 13个bit表明rtp个数,最多可以表述0xFFFF >> 3个rtp状态 + break; + } + if (pr.second.first != symbol) { + //状态发送变更了,本chunk结束 + break; + } + } + if (count >= 7) { + //连续状态相同个数大于6个时,使用RunLengthChunk模式比较节省带宽 + RunLengthChunk chunk(symbol, count); + fci.append((char *)&chunk, RunLengthChunk::kSize); + appendDeltaString(delta_str, status, count); + continue; + } + } + + { + //StatusVecChunk模式 + //symbol_list中元素是1个bit + auto symbol = 0; + int count = 0; + vector vec; + for (auto &pr : status) { + vec.push_back(pr.second.first); + if (pr.second.first >= SymbolStatus::large_delta) { + //symbol_list中元素是2个bit + symbol = 1; + } + if ((1 + symbol) * (++count) == 14) { + //symbol为0时,最多存放14个rtp的状态 + //symbol为1时,最多存放7个rtp的状态 + break; + } + } + StatusVecChunk chunk(symbol, vec); + fci.append((char *)&chunk, StatusVecChunk::kSize); + appendDeltaString(delta_str, status, count); + } + } + + //recv delta部分 + fci.append(delta_str); + return fci; +} + +}//namespace mediakit \ No newline at end of file diff --git a/src/Rtcp/RtcpFCI.h b/src/Rtcp/RtcpFCI.h index 83ff255f..9681048b 100644 --- a/src/Rtcp/RtcpFCI.h +++ b/src/Rtcp/RtcpFCI.h @@ -346,14 +346,16 @@ enum class SymbolStatus : uint8_t{ class FCI_TWCC{ public: static size_t constexpr kSize = 8; - + using TwccPacketStatus = map >; void check(size_t size); string dumpString(size_t total_size) const; uint16_t getBaseSeq() const; //单位64ms uint32_t getReferenceTime() const; uint16_t getPacketCount() const; - map > getPacketChunkList(size_t total_size) const; + TwccPacketStatus getPacketChunkList(size_t total_size) const; + + static string create(uint32_t ref_time, uint8_t fb_pkt_count, TwccPacketStatus &status); private: //base sequence number,基础序号,本次反馈的第一个包的序号;也就是RTP扩展头的序列号 diff --git a/tests/test_rtcp_fci.cpp b/tests/test_rtcp_fci.cpp deleted file mode 100644 index 036e2924..00000000 --- a/tests/test_rtcp_fci.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved. - * - * This file is part of ZLToolKit(https://github.com/xia-chu/ZLToolKit). - * - * Use of this source code is governed by MIT license that can be found in the - * LICENSE file in the root of the source tree. All contributing project authors - * may be found in the AUTHORS file in the root of the source tree. - */ - -#include -#include "Util/logger.h" -#include "Rtcp/RtcpFCI.h" -using namespace std; -using namespace toolkit; -using namespace mediakit; - -extern void testFCI(); - -int main() { - Logger::Instance().add(std::make_shared()); - - testFCI(); - return 0; -} diff --git a/webrtc/TwccContext.cpp b/webrtc/TwccContext.cpp index 4bba225a..c479387e 100644 --- a/webrtc/TwccContext.cpp +++ b/webrtc/TwccContext.cpp @@ -9,6 +9,9 @@ */ #include "TwccContext.h" +#include "Rtcp/RtcpFCI.h" + +using namespace mediakit; enum class ExtSeqStatus : int { normal = 0, @@ -78,17 +81,27 @@ void TwccContext::onSendTwcc() { auto begin = _rtp_recv_status.begin(); auto min = begin->first; auto ref_time = begin->second; - DebugL << "base_seq:" << min << ",pkt_status_count:" << max + 1 - min << ",ref time:" << ref_time / 64 - << ", fb count:" << (int) (_twcc_pkt_count++); - for (auto i = min; i <= max; ++i) { - auto it = _rtp_recv_status.find(i); - if (it == _rtp_recv_status.end()) { - DebugL << "rtp seq:" << i << ",packet status:" << 0 /*not recved*/ << ",delta_ms:" << 0; - } else { - auto delta_ms = it->second - ref_time; - DebugL << "rtp seq:" << i << ",packet status:" << 1 /*recved*/ << ",delta_ms:" << delta_ms; + FCI_TWCC::TwccPacketStatus status; + for (auto seq = min; seq <= max; ++seq) { + int16_t delta = 0; + SymbolStatus symbol = SymbolStatus::not_received; + auto it = _rtp_recv_status.find(seq); + if (it != _rtp_recv_status.end()) { + //recv delta,单位为250us,1ms等于4x250us + delta = (int16_t) (4 * ((int64_t) it->second - (int64_t) ref_time)); + if (delta < 0 || delta > 0xFF) { + symbol = SymbolStatus::large_delta; + } else { + symbol = SymbolStatus::small_delta; + } + ref_time = it->second; } + status.emplace(seq, std::make_pair(symbol, delta)); } + auto fci = FCI_TWCC::create(ref_time / 64, _twcc_pkt_count, status); + InfoL << ((FCI_TWCC *) (fci.data()))->dumpString(fci.size()); + + ++_twcc_pkt_count; clearStatus(); }