diff --git a/src/Rtcp/RtcpFCI.cpp b/src/Rtcp/RtcpFCI.cpp
index 725236d4..78877337 100644
--- a/src/Rtcp/RtcpFCI.cpp
+++ b/src/Rtcp/RtcpFCI.cpp
@@ -428,8 +428,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;
+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);
diff --git a/src/Rtcp/RtcpFCI.h b/src/Rtcp/RtcpFCI.h
index 071a3d1b..83ff255f 100644
--- a/src/Rtcp/RtcpFCI.h
+++ b/src/Rtcp/RtcpFCI.h
@@ -353,7 +353,7 @@ public:
//单位64ms
uint32_t getReferenceTime() const;
uint16_t getPacketCount() const;
- map > getPacketChunkList(size_t total_size) const;
+ map > getPacketChunkList(size_t total_size) const;
private:
//base sequence number,基础序号,本次反馈的第一个包的序号;也就是RTP扩展头的序列号
diff --git a/webrtc/RtpExt.cpp b/webrtc/RtpExt.cpp
index ac4143d5..89e56b00 100644
--- a/webrtc/RtpExt.cpp
+++ b/webrtc/RtpExt.cpp
@@ -239,7 +239,7 @@ string RtpExt::dumpString() const {
break;
}
case RtpExtType::transport_cc : {
- printer << "twcc seq:" << getTransportCCSeq();
+ printer << "twcc ext seq:" << getTransportCCSeq();
break;
}
case RtpExtType::sdes_mid : {
@@ -546,6 +546,10 @@ RtpExtType RtpExt::getType() const {
return _type;
}
+RtpExt::operator bool() const {
+ return _ext != nullptr;
+}
+
RtpExtContext::RtpExtContext(const RtcMedia &m){
for (auto &ext : m.extmap) {
auto ext_type = RtpExt::getExtType(ext.ext);
@@ -566,8 +570,9 @@ void RtpExtContext::setRid(uint32_t ssrc, const string &rid) {
_ssrc_to_rid[ssrc] = rid;
}
-void RtpExtContext::changeRtpExtId(const RtpHeader *header, bool is_recv, string *rid_ptr) {
+RtpExt RtpExtContext::changeRtpExtId(const RtpHeader *header, bool is_recv, string *rid_ptr, RtpExtType type) {
string rid, repaired_rid;
+ RtpExt ret;
auto ext_map = RtpExt::getExtValue(header);
for (auto &pr : ext_map) {
if (is_recv) {
@@ -596,10 +601,13 @@ void RtpExtContext::changeRtpExtId(const RtpHeader *header, bool is_recv, string
//重新赋值ext id为客户端sdp声明的类型
pr.second.setExtId(it->second);
}
+ if (pr.second.getType() == type) {
+ ret = pr.second;
+ }
}
if (!is_recv) {
- return;
+ return ret;
}
if (rid.empty()) {
rid = repaired_rid;
@@ -619,6 +627,7 @@ void RtpExtContext::changeRtpExtId(const RtpHeader *header, bool is_recv, string
if (rid_ptr) {
*rid_ptr = rid;
}
+ return ret;
}
void RtpExtContext::setOnGetRtp(OnGetRtp cb) {
diff --git a/webrtc/RtpExt.h b/webrtc/RtpExt.h
index d53a4a9b..b05a8021 100644
--- a/webrtc/RtpExt.h
+++ b/webrtc/RtpExt.h
@@ -52,7 +52,7 @@ class RtpExt {
public:
template
friend void appendExt(map &ret, uint8_t *ptr, const uint8_t *end);
-
+ friend class RtpExtContext;
~RtpExt() = default;
static map getExtValue(const RtpHeader *header);
@@ -94,8 +94,10 @@ public:
void setExtId(uint8_t ext_id);
void clearExt();
+ operator bool () const;
private:
+ RtpExt() = default;
RtpExt(void *ptr, bool one_byte_ext, const char *str, size_t size);
const char *data() const;
size_t size() const;
@@ -122,7 +124,7 @@ public:
void setOnGetRtp(OnGetRtp cb);
string getRid(uint32_t ssrc) const;
void setRid(uint32_t ssrc, const string &rid);
- void changeRtpExtId(const RtpHeader *header, bool is_recv, string *rid_ptr = nullptr);
+ RtpExt changeRtpExtId(const RtpHeader *header, bool is_recv, string *rid_ptr = nullptr, RtpExtType type = RtpExtType::padding);
private:
void onGetRtp(uint8_t pt, uint32_t ssrc, const string &rid);
diff --git a/webrtc/TwccContext.cpp b/webrtc/TwccContext.cpp
new file mode 100644
index 00000000..4bba225a
--- /dev/null
+++ b/webrtc/TwccContext.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2021 The ZLMediaKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
+ *
+ * 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 "TwccContext.h"
+
+enum class ExtSeqStatus : int {
+ normal = 0,
+ looped,
+ jumped,
+};
+
+void TwccContext::onRtp(uint16_t twcc_ext_seq) {
+ switch ((ExtSeqStatus) checkSeqStatus(twcc_ext_seq)) {
+ case ExtSeqStatus::jumped: /*回环后,收到回环前的大ext seq包,过滤掉*/ return;
+ case ExtSeqStatus::looped: /*回环,触发发送twcc rtcp*/ onSendTwcc(); break;
+ case ExtSeqStatus::normal: break;
+ default: /*不可达*/assert(0); break;
+ }
+
+ auto result = _rtp_recv_status.emplace(twcc_ext_seq, _ticker.createdTime());
+ if (!result.second) {
+ WarnL << "recv same twcc ext seq:" << twcc_ext_seq;
+ return;
+ }
+
+ _max_stamp = result.first->second;
+ if (!_min_stamp) {
+ _min_stamp = _max_stamp;
+ }
+
+ if (checkIfNeedSendTwcc()) {
+ //其他匹配条件立即发送twcc
+ onSendTwcc();
+ }
+}
+
+bool TwccContext::checkIfNeedSendTwcc() const {
+ auto size = _rtp_recv_status.size();
+ if (!size) {
+ return false;
+ }
+ if (size >= kMaxSeqDelta) {
+ return true;
+ }
+ auto delta_ms = _max_stamp - _min_stamp;
+ if (delta_ms >= kMaxTimeDelta) {
+ return true;
+ }
+ return false;
+}
+
+int TwccContext::checkSeqStatus(uint16_t twcc_ext_seq) const {
+ if (_rtp_recv_status.empty()) {
+ return (int) ExtSeqStatus::normal;
+ }
+ auto max = _rtp_recv_status.rbegin()->first;
+ if (max > 0xFF00 && twcc_ext_seq < 0xFF) {
+ //发生回环了
+ TraceL << "rtp twcc ext seq looped:" << max << " -> " << twcc_ext_seq;
+ return (int) ExtSeqStatus::looped;
+ }
+ if (twcc_ext_seq - max > 0xFFFF / 2) {
+ TraceL << "rtp twcc ext seq jumped:" << max << " -> " << twcc_ext_seq;
+ return (int) ExtSeqStatus::jumped;
+ }
+ return (int) ExtSeqStatus::normal;
+}
+
+void TwccContext::onSendTwcc() {
+ auto max = _rtp_recv_status.rbegin()->first;
+ 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;
+ }
+ }
+ clearStatus();
+}
+
+void TwccContext::clearStatus() {
+ _rtp_recv_status.clear();
+ _min_stamp = 0;
+}
diff --git a/webrtc/TwccContext.h b/webrtc/TwccContext.h
new file mode 100644
index 00000000..0c73c36e
--- /dev/null
+++ b/webrtc/TwccContext.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2021 The ZLMediaKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
+ *
+ * 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.
+ */
+
+#ifndef ZLMEDIAKIT_TWCCCONTEXT_H
+#define ZLMEDIAKIT_TWCCCONTEXT_H
+
+#include
+#include