mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-22 19:00:01 +08:00
初步添加twcc rtcp发送逻辑
This commit is contained in:
parent
fc5b09365e
commit
dbc377a1f9
@ -428,8 +428,8 @@ static int16_t getRecvDelta(SymbolStatus status, uint8_t *&ptr, const uint8_t *e
|
|||||||
return delta;
|
return delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
map<uint16_t, std::pair<SymbolStatus, uint32_t/*stamp*/> > FCI_TWCC::getPacketChunkList(size_t total_size) const {
|
map<uint16_t, std::pair<SymbolStatus, int16_t/*stamp*/> > FCI_TWCC::getPacketChunkList(size_t total_size) const {
|
||||||
map<uint16_t, std::pair<SymbolStatus, uint32_t> > ret;
|
map<uint16_t, std::pair<SymbolStatus, int16_t> > ret;
|
||||||
auto ptr = (uint8_t *) this + kSize;
|
auto ptr = (uint8_t *) this + kSize;
|
||||||
auto end = (uint8_t *) this + total_size;
|
auto end = (uint8_t *) this + total_size;
|
||||||
CHECK(ptr < end);
|
CHECK(ptr < end);
|
||||||
|
@ -353,7 +353,7 @@ public:
|
|||||||
//单位64ms
|
//单位64ms
|
||||||
uint32_t getReferenceTime() const;
|
uint32_t getReferenceTime() const;
|
||||||
uint16_t getPacketCount() const;
|
uint16_t getPacketCount() const;
|
||||||
map<uint16_t, std::pair<SymbolStatus, uint32_t/*recv delta,单位为250us*/> > getPacketChunkList(size_t total_size) const;
|
map<uint16_t/*rtp ext seq*/, std::pair<SymbolStatus, int16_t/*recv delta,单位为250us*/> > getPacketChunkList(size_t total_size) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//base sequence number,基础序号,本次反馈的第一个包的序号;也就是RTP扩展头的序列号
|
//base sequence number,基础序号,本次反馈的第一个包的序号;也就是RTP扩展头的序列号
|
||||||
|
@ -239,7 +239,7 @@ string RtpExt::dumpString() const {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case RtpExtType::transport_cc : {
|
case RtpExtType::transport_cc : {
|
||||||
printer << "twcc seq:" << getTransportCCSeq();
|
printer << "twcc ext seq:" << getTransportCCSeq();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case RtpExtType::sdes_mid : {
|
case RtpExtType::sdes_mid : {
|
||||||
@ -546,6 +546,10 @@ RtpExtType RtpExt::getType() const {
|
|||||||
return _type;
|
return _type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RtpExt::operator bool() const {
|
||||||
|
return _ext != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
RtpExtContext::RtpExtContext(const RtcMedia &m){
|
RtpExtContext::RtpExtContext(const RtcMedia &m){
|
||||||
for (auto &ext : m.extmap) {
|
for (auto &ext : m.extmap) {
|
||||||
auto ext_type = RtpExt::getExtType(ext.ext);
|
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;
|
_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;
|
string rid, repaired_rid;
|
||||||
|
RtpExt ret;
|
||||||
auto ext_map = RtpExt::getExtValue(header);
|
auto ext_map = RtpExt::getExtValue(header);
|
||||||
for (auto &pr : ext_map) {
|
for (auto &pr : ext_map) {
|
||||||
if (is_recv) {
|
if (is_recv) {
|
||||||
@ -596,10 +601,13 @@ void RtpExtContext::changeRtpExtId(const RtpHeader *header, bool is_recv, string
|
|||||||
//重新赋值ext id为客户端sdp声明的类型
|
//重新赋值ext id为客户端sdp声明的类型
|
||||||
pr.second.setExtId(it->second);
|
pr.second.setExtId(it->second);
|
||||||
}
|
}
|
||||||
|
if (pr.second.getType() == type) {
|
||||||
|
ret = pr.second;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_recv) {
|
if (!is_recv) {
|
||||||
return;
|
return ret;
|
||||||
}
|
}
|
||||||
if (rid.empty()) {
|
if (rid.empty()) {
|
||||||
rid = repaired_rid;
|
rid = repaired_rid;
|
||||||
@ -619,6 +627,7 @@ void RtpExtContext::changeRtpExtId(const RtpHeader *header, bool is_recv, string
|
|||||||
if (rid_ptr) {
|
if (rid_ptr) {
|
||||||
*rid_ptr = rid;
|
*rid_ptr = rid;
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RtpExtContext::setOnGetRtp(OnGetRtp cb) {
|
void RtpExtContext::setOnGetRtp(OnGetRtp cb) {
|
||||||
|
@ -52,7 +52,7 @@ class RtpExt {
|
|||||||
public:
|
public:
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
friend void appendExt(map<uint8_t, RtpExt> &ret, uint8_t *ptr, const uint8_t *end);
|
friend void appendExt(map<uint8_t, RtpExt> &ret, uint8_t *ptr, const uint8_t *end);
|
||||||
|
friend class RtpExtContext;
|
||||||
~RtpExt() = default;
|
~RtpExt() = default;
|
||||||
|
|
||||||
static map<uint8_t/*id*/, RtpExt/*data*/> getExtValue(const RtpHeader *header);
|
static map<uint8_t/*id*/, RtpExt/*data*/> getExtValue(const RtpHeader *header);
|
||||||
@ -94,8 +94,10 @@ public:
|
|||||||
|
|
||||||
void setExtId(uint8_t ext_id);
|
void setExtId(uint8_t ext_id);
|
||||||
void clearExt();
|
void clearExt();
|
||||||
|
operator bool () const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
RtpExt() = default;
|
||||||
RtpExt(void *ptr, bool one_byte_ext, const char *str, size_t size);
|
RtpExt(void *ptr, bool one_byte_ext, const char *str, size_t size);
|
||||||
const char *data() const;
|
const char *data() const;
|
||||||
size_t size() const;
|
size_t size() const;
|
||||||
@ -122,7 +124,7 @@ public:
|
|||||||
void setOnGetRtp(OnGetRtp cb);
|
void setOnGetRtp(OnGetRtp cb);
|
||||||
string getRid(uint32_t ssrc) const;
|
string getRid(uint32_t ssrc) const;
|
||||||
void setRid(uint32_t ssrc, const string &rid);
|
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:
|
private:
|
||||||
void onGetRtp(uint8_t pt, uint32_t ssrc, const string &rid);
|
void onGetRtp(uint8_t pt, uint32_t ssrc, const string &rid);
|
||||||
|
98
webrtc/TwccContext.cpp
Normal file
98
webrtc/TwccContext.cpp
Normal file
@ -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;
|
||||||
|
}
|
46
webrtc/TwccContext.h
Normal file
46
webrtc/TwccContext.h
Normal file
@ -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 <stdint.h>
|
||||||
|
#include <map>
|
||||||
|
#include "Util/TimeTicker.h"
|
||||||
|
using namespace toolkit;
|
||||||
|
|
||||||
|
class TwccContext {
|
||||||
|
public:
|
||||||
|
//每个twcc rtcp包最多表明的rtp ext seq增量
|
||||||
|
static constexpr size_t kMaxSeqDelta = 20;
|
||||||
|
//每个twcc rtcp包发送的最大时间间隔,单位毫秒
|
||||||
|
static constexpr size_t kMaxTimeDelta = 64;
|
||||||
|
|
||||||
|
TwccContext() = default;
|
||||||
|
~TwccContext() = default;
|
||||||
|
|
||||||
|
void onRtp(uint16_t twcc_ext_seq);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onSendTwcc();
|
||||||
|
bool checkIfNeedSendTwcc() const;
|
||||||
|
int checkSeqStatus(uint16_t twcc_ext_seq) const;
|
||||||
|
void clearStatus();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ticker _ticker;
|
||||||
|
uint64_t _min_stamp = 0;
|
||||||
|
uint64_t _max_stamp;
|
||||||
|
std::map<uint32_t /*twcc_ext_seq*/, uint64_t/*recv time in ms*/> _rtp_recv_status;
|
||||||
|
uint8_t _twcc_pkt_count = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //ZLMEDIAKIT_TWCCCONTEXT_H
|
@ -808,7 +808,10 @@ void WebRtcTransportImp::onRtp(const char *buf, size_t len) {
|
|||||||
|
|
||||||
//修改ext id至统一
|
//修改ext id至统一
|
||||||
string rid;
|
string rid;
|
||||||
track->rtp_ext_ctx->changeRtpExtId(rtp, true, &rid);
|
auto twcc_ext = track->rtp_ext_ctx->changeRtpExtId(rtp, true, &rid, RtpExtType::transport_cc);
|
||||||
|
if (twcc_ext && !is_rtx) {
|
||||||
|
_twcc_ctx.onRtp(twcc_ext.getTransportCCSeq());
|
||||||
|
}
|
||||||
|
|
||||||
auto &ref = track->rtp_channel[rid];
|
auto &ref = track->rtp_channel[rid];
|
||||||
if (!ref) {
|
if (!ref) {
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "Rtcp/RtcpFCI.h"
|
#include "Rtcp/RtcpFCI.h"
|
||||||
#include "Nack.h"
|
#include "Nack.h"
|
||||||
#include "Network/Session.h"
|
#include "Network/Session.h"
|
||||||
|
#include "TwccContext.h"
|
||||||
|
|
||||||
using namespace toolkit;
|
using namespace toolkit;
|
||||||
using namespace mediakit;
|
using namespace mediakit;
|
||||||
@ -251,4 +252,5 @@ private:
|
|||||||
unordered_map<uint8_t/*pt*/, std::pair<bool/*is rtx*/,MediaTrack::Ptr> > _pt_to_track;
|
unordered_map<uint8_t/*pt*/, std::pair<bool/*is rtx*/,MediaTrack::Ptr> > _pt_to_track;
|
||||||
//根据rtcp的ssrc获取相关信息,收发rtp和rtx的ssrc都会记录
|
//根据rtcp的ssrc获取相关信息,收发rtp和rtx的ssrc都会记录
|
||||||
unordered_map<uint32_t/*ssrc*/, MediaTrack::Ptr> _ssrc_to_track;
|
unordered_map<uint32_t/*ssrc*/, MediaTrack::Ptr> _ssrc_to_track;
|
||||||
|
TwccContext _twcc_ctx;
|
||||||
};
|
};
|
Loading…
Reference in New Issue
Block a user