整理webrtc相关代码命名空间

This commit is contained in:
ziyue 2022-09-18 21:03:05 +08:00
parent 15affeff1d
commit 0b355759de
22 changed files with 164 additions and 111 deletions

View File

@ -24,6 +24,8 @@
#include "../webrtc/WebRtcPusher.h" #include "../webrtc/WebRtcPusher.h"
#include "../webrtc/WebRtcTransport.h" #include "../webrtc/WebRtcTransport.h"
using namespace mediakit;
namespace API { namespace API {
typedef enum { typedef enum {
NotFound = -500, //未找到 NotFound = -500, //未找到

View File

@ -286,7 +286,7 @@ int start_main(int argc,char *argv[]) {
} }
return Socket::createSocket(new_poller, false); return Socket::createSocket(new_poller, false);
}); });
uint16_t rtcPort = mINI::Instance()[RTC::kPort]; uint16_t rtcPort = mINI::Instance()[Rtc::kPort];
#endif//defined(ENABLE_WEBRTC) #endif//defined(ENABLE_WEBRTC)

View File

@ -83,7 +83,7 @@ onceToken token1([](){
} // namespace mediakit } // namespace mediakit
#define REALM "realm_zlmedaikit" #define REALM "realm_zlmediakit"
static map<string,FlvRecorder::Ptr> s_mapFlvRecorder; static map<string,FlvRecorder::Ptr> s_mapFlvRecorder;
static mutex s_mtxFlvRecorder; static mutex s_mtxFlvRecorder;

View File

@ -12,7 +12,8 @@
using namespace std; using namespace std;
using namespace toolkit; using namespace toolkit;
using namespace mediakit;
namespace mediakit {
static constexpr uint32_t kMaxNackMS = 5 * 1000; static constexpr uint32_t kMaxNackMS = 5 * 1000;
static constexpr uint32_t kRtpCacheCheckInterval = 100; static constexpr uint32_t kRtpCacheCheckInterval = 100;
@ -92,7 +93,6 @@ int64_t NackList::getRtpStamp(uint16_t seq) {
return it->second->getStampMS(false); return it->second->getStampMS(false);
} }
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
void NackContext::received(uint16_t seq, bool is_rtx) { void NackContext::received(uint16_t seq, bool is_rtx) {
@ -101,7 +101,7 @@ void NackContext::received(uint16_t seq, bool is_rtx) {
} }
if (is_rtx || (seq < _last_max_seq && !(seq < 1024 && _last_max_seq > UINT16_MAX - 1024))) { if (is_rtx || (seq < _last_max_seq && !(seq < 1024 && _last_max_seq > UINT16_MAX - 1024))) {
//重传包或 //重传包或
//seq回退且非回环那么这个应该是重传包 // seq回退且非回环那么这个应该是重传包
onRtx(seq); onRtx(seq);
return; return;
} }
@ -127,7 +127,7 @@ void NackContext::received(uint16_t seq, bool is_rtx) {
_seq.clear(); _seq.clear();
_last_max_seq = max_seq; _last_max_seq = max_seq;
} else { } else {
//seq不连续有丢包 // seq不连续有丢包
if (min_seq == _last_max_seq + 1) { if (min_seq == _last_max_seq + 1) {
//前面部分seq是连续的未丢包移除之 //前面部分seq是连续的未丢包移除之
eraseFrontSeq(); eraseFrontSeq();
@ -170,7 +170,7 @@ void NackContext::eraseFrontSeq() {
//前面部分seq是连续的未丢包移除之 //前面部分seq是连续的未丢包移除之
for (auto it = _seq.begin(); it != _seq.end();) { for (auto it = _seq.begin(); it != _seq.end();) {
if (*it != _last_max_seq + 1) { if (*it != _last_max_seq + 1) {
//seq不连续丢包了 // seq不连续丢包了
break; break;
} }
_last_max_seq = *it; _last_max_seq = *it;
@ -187,9 +187,9 @@ void NackContext::onRtx(uint16_t seq) {
_nack_send_status.erase(it); _nack_send_status.erase(it);
if (rtt >= 0) { if (rtt >= 0) {
//rtt不肯小于0 // rtt不肯小于0
_rtt = rtt; _rtt = rtt;
//InfoL << "rtt:" << rtt; // InfoL << "rtt:" << rtt;
} }
} }
@ -230,7 +230,7 @@ uint64_t NackContext::reSendNack() {
//更新nack发送时间戳 //更新nack发送时间戳
it->second.update_stamp = now; it->second.update_stamp = now;
if (++(it->second.nack_count) == kNackMaxCount) { if (++(it->second.nack_count) == kNackMaxCount) {
//nack次数太多移除之 // nack次数太多移除之
it = _nack_send_status.erase(it); it = _nack_send_status.erase(it);
continue; continue;
} }
@ -269,3 +269,5 @@ uint64_t NackContext::reSendNack() {
//重传间隔不得低于5ms //重传间隔不得低于5ms
return max(_rtt, 5); return max(_rtt, 5);
} }
} // namespace mediakit

View File

@ -14,38 +14,39 @@
#include "Rtsp/Rtsp.h" #include "Rtsp/Rtsp.h"
#include "Rtcp/RtcpFCI.h" #include "Rtcp/RtcpFCI.h"
namespace mediakit {
class NackList { class NackList {
public: public:
NackList() = default; NackList() = default;
~NackList() = default; ~NackList() = default;
void pushBack(mediakit::RtpPacket::Ptr rtp); void pushBack(RtpPacket::Ptr rtp);
void forEach(const mediakit::FCI_NACK &nack, const std::function<void(const mediakit::RtpPacket::Ptr &rtp)> &cb); void forEach(const FCI_NACK &nack, const std::function<void(const RtpPacket::Ptr &rtp)> &cb);
private: private:
void popFront(); void popFront();
uint32_t getCacheMS(); uint32_t getCacheMS();
int64_t getRtpStamp(uint16_t seq); int64_t getRtpStamp(uint16_t seq);
mediakit::RtpPacket::Ptr *getRtp(uint16_t seq); RtpPacket::Ptr *getRtp(uint16_t seq);
private: private:
uint32_t _cache_ms_check = 0; uint32_t _cache_ms_check = 0;
std::deque<uint16_t> _nack_cache_seq; std::deque<uint16_t> _nack_cache_seq;
std::unordered_map<uint16_t, mediakit::RtpPacket::Ptr> _nack_cache_pkt; std::unordered_map<uint16_t, RtpPacket::Ptr> _nack_cache_pkt;
}; };
class NackContext { class NackContext {
public: public:
using Ptr = std::shared_ptr<NackContext>; using Ptr = std::shared_ptr<NackContext>;
using onNack = std::function<void(const mediakit::FCI_NACK &nack)>; using onNack = std::function<void(const FCI_NACK &nack)>;
//最大保留的rtp丢包状态个数 //最大保留的rtp丢包状态个数
static constexpr auto kNackMaxSize = 2048; static constexpr auto kNackMaxSize = 2048;
//rtp丢包状态最长保留时间 // rtp丢包状态最长保留时间
static constexpr auto kNackMaxMS = 3 * 1000; static constexpr auto kNackMaxMS = 3 * 1000;
//nack最多请求重传10次 // nack最多请求重传10次
static constexpr auto kNackMaxCount = 10; static constexpr auto kNackMaxCount = 10;
//nack重传频率rtt的倍数 // nack重传频率rtt的倍数
static constexpr auto kNackIntervalRatio = 1.0f; static constexpr auto kNackIntervalRatio = 1.0f;
NackContext() = default; NackContext() = default;
@ -57,8 +58,8 @@ public:
private: private:
void eraseFrontSeq(); void eraseFrontSeq();
void doNack(const mediakit::FCI_NACK &nack, bool record_nack); void doNack(const FCI_NACK &nack, bool record_nack);
void recordNack(const mediakit::FCI_NACK &nack); void recordNack(const FCI_NACK &nack);
void onRtx(uint16_t seq); void onRtx(uint16_t seq);
private: private:
@ -67,12 +68,14 @@ private:
std::set<uint16_t> _seq; std::set<uint16_t> _seq;
uint16_t _last_max_seq = 0; uint16_t _last_max_seq = 0;
struct NackStatus{ struct NackStatus {
uint64_t first_stamp; uint64_t first_stamp;
uint64_t update_stamp; uint64_t update_stamp;
int nack_count = 0; int nack_count = 0;
}; };
std::map<uint16_t/*seq*/, NackStatus > _nack_send_status; std::map<uint16_t /*seq*/, NackStatus> _nack_send_status;
}; };
} // namespace mediakit
#endif //ZLMEDIAKIT_NACK_H #endif //ZLMEDIAKIT_NACK_H

View File

@ -17,7 +17,8 @@
using namespace std; using namespace std;
using namespace toolkit; using namespace toolkit;
using namespace mediakit;
namespace mediakit {
//https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01 //https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01
//https://tools.ietf.org/html/rfc5285 //https://tools.ietf.org/html/rfc5285
@ -644,3 +645,4 @@ void RtpExtContext::onGetRtp(uint8_t pt, uint32_t ssrc, const string &rid){
} }
} }
}// namespace mediakit

View File

@ -17,6 +17,7 @@
#include "Common/macros.h" #include "Common/macros.h"
#include "Rtsp/Rtsp.h" #include "Rtsp/Rtsp.h"
namespace mediakit {
#define RTP_EXT_MAP(XX) \ #define RTP_EXT_MAP(XX) \
XX(ssrc_audio_level, "urn:ietf:params:rtp-hdrext:ssrc-audio-level") \ XX(ssrc_audio_level, "urn:ietf:params:rtp-hdrext:ssrc-audio-level") \
@ -53,7 +54,7 @@ public:
friend class RtpExtContext; friend class RtpExtContext;
~RtpExt() = default; ~RtpExt() = default;
static std::map<uint8_t/*id*/, RtpExt/*data*/> getExtValue(const mediakit::RtpHeader *header); static std::map<uint8_t/*id*/, RtpExt/*data*/> getExtValue(const RtpHeader *header);
static RtpExtType getExtType(const std::string &url); static RtpExtType getExtType(const std::string &url);
static const std::string& getExtUrl(RtpExtType type); static const std::string& getExtUrl(RtpExtType type);
static const char *getExtName(RtpExtType type); static const char *getExtName(RtpExtType type);
@ -122,7 +123,7 @@ public:
void setOnGetRtp(OnGetRtp cb); void setOnGetRtp(OnGetRtp cb);
std::string getRid(uint32_t ssrc) const; std::string getRid(uint32_t ssrc) const;
void setRid(uint32_t ssrc, const std::string &rid); void setRid(uint32_t ssrc, const std::string &rid);
RtpExt changeRtpExtId(const mediakit::RtpHeader *header, bool is_recv, std::string *rid_ptr = nullptr, RtpExtType type = RtpExtType::padding); RtpExt changeRtpExtId(const RtpHeader *header, bool is_recv, std::string *rid_ptr = nullptr, RtpExtType type = RtpExtType::padding);
private: private:
void onGetRtp(uint8_t pt, uint32_t ssrc, const std::string &rid); void onGetRtp(uint8_t pt, uint32_t ssrc, const std::string &rid);
@ -137,4 +138,5 @@ private:
std::unordered_map<uint32_t/*simulcast ssrc*/, std::string/*rid*/> _ssrc_to_rid; std::unordered_map<uint32_t/*simulcast ssrc*/, std::string/*rid*/> _ssrc_to_rid;
}; };
} //namespace mediakit
#endif //ZLMEDIAKIT_RTPEXT_H #endif //ZLMEDIAKIT_RTPEXT_H

View File

@ -14,9 +14,10 @@
using namespace std; using namespace std;
using namespace toolkit; using namespace toolkit;
using namespace mediakit;
namespace RTC { namespace mediakit {
namespace Rtc {
#define RTC_FIELD "rtc." #define RTC_FIELD "rtc."
const string kPreferredCodecA = RTC_FIELD"preferredCodecA"; const string kPreferredCodecA = RTC_FIELD"preferredCodecA";
const string kPreferredCodecV = RTC_FIELD"preferredCodecV"; const string kPreferredCodecV = RTC_FIELD"preferredCodecV";
@ -1404,7 +1405,7 @@ void RtcConfigure::RtcTrackConfigure::setDefaultSetting(TrackType type){
switch (type) { switch (type) {
case TrackAudio: { case TrackAudio: {
//此处调整偏好的编码格式优先级 //此处调整偏好的编码格式优先级
GET_CONFIG_FUNC(vector<CodecId>, s_preferred_codec, RTC::kPreferredCodecA, toCodecArray); GET_CONFIG_FUNC(vector<CodecId>, s_preferred_codec, Rtc::kPreferredCodecA, toCodecArray);
CHECK(!s_preferred_codec.empty(), "rtc音频偏好codec不能为空"); CHECK(!s_preferred_codec.empty(), "rtc音频偏好codec不能为空");
preferred_codec = s_preferred_codec; preferred_codec = s_preferred_codec;
@ -1423,7 +1424,7 @@ void RtcConfigure::RtcTrackConfigure::setDefaultSetting(TrackType type){
} }
case TrackVideo: { case TrackVideo: {
//此处调整偏好的编码格式优先级 //此处调整偏好的编码格式优先级
GET_CONFIG_FUNC(vector<CodecId>, s_preferred_codec, RTC::kPreferredCodecV, toCodecArray); GET_CONFIG_FUNC(vector<CodecId>, s_preferred_codec, Rtc::kPreferredCodecV, toCodecArray);
CHECK(!s_preferred_codec.empty(), "rtc视频偏好codec不能为空"); CHECK(!s_preferred_codec.empty(), "rtc视频偏好codec不能为空");
preferred_codec = s_preferred_codec; preferred_codec = s_preferred_codec;
@ -1811,3 +1812,5 @@ void RtcConfigure::onSelectPlan(RtcCodecPlan &plan, CodecId codec) const {
plan.fmtp[kMode] = mode.empty() ? "0" : mode; plan.fmtp[kMode] = mode.empty() ? "0" : mode;
} }
} }
} // namespace mediakit

View File

@ -18,6 +18,8 @@
#include "Extension/Frame.h" #include "Extension/Frame.h"
#include "Common/Parser.h" #include "Common/Parser.h"
namespace mediakit {
//https://datatracker.ietf.org/doc/rfc4566/?include_text=1 //https://datatracker.ietf.org/doc/rfc4566/?include_text=1
//https://blog.csdn.net/aggresss/article/details/109850434 //https://blog.csdn.net/aggresss/article/details/109850434
//https://aggresss.blog.csdn.net/article/details/106436703 //https://aggresss.blog.csdn.net/article/details/106436703
@ -189,7 +191,7 @@ class SdpMedia : public SdpItem {
public: public:
// 5.14. Media Descriptions ("m=") // 5.14. Media Descriptions ("m=")
// m=<media> <port> <proto> <fmt> ... // m=<media> <port> <proto> <fmt> ...
mediakit::TrackType type; TrackType type;
uint16_t port; uint16_t port;
//RTP/AVP应用场景为视频/音频的 RTP 协议。参考 RFC 3551 //RTP/AVP应用场景为视频/音频的 RTP 协议。参考 RFC 3551
//RTP/SAVP应用场景为视频/音频的 SRTP 协议。参考 RFC 3711 //RTP/SAVP应用场景为视频/音频的 SRTP 协议。参考 RFC 3711
@ -374,7 +376,7 @@ class SdpAttrFmtp : public SdpItem {
public: public:
//fmtp:96 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f //fmtp:96 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f
uint8_t pt; uint8_t pt;
std::map<std::string/*key*/, std::string/*value*/, mediakit::StrCaseCompare> fmtp; std::map<std::string/*key*/, std::string/*value*/, StrCaseCompare> fmtp;
void parse(const std::string &str) override; void parse(const std::string &str) override;
std::string toString() const override; std::string toString() const override;
const char* getKey() const override { return "fmtp";} const char* getKey() const override { return "fmtp";}
@ -600,7 +602,7 @@ public:
uint32_t channel = 0; uint32_t channel = 0;
//rtcp反馈 //rtcp反馈
std::set<std::string> rtcp_fb; std::set<std::string> rtcp_fb;
std::map<std::string/*key*/, std::string/*value*/, mediakit::StrCaseCompare> fmtp; std::map<std::string/*key*/, std::string/*value*/, StrCaseCompare> fmtp;
std::string getFmtp(const char *key) const; std::string getFmtp(const char *key) const;
}; };
@ -608,7 +610,7 @@ public:
//rtc 媒体描述 //rtc 媒体描述
class RtcMedia{ class RtcMedia{
public: public:
mediakit::TrackType type{mediakit::TrackType::TrackInvalid}; TrackType type{TrackType::TrackInvalid};
std::string mid; std::string mid;
uint16_t port{0}; uint16_t port{0};
SdpConnection addr; SdpConnection addr;
@ -675,8 +677,8 @@ public:
void checkValid() const; void checkValid() const;
std::string toString() const; std::string toString() const;
std::string toRtspSdp() const; std::string toRtspSdp() const;
const RtcMedia *getMedia(mediakit::TrackType type) const; const RtcMedia *getMedia(TrackType type) const;
bool supportRtcpFb(const std::string &name, mediakit::TrackType type = mediakit::TrackType::TrackVideo) const; bool supportRtcpFb(const std::string &name, TrackType type = TrackType::TrackVideo) const;
bool supportSimulcast() const; bool supportSimulcast() const;
bool isOnlyDatachannel() const; bool isOnlyDatachannel() const;
@ -706,10 +708,10 @@ public:
std::set<std::string> rtcp_fb; std::set<std::string> rtcp_fb;
std::map<RtpExtType, RtpDirection> extmap; std::map<RtpExtType, RtpDirection> extmap;
std::vector<mediakit::CodecId> preferred_codec; std::vector<CodecId> preferred_codec;
std::vector<SdpAttrCandidate> candidate; std::vector<SdpAttrCandidate> candidate;
void setDefaultSetting(mediakit::TrackType type); void setDefaultSetting(TrackType type);
void enableTWCC(bool enable = true); void enableTWCC(bool enable = true);
void enableREMB(bool enable = true); void enableREMB(bool enable = true);
}; };
@ -719,19 +721,19 @@ public:
RtcTrackConfigure application; RtcTrackConfigure application;
void setDefaultSetting(std::string ice_ufrag, std::string ice_pwd, RtpDirection direction, const SdpAttrFingerprint &fingerprint); void setDefaultSetting(std::string ice_ufrag, std::string ice_pwd, RtpDirection direction, const SdpAttrFingerprint &fingerprint);
void addCandidate(const SdpAttrCandidate &candidate, mediakit::TrackType type = mediakit::TrackInvalid); void addCandidate(const SdpAttrCandidate &candidate, TrackType type = TrackInvalid);
std::shared_ptr<RtcSession> createAnswer(const RtcSession &offer) const; std::shared_ptr<RtcSession> createAnswer(const RtcSession &offer) const;
void setPlayRtspInfo(const std::string &sdp); void setPlayRtspInfo(const std::string &sdp);
void enableTWCC(bool enable = true, mediakit::TrackType type = mediakit::TrackInvalid); void enableTWCC(bool enable = true, TrackType type = TrackInvalid);
void enableREMB(bool enable = true, mediakit::TrackType type = mediakit::TrackInvalid); void enableREMB(bool enable = true, TrackType type = TrackInvalid);
private: private:
void matchMedia(const std::shared_ptr<RtcSession> &ret, const RtcMedia &media) const; void matchMedia(const std::shared_ptr<RtcSession> &ret, const RtcMedia &media) const;
bool onCheckCodecProfile(const RtcCodecPlan &plan, mediakit::CodecId codec) const; bool onCheckCodecProfile(const RtcCodecPlan &plan, CodecId codec) const;
void onSelectPlan(RtcCodecPlan &plan, mediakit::CodecId codec) const; void onSelectPlan(RtcCodecPlan &plan, CodecId codec) const;
private: private:
RtcCodecPlan::Ptr _rtsp_video_plan; RtcCodecPlan::Ptr _rtsp_video_plan;
@ -748,5 +750,6 @@ private:
~SdpConst() = delete; ~SdpConst() = delete;
}; };
}// namespace mediakit
#endif //ZLMEDIAKIT_SDP_H #endif //ZLMEDIAKIT_SDP_H

View File

@ -11,7 +11,7 @@
#include "TwccContext.h" #include "TwccContext.h"
#include "Rtcp/RtcpFCI.h" #include "Rtcp/RtcpFCI.h"
using namespace mediakit; namespace mediakit {
enum class ExtSeqStatus : int { enum class ExtSeqStatus : int {
normal = 0, normal = 0,
@ -121,3 +121,5 @@ void TwccContext::clearStatus() {
void TwccContext::setOnSendTwccCB(TwccContext::onSendTwccCB cb) { void TwccContext::setOnSendTwccCB(TwccContext::onSendTwccCB cb) {
_cb = std::move(cb); _cb = std::move(cb);
} }
}// namespace mediakit

View File

@ -16,6 +16,8 @@
#include <functional> #include <functional>
#include "Util/TimeTicker.h" #include "Util/TimeTicker.h"
namespace mediakit {
class TwccContext { class TwccContext {
public: public:
using onSendTwccCB = std::function<void(uint32_t ssrc, std::string fci)>; using onSendTwccCB = std::function<void(uint32_t ssrc, std::string fci)>;
@ -44,5 +46,5 @@ private:
onSendTwccCB _cb; onSendTwccCB _cb;
}; };
}// namespace mediakit
#endif //ZLMEDIAKIT_TWCCCONTEXT_H #endif //ZLMEDIAKIT_TWCCCONTEXT_H

View File

@ -10,6 +10,8 @@
#include "WebRtcEchoTest.h" #include "WebRtcEchoTest.h"
namespace mediakit {
WebRtcEchoTest::Ptr WebRtcEchoTest::create(const EventPoller::Ptr &poller) { WebRtcEchoTest::Ptr WebRtcEchoTest::create(const EventPoller::Ptr &poller) {
WebRtcEchoTest::Ptr ret(new WebRtcEchoTest(poller), [](WebRtcEchoTest *ptr) { WebRtcEchoTest::Ptr ret(new WebRtcEchoTest(poller), [](WebRtcEchoTest *ptr) {
ptr->onDestory(); ptr->onDestory();
@ -49,3 +51,5 @@ void WebRtcEchoTest::onCheckSdp(SdpType type, RtcSession &sdp) {
} }
} }
} }
}// namespace mediakit

View File

@ -13,6 +13,8 @@
#include "WebRtcTransport.h" #include "WebRtcTransport.h"
namespace mediakit {
class WebRtcEchoTest : public WebRtcTransportImp { class WebRtcEchoTest : public WebRtcTransportImp {
public: public:
using Ptr = std::shared_ptr<WebRtcEchoTest>; using Ptr = std::shared_ptr<WebRtcEchoTest>;
@ -26,7 +28,7 @@ protected:
void onRtp(const char *buf, size_t len, uint64_t stamp_ms) override; void onRtp(const char *buf, size_t len, uint64_t stamp_ms) override;
void onRtcp(const char *buf, size_t len) override; void onRtcp(const char *buf, size_t len) override;
void onRecvRtp(MediaTrack &track, const std::string &rid, mediakit::RtpPacket::Ptr rtp) override {}; void onRecvRtp(MediaTrack &track, const std::string &rid, RtpPacket::Ptr rtp) override {};
void onBeforeEncryptRtp(const char *buf, int &len, void *ctx) override {}; void onBeforeEncryptRtp(const char *buf, int &len, void *ctx) override {};
void onBeforeEncryptRtcp(const char *buf, int &len, void *ctx) override {}; void onBeforeEncryptRtcp(const char *buf, int &len, void *ctx) override {};
@ -34,4 +36,5 @@ private:
WebRtcEchoTest(const EventPoller::Ptr &poller); WebRtcEchoTest(const EventPoller::Ptr &poller);
}; };
}// namespace mediakit
#endif //ZLMEDIAKIT_WEBRTCECHOTEST_H #endif //ZLMEDIAKIT_WEBRTCECHOTEST_H

View File

@ -11,7 +11,8 @@
#include "WebRtcPlayer.h" #include "WebRtcPlayer.h"
using namespace std; using namespace std;
using namespace mediakit;
namespace mediakit {
WebRtcPlayer::Ptr WebRtcPlayer::create(const EventPoller::Ptr &poller, WebRtcPlayer::Ptr WebRtcPlayer::create(const EventPoller::Ptr &poller,
const RtspMediaSource::Ptr &src, const RtspMediaSource::Ptr &src,
@ -88,3 +89,5 @@ void WebRtcPlayer::onRtcConfigure(RtcConfigure &configure) const {
configure.audio.direction = configure.video.direction = RtpDirection::sendonly; configure.audio.direction = configure.video.direction = RtpDirection::sendonly;
configure.setPlayRtspInfo(_play_src->getSdp()); configure.setPlayRtspInfo(_play_src->getSdp());
} }
}// namespace mediakit

View File

@ -13,30 +13,32 @@
#include "WebRtcTransport.h" #include "WebRtcTransport.h"
namespace mediakit {
class WebRtcPlayer : public WebRtcTransportImp { class WebRtcPlayer : public WebRtcTransportImp {
public: public:
using Ptr = std::shared_ptr<WebRtcPlayer>; using Ptr = std::shared_ptr<WebRtcPlayer>;
~WebRtcPlayer() override = default; ~WebRtcPlayer() override = default;
static Ptr create(const EventPoller::Ptr &poller, const mediakit::RtspMediaSource::Ptr &src, const mediakit::MediaInfo &info); static Ptr create(const EventPoller::Ptr &poller, const RtspMediaSource::Ptr &src, const MediaInfo &info);
protected: protected:
///////WebRtcTransportImp override/////// ///////WebRtcTransportImp override///////
void onStartWebRTC() override; void onStartWebRTC() override;
void onDestory() override; void onDestory() override;
void onRtcConfigure(RtcConfigure &configure) const override; void onRtcConfigure(RtcConfigure &configure) const override;
void onRecvRtp(MediaTrack &track, const std::string &rid, mediakit::RtpPacket::Ptr rtp) override {}; void onRecvRtp(MediaTrack &track, const std::string &rid, RtpPacket::Ptr rtp) override {};
private: private:
WebRtcPlayer(const EventPoller::Ptr &poller, const mediakit::RtspMediaSource::Ptr &src, const mediakit::MediaInfo &info); WebRtcPlayer(const EventPoller::Ptr &poller, const RtspMediaSource::Ptr &src, const MediaInfo &info);
private: private:
//媒体相关元数据 //媒体相关元数据
mediakit::MediaInfo _media_info; MediaInfo _media_info;
//播放的rtsp源 //播放的rtsp源
mediakit::RtspMediaSource::Ptr _play_src; RtspMediaSource::Ptr _play_src;
//播放rtsp源的reader对象 //播放rtsp源的reader对象
mediakit::RtspMediaSource::RingType::RingReader::Ptr _reader; RtspMediaSource::RingType::RingReader::Ptr _reader;
}; };
}// namespace mediakit
#endif //ZLMEDIAKIT_WEBRTCPLAYER_H #endif // ZLMEDIAKIT_WEBRTCPLAYER_H

View File

@ -11,13 +11,14 @@
#include "WebRtcPusher.h" #include "WebRtcPusher.h"
using namespace std; using namespace std;
using namespace mediakit;
namespace mediakit {
WebRtcPusher::Ptr WebRtcPusher::create(const EventPoller::Ptr &poller, WebRtcPusher::Ptr WebRtcPusher::create(const EventPoller::Ptr &poller,
const RtspMediaSourceImp::Ptr &src, const RtspMediaSourceImp::Ptr &src,
const std::shared_ptr<void> &ownership, const std::shared_ptr<void> &ownership,
const MediaInfo &info, const MediaInfo &info,
const mediakit::ProtocolOption &option) { const ProtocolOption &option) {
WebRtcPusher::Ptr ret(new WebRtcPusher(poller, src, ownership, info, option), [](WebRtcPusher *ptr) { WebRtcPusher::Ptr ret(new WebRtcPusher(poller, src, ownership, info, option), [](WebRtcPusher *ptr) {
ptr->onDestory(); ptr->onDestory();
delete ptr; delete ptr;
@ -30,7 +31,7 @@ WebRtcPusher::WebRtcPusher(const EventPoller::Ptr &poller,
const RtspMediaSourceImp::Ptr &src, const RtspMediaSourceImp::Ptr &src,
const std::shared_ptr<void> &ownership, const std::shared_ptr<void> &ownership,
const MediaInfo &info, const MediaInfo &info,
const mediakit::ProtocolOption &option) : WebRtcTransportImp(poller) { const ProtocolOption &option) : WebRtcTransportImp(poller) {
_media_info = info; _media_info = info;
_push_src = src; _push_src = src;
_push_src_ownership = ownership; _push_src_ownership = ownership;
@ -142,7 +143,7 @@ void WebRtcPusher::onRtcConfigure(RtcConfigure &configure) const {
configure.audio.direction = configure.video.direction = RtpDirection::recvonly; configure.audio.direction = configure.video.direction = RtpDirection::recvonly;
} }
float WebRtcPusher::getLossRate(MediaSource &sender,mediakit::TrackType type){ float WebRtcPusher::getLossRate(MediaSource &sender,TrackType type){
return WebRtcTransportImp::getLossRate(type); return WebRtcTransportImp::getLossRate(type);
} }
@ -156,3 +157,5 @@ void WebRtcPusher::onRtcpBye(){
_push_src = nullptr; _push_src = nullptr;
WebRtcTransportImp::onRtcpBye(); WebRtcTransportImp::onRtcpBye();
} }
}// namespace mediakit

View File

@ -13,19 +13,21 @@
#include "WebRtcTransport.h" #include "WebRtcTransport.h"
class WebRtcPusher : public WebRtcTransportImp, public mediakit::MediaSourceEvent { namespace mediakit {
class WebRtcPusher : public WebRtcTransportImp, public MediaSourceEvent {
public: public:
using Ptr = std::shared_ptr<WebRtcPusher>; using Ptr = std::shared_ptr<WebRtcPusher>;
~WebRtcPusher() override = default; ~WebRtcPusher() override = default;
static Ptr create(const EventPoller::Ptr &poller, const mediakit::RtspMediaSourceImp::Ptr &src, static Ptr create(const EventPoller::Ptr &poller, const RtspMediaSourceImp::Ptr &src,
const std::shared_ptr<void> &ownership, const mediakit::MediaInfo &info, const mediakit::ProtocolOption &option); const std::shared_ptr<void> &ownership, const MediaInfo &info, const ProtocolOption &option);
protected: protected:
///////WebRtcTransportImp override/////// ///////WebRtcTransportImp override///////
void onStartWebRTC() override; void onStartWebRTC() override;
void onDestory() override; void onDestory() override;
void onRtcConfigure(RtcConfigure &configure) const override; void onRtcConfigure(RtcConfigure &configure) const override;
void onRecvRtp(MediaTrack &track, const std::string &rid, mediakit::RtpPacket::Ptr rtp) override; void onRecvRtp(MediaTrack &track, const std::string &rid, RtpPacket::Ptr rtp) override;
void onRtcpBye() override; void onRtcpBye() override;
//// dtls相关的回调 //// //// dtls相关的回调 ////
void OnDtlsTransportClosed(const RTC::DtlsTransport *dtlsTransport) override; void OnDtlsTransportClosed(const RTC::DtlsTransport *dtlsTransport) override;
@ -33,35 +35,36 @@ protected:
protected: protected:
///////MediaSourceEvent override/////// ///////MediaSourceEvent override///////
// 关闭 // 关闭
bool close(mediakit::MediaSource &sender) override; bool close(MediaSource &sender) override;
// 播放总人数 // 播放总人数
int totalReaderCount(mediakit::MediaSource &sender) override; int totalReaderCount(MediaSource &sender) override;
// 获取媒体源类型 // 获取媒体源类型
mediakit::MediaOriginType getOriginType(mediakit::MediaSource &sender) const override; MediaOriginType getOriginType(MediaSource &sender) const override;
// 获取媒体源url或者文件路径 // 获取媒体源url或者文件路径
std::string getOriginUrl(mediakit::MediaSource &sender) const override; std::string getOriginUrl(MediaSource &sender) const override;
// 获取媒体源客户端相关信息 // 获取媒体源客户端相关信息
std::shared_ptr<SockInfo> getOriginSock(mediakit::MediaSource &sender) const override; std::shared_ptr<SockInfo> getOriginSock(MediaSource &sender) const override;
// 获取丢包率 // 获取丢包率
float getLossRate(mediakit::MediaSource &sender,mediakit::TrackType type) override; float getLossRate(MediaSource &sender,TrackType type) override;
private: private:
WebRtcPusher(const EventPoller::Ptr &poller, const mediakit::RtspMediaSourceImp::Ptr &src, WebRtcPusher(const EventPoller::Ptr &poller, const RtspMediaSourceImp::Ptr &src,
const std::shared_ptr<void> &ownership, const mediakit::MediaInfo &info, const mediakit::ProtocolOption &option); const std::shared_ptr<void> &ownership, const MediaInfo &info, const ProtocolOption &option);
private: private:
bool _simulcast = false; bool _simulcast = false;
//断连续推延时 //断连续推延时
uint32_t _continue_push_ms = 0; uint32_t _continue_push_ms = 0;
//媒体相关元数据 //媒体相关元数据
mediakit::MediaInfo _media_info; MediaInfo _media_info;
//推流的rtsp源 //推流的rtsp源
mediakit::RtspMediaSourceImp::Ptr _push_src; RtspMediaSourceImp::Ptr _push_src;
//推流所有权 //推流所有权
std::shared_ptr<void> _push_src_ownership; std::shared_ptr<void> _push_src_ownership;
//推流的rtsp源,支持simulcast //推流的rtsp源,支持simulcast
std::unordered_map<std::string/*rid*/, mediakit::RtspMediaSource::Ptr> _push_src_sim; std::unordered_map<std::string/*rid*/, RtspMediaSource::Ptr> _push_src_sim;
std::unordered_map<std::string/*rid*/, std::shared_ptr<void> > _push_src_sim_ownership; std::unordered_map<std::string/*rid*/, std::shared_ptr<void> > _push_src_sim_ownership;
}; };
}// namespace mediakit
#endif //ZLMEDIAKIT_WEBRTCPUSHER_H #endif //ZLMEDIAKIT_WEBRTCPUSHER_H

View File

@ -12,7 +12,8 @@
#include "Util/util.h" #include "Util/util.h"
using namespace std; using namespace std;
using namespace mediakit;
namespace mediakit {
static string getUserName(const Buffer::Ptr &buffer) { static string getUserName(const Buffer::Ptr &buffer) {
auto buf = buffer->data(); auto buf = buffer->data();
@ -85,7 +86,7 @@ void WebRtcSession::onError(const SockException &err) {
} }
void WebRtcSession::onManager() { void WebRtcSession::onManager() {
GET_CONFIG(float, timeoutSec, RTC::kTimeOutSec); GET_CONFIG(float, timeoutSec, Rtc::kTimeOutSec);
if (!_transport && _ticker.createdTime() > timeoutSec * 1000) { if (!_transport && _ticker.createdTime() > timeoutSec * 1000) {
shutdown(SockException(Err_timeout, "illegal webrtc connection")); shutdown(SockException(Err_timeout, "illegal webrtc connection"));
return; return;
@ -96,5 +97,6 @@ void WebRtcSession::onManager() {
} }
} }
}// namespace mediakit

View File

@ -16,6 +16,8 @@
#include "IceServer.hpp" #include "IceServer.hpp"
#include "WebRtcTransport.h" #include "WebRtcTransport.h"
namespace mediakit {
class WebRtcSession : public UdpSession { class WebRtcSession : public UdpSession {
public: public:
WebRtcSession(const Socket::Ptr &sock); WebRtcSession(const Socket::Ptr &sock);
@ -35,5 +37,6 @@ private:
std::shared_ptr<WebRtcTransportImp> _transport; std::shared_ptr<WebRtcTransportImp> _transport;
}; };
}// namespace mediakit
#endif //ZLMEDIAKIT_WEBRTCSESSION_H #endif //ZLMEDIAKIT_WEBRTCSESSION_H

View File

@ -8,15 +8,18 @@
* may be found in the AUTHORS file in the root of the source tree. * may be found in the AUTHORS file in the root of the source tree.
*/ */
#include "WebRtcTransport.h" #include <iostream>
#include "Rtcp/Rtcp.h"
#include "Rtcp/RtcpFCI.h"
#include "RtpExt.h"
#include "Rtsp/RtpReceiver.h"
#include <srtp2/srtp.h> #include <srtp2/srtp.h>
#include <iostream> #include "RtpExt.h"
#include "Rtcp/Rtcp.h"
#include "Rtcp/RtcpFCI.h"
#include "Rtsp/RtpReceiver.h"
#include "WebRtcTransport.h"
#include "WebRtcEchoTest.h"
#include "WebRtcPlayer.h"
#include "WebRtcPusher.h"
#define RTP_SSRC_OFFSET 1 #define RTP_SSRC_OFFSET 1
#define RTX_SSRC_OFFSET 2 #define RTX_SSRC_OFFSET 2
@ -26,10 +29,11 @@
#define RTP_MSID RTP_MSLABEL " " RTP_LABEL #define RTP_MSID RTP_MSLABEL " " RTP_LABEL
using namespace std; using namespace std;
using namespace mediakit;
namespace mediakit {
// RTC配置项目 // RTC配置项目
namespace RTC { namespace Rtc {
#define RTC_FIELD "rtc." #define RTC_FIELD "rtc."
// rtp和rtcp接受超时时间 // rtp和rtcp接受超时时间
const string kTimeOutSec = RTC_FIELD "timeoutSec"; const string kTimeOutSec = RTC_FIELD "timeoutSec";
@ -246,7 +250,7 @@ void WebRtcTransport::setRemoteDtlsFingerprint(const RtcSession &remote) {
void WebRtcTransport::onRtcConfigure(RtcConfigure &configure) const { void WebRtcTransport::onRtcConfigure(RtcConfigure &configure) const {
// 开启remb后关闭twcc因为开启twcc后remb无效 // 开启remb后关闭twcc因为开启twcc后remb无效
GET_CONFIG(size_t, remb_bit_rate, RTC::kRembBitRate); GET_CONFIG(size_t, remb_bit_rate, Rtc::kRembBitRate);
configure.enableTWCC(!remb_bit_rate); configure.enableTWCC(!remb_bit_rate);
} }
@ -368,7 +372,7 @@ void WebRtcTransportImp::onCreate() {
registerSelf(); registerSelf();
weak_ptr<WebRtcTransportImp> weak_self = static_pointer_cast<WebRtcTransportImp>(shared_from_this()); weak_ptr<WebRtcTransportImp> weak_self = static_pointer_cast<WebRtcTransportImp>(shared_from_this());
GET_CONFIG(float, timeoutSec, RTC::kTimeOutSec); GET_CONFIG(float, timeoutSec, Rtc::kTimeOutSec);
_timer = std::make_shared<Timer>( _timer = std::make_shared<Timer>(
timeoutSec / 2, timeoutSec / 2,
[weak_self]() { [weak_self]() {
@ -511,7 +515,7 @@ void WebRtcTransportImp::onStartWebRTC() {
void WebRtcTransportImp::onCheckAnswer(RtcSession &sdp) { void WebRtcTransportImp::onCheckAnswer(RtcSession &sdp) {
// 修改answer sdp的ip、端口信息 // 修改answer sdp的ip、端口信息
GET_CONFIG_FUNC(std::vector<std::string>, extern_ips, RTC::kExternIP, [](string str) { GET_CONFIG_FUNC(std::vector<std::string>, extern_ips, Rtc::kExternIP, [](string str) {
std::vector<std::string> ret; std::vector<std::string> ret;
if (str.length()) { if (str.length()) {
ret = split(str, ","); ret = split(str, ",");
@ -525,7 +529,7 @@ void WebRtcTransportImp::onCheckAnswer(RtcSession &sdp) {
m.rtcp_addr.reset(); m.rtcp_addr.reset();
m.rtcp_addr.address = m.addr.address; m.rtcp_addr.address = m.addr.address;
GET_CONFIG(uint16_t, local_port, RTC::kPort); GET_CONFIG(uint16_t, local_port, Rtc::kPort);
m.rtcp_addr.port = local_port; m.rtcp_addr.port = local_port;
m.port = m.rtcp_addr.port; m.port = m.rtcp_addr.port;
sdp.origin.address = m.addr.address; sdp.origin.address = m.addr.address;
@ -592,9 +596,9 @@ makeIceCandidate(std::string ip, uint16_t port, uint32_t priority = 100, std::st
void WebRtcTransportImp::onRtcConfigure(RtcConfigure &configure) const { void WebRtcTransportImp::onRtcConfigure(RtcConfigure &configure) const {
WebRtcTransport::onRtcConfigure(configure); WebRtcTransport::onRtcConfigure(configure);
GET_CONFIG(uint16_t, local_port, RTC::kPort); GET_CONFIG(uint16_t, local_port, Rtc::kPort);
// 添加接收端口candidate信息 // 添加接收端口candidate信息
GET_CONFIG_FUNC(std::vector<std::string>, extern_ips, RTC::kExternIP, [](string str) { GET_CONFIG_FUNC(std::vector<std::string>, extern_ips, Rtc::kExternIP, [](string str) {
std::vector<std::string> ret; std::vector<std::string> ret;
if (str.length()) { if (str.length()) {
ret = split(str, ","); ret = split(str, ",");
@ -698,7 +702,7 @@ std::shared_ptr<RtpChannel> MediaTrack::getRtpChannel(uint32_t ssrc) const {
return it_chn->second; return it_chn->second;
} }
float WebRtcTransportImp::getLossRate(mediakit::TrackType type) { float WebRtcTransportImp::getLossRate(TrackType type) {
for (auto &pr : _ssrc_to_track) { for (auto &pr : _ssrc_to_track) {
auto ssrc = pr.first; auto ssrc = pr.first;
auto &track = pr.second; auto &track = pr.second;
@ -942,7 +946,7 @@ void WebRtcTransportImp::onSortedRtp(MediaTrack &track, const string &rid, RtpPa
sendRtcpPli(rtp->getSSRC()); sendRtcpPli(rtp->getSSRC());
// 开启remb则发送remb包调节比特率 // 开启remb则发送remb包调节比特率
GET_CONFIG(size_t, remb_bit_rate, RTC::kRembBitRate); GET_CONFIG(size_t, remb_bit_rate, Rtc::kRembBitRate);
if (remb_bit_rate && _answer_sdp->supportRtcpFb(SdpConst::kRembRtcpFb)) { if (remb_bit_rate && _answer_sdp->supportRtcpFb(SdpConst::kRembRtcpFb)) {
sendRtcpRemb(rtp->getSSRC(), remb_bit_rate); sendRtcpRemb(rtp->getSSRC(), remb_bit_rate);
} }
@ -1121,10 +1125,6 @@ void WebRtcPluginManager::getAnswerSdp(
it->second(sender, offer, args, cb); it->second(sender, offer, args, cb);
} }
#include "WebRtcEchoTest.h"
#include "WebRtcPlayer.h"
#include "WebRtcPusher.h"
void echo_plugin( void echo_plugin(
Session &sender, const string &offer, const WebRtcArgs &args, const WebRtcPluginManager::onCreateRtc &cb) { Session &sender, const string &offer, const WebRtcArgs &args, const WebRtcPluginManager::onCreateRtc &cb) {
cb(*WebRtcEchoTest::create(EventPollerPool::Instance().getPoller())); cb(*WebRtcEchoTest::create(EventPollerPool::Instance().getPoller()));
@ -1227,3 +1227,5 @@ static onceToken s_rtc_auto_register([]() {
WebRtcPluginManager::Instance().registerPlugin("push", push_plugin); WebRtcPluginManager::Instance().registerPlugin("push", push_plugin);
WebRtcPluginManager::Instance().registerPlugin("play", play_plugin); WebRtcPluginManager::Instance().registerPlugin("play", play_plugin);
}); });
}// namespace mediakit

View File

@ -27,8 +27,10 @@
#include "TwccContext.h" #include "TwccContext.h"
#include "SctpAssociation.hpp" #include "SctpAssociation.hpp"
namespace mediakit {
//RTC配置项目 //RTC配置项目
namespace RTC { namespace Rtc {
extern const std::string kPort; extern const std::string kPort;
extern const std::string kTimeOutSec; extern const std::string kTimeOutSec;
}//namespace RTC }//namespace RTC
@ -200,7 +202,7 @@ public:
//for send rtp //for send rtp
NackList nack_list; NackList nack_list;
mediakit::RtcpContext::Ptr rtcp_context_send; RtcpContext::Ptr rtcp_context_send;
//for recv rtp //for recv rtp
std::unordered_map<std::string/*rid*/, std::shared_ptr<RtpChannel> > rtp_channel; std::unordered_map<std::string/*rid*/, std::shared_ptr<RtpChannel> > rtp_channel;
@ -211,13 +213,13 @@ struct WrappedMediaTrack {
MediaTrack::Ptr track; MediaTrack::Ptr track;
explicit WrappedMediaTrack(MediaTrack::Ptr ptr): track(ptr) {} explicit WrappedMediaTrack(MediaTrack::Ptr ptr): track(ptr) {}
virtual ~WrappedMediaTrack() {} virtual ~WrappedMediaTrack() {}
virtual void inputRtp(const char *buf, size_t len, uint64_t stamp_ms, mediakit::RtpHeader *rtp) = 0; virtual void inputRtp(const char *buf, size_t len, uint64_t stamp_ms, RtpHeader *rtp) = 0;
}; };
struct WrappedRtxTrack: public WrappedMediaTrack { struct WrappedRtxTrack: public WrappedMediaTrack {
explicit WrappedRtxTrack(MediaTrack::Ptr ptr) explicit WrappedRtxTrack(MediaTrack::Ptr ptr)
: WrappedMediaTrack(std::move(ptr)) {} : WrappedMediaTrack(std::move(ptr)) {}
void inputRtp(const char *buf, size_t len, uint64_t stamp_ms, mediakit::RtpHeader *rtp) override; void inputRtp(const char *buf, size_t len, uint64_t stamp_ms, RtpHeader *rtp) override;
}; };
class WebRtcTransportImp; class WebRtcTransportImp;
@ -229,7 +231,7 @@ struct WrappedRtpTrack : public WrappedMediaTrack {
, _transport(t) {} , _transport(t) {}
TwccContext& _twcc_ctx; TwccContext& _twcc_ctx;
WebRtcTransportImp& _transport; WebRtcTransportImp& _transport;
void inputRtp(const char *buf, size_t len, uint64_t stamp_ms, mediakit::RtpHeader *rtp) override; void inputRtp(const char *buf, size_t len, uint64_t stamp_ms, RtpHeader *rtp) override;
}; };
class WebRtcTransportImp : public WebRtcTransport { class WebRtcTransportImp : public WebRtcTransport {
@ -243,7 +245,7 @@ public:
uint64_t getDuration() const; uint64_t getDuration() const;
bool canSendRtp() const; bool canSendRtp() const;
bool canRecvRtp() const; bool canRecvRtp() const;
void onSendRtp(const mediakit::RtpPacket::Ptr &rtp, bool flush, bool rtx = false); void onSendRtp(const RtpPacket::Ptr &rtp, bool flush, bool rtx = false);
void createRtpChannel(const std::string &rid, uint32_t ssrc, MediaTrack &track); void createRtpChannel(const std::string &rid, uint32_t ssrc, MediaTrack &track);
@ -262,14 +264,14 @@ protected:
void onCreate() override; void onCreate() override;
void onDestory() override; void onDestory() override;
void onShutdown(const SockException &ex) override; void onShutdown(const SockException &ex) override;
virtual void onRecvRtp(MediaTrack &track, const std::string &rid, mediakit::RtpPacket::Ptr rtp) = 0; virtual void onRecvRtp(MediaTrack &track, const std::string &rid, RtpPacket::Ptr rtp) = 0;
void updateTicker(); void updateTicker();
float getLossRate(mediakit::TrackType type); float getLossRate(TrackType type);
void onRtcpBye() override; void onRtcpBye() override;
private: private:
void onSortedRtp(MediaTrack &track, const std::string &rid, mediakit::RtpPacket::Ptr rtp); void onSortedRtp(MediaTrack &track, const std::string &rid, RtpPacket::Ptr rtp);
void onSendNack(MediaTrack &track, const mediakit::FCI_NACK &nack, uint32_t ssrc); void onSendNack(MediaTrack &track, const FCI_NACK &nack, uint32_t ssrc);
void onSendTwcc(uint32_t ssrc, const std::string &twcc_fci); void onSendTwcc(uint32_t ssrc, const std::string &twcc_fci);
void registerSelf(); void registerSelf();
@ -344,3 +346,5 @@ private:
mutable std::mutex _mtx_creator; mutable std::mutex _mtx_creator;
std::unordered_map<std::string, Plugin> _map_creator; std::unordered_map<std::string, Plugin> _map_creator;
}; };
}// namespace mediakit

View File

@ -16,6 +16,9 @@
- SrtpSession.cpp - SrtpSession.cpp
- SrtpSession.hpp - SrtpSession.hpp
- datachannel相关功能
- SctpAssociation.cpp
- SctpAssociation.hpp
以上源码有一定的修改和裁剪感谢MediaSoup开源项目及作者 以上源码有一定的修改和裁剪感谢MediaSoup开源项目及作者
用户在使用本项目的同时应该同时遵循MediaSoup的开源协议。 用户在使用本项目的同时应该同时遵循MediaSoup的开源协议。