diff --git a/conf/config.ini b/conf/config.ini index c7330ed2..35a6cc58 100644 --- a/conf/config.ini +++ b/conf/config.ini @@ -211,6 +211,8 @@ timeoutSec=15 timeoutSec=15 #本机对rtc客户端的可见ip,作为服务器时一般为公网ip,置空时,会自动获取网卡ip externIP= +#设置remb比特率,非0时关闭twcc并开启remb。该设置在rtc推流时有效,可以控制推流画质 +rembBitRate=1000000 [rtsp] #rtsp专有鉴权方式是采用base64还是md5方式 diff --git a/webrtc/Sdp.cpp b/webrtc/Sdp.cpp index 6317c87b..8a671f66 100644 --- a/webrtc/Sdp.cpp +++ b/webrtc/Sdp.cpp @@ -1241,10 +1241,18 @@ const RtcMedia *RtcSession::getMedia(TrackType type) const{ return nullptr; } +bool RtcSession::supportRtcpFb(const string &name, TrackType type) const { + auto media = getMedia(type); + if (!media) { + return false; + } + auto &ref = media->plan[0].rtcp_fb; + return ref.find(name) != ref.end(); +} + static string const kTWCCRtcpFb = "transport-cc"; static string const kTWCCExtMap = "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01"; - void RtcConfigure::RtcTrackConfigure::enableTWCC(bool enable){ if (!enable) { rtcp_fb.erase(kTWCCRtcpFb); diff --git a/webrtc/Sdp.h b/webrtc/Sdp.h index 6c9784b0..bcd1783c 100644 --- a/webrtc/Sdp.h +++ b/webrtc/Sdp.h @@ -667,6 +667,7 @@ public: string toString() const; string toRtspSdp() const; const RtcMedia *getMedia(TrackType type) const; + bool supportRtcpFb(const string &name, TrackType type = TrackType::TrackVideo) const; private: RtcSessionSdp::Ptr toRtcSessionSdp() const; diff --git a/webrtc/WebRtcTransport.cpp b/webrtc/WebRtcTransport.cpp index 80b3d6ae..178daca6 100644 --- a/webrtc/WebRtcTransport.cpp +++ b/webrtc/WebRtcTransport.cpp @@ -11,7 +11,9 @@ #include "WebRtcTransport.h" #include #include "Rtcp/Rtcp.h" +#include "Rtcp/RtcpFCI.h" #include "Rtsp/RtpReceiver.h" + #define RTX_SSRC_OFFSET 2 #define RTP_CNAME "zlmediakit-rtp" #define RTX_CNAME "zlmediakit-rtx" @@ -23,10 +25,13 @@ namespace RTC { const string kTimeOutSec = RTC_FIELD"timeoutSec"; //服务器外网ip const string kExternIP = RTC_FIELD"externIP"; +//设置remb比特率,非0时关闭twcc并开启remb。该设置在rtc推流时有效,可以控制推流画质 +const string kRembBitRate = RTC_FIELD"rembBitRate"; static onceToken token([]() { mINI::Instance()[kTimeOutSec] = 15; mINI::Instance()[kExternIP] = ""; + mINI::Instance()[kRembBitRate] = 0; }); }//namespace RTC @@ -134,6 +139,22 @@ RTC::TransportTuple* WebRtcTransport::getSelectedTuple() const{ return _ice_server->GetSelectedTuple(); } +void WebRtcTransport::sendRtcpRemb(uint32_t ssrc, size_t bit_rate) { + auto remb = FCI_REMB::create({ssrc}, (uint32_t)bit_rate); + auto fb = RtcpFB::create(PSFBType::RTCP_PSFB_REMB, remb.data(), remb.size()); + fb->ssrc = htonl(0); + fb->ssrc_media = htonl(ssrc); + sendRtcpPacket((char *) fb.get(), fb->getSize(), true); + TraceL << ssrc << " " << bit_rate; +} + +void WebRtcTransport::sendRtcpPli(uint32_t ssrc) { + auto pli = RtcpFB::create(PSFBType::RTCP_PSFB_PLI); + pli->ssrc = htonl(0); + pli->ssrc_media = htonl(ssrc); + sendRtcpPacket((char *) pli.get(), pli->getSize(), true); +} + string getFingerprint(const string &algorithm_str, const std::shared_ptr &transport){ auto algorithm = RTC::DtlsTransport::GetFingerprintAlgorithm(algorithm_str); for (auto &finger_prints : transport->GetLocalFingerprints()) { @@ -163,6 +184,12 @@ void WebRtcTransport::onCheckSdp(SdpType type, RtcSession &sdp){ } } +void WebRtcTransport::onRtcConfigure(RtcConfigure &configure) const { + //开启remb后关闭twcc,因为开启twcc后remb无效 + GET_CONFIG(size_t, remb_bit_rate, RTC::kRembBitRate); + configure.enableTWCC(!remb_bit_rate); +} + std::string WebRtcTransport::getAnswerSdp(const string &offer){ try { //// 解析offer sdp //// @@ -389,6 +416,10 @@ void WebRtcTransportImp::onStartWebRTC() { if (canRecvRtp()) { _push_src->setSdp(getSdp(SdpType::answer).toRtspSdp()); + GET_CONFIG(size_t, remb_bit_rate, RTC::kRembBitRate); + if (remb_bit_rate && getSdp(SdpType::answer).supportRtcpFb("goog-remb")) { + sendRtcpRemb(_recv_video_ssrc, remb_bit_rate); + } } if (canSendRtp()) { _reader = _play_src->getRing()->attach(getPoller(), true); @@ -592,10 +623,7 @@ void WebRtcTransportImp::onSortedRtp(const RtpPayloadInfo &info, RtpPacket::Ptr if (_pli_ticker.elapsedTime() > 2000) { //定期发送pli请求关键帧,方便非rtc等协议 _pli_ticker.resetTime(); - auto pli = RtcpFB::create(PSFBType::RTCP_PSFB_PLI); - pli->ssrc = htonl(0); - pli->ssrc_media = htonl(_recv_video_ssrc); - sendRtcpPacket((char *) pli.get(), pli->getSize(), true); + sendRtcpPli(_recv_video_ssrc); } if (_push_src) { _push_src->onWrite(std::move(rtp), false); diff --git a/webrtc/WebRtcTransport.h b/webrtc/WebRtcTransport.h index 50f45604..9cc64664 100644 --- a/webrtc/WebRtcTransport.h +++ b/webrtc/WebRtcTransport.h @@ -93,7 +93,7 @@ protected: protected: virtual void onStartWebRTC() = 0; - virtual void onRtcConfigure(RtcConfigure &configure) const {} + virtual void onRtcConfigure(RtcConfigure &configure) const; virtual void onCheckSdp(SdpType type, RtcSession &sdp); virtual void onSendSockData(const char *buf, size_t len, struct sockaddr_in *dst, bool flush = true) = 0; @@ -104,6 +104,8 @@ protected: protected: const RtcSession& getSdp(SdpType type) const; RTC::TransportTuple* getSelectedTuple() const; + void sendRtcpRemb(uint32_t ssrc, size_t bit_rate); + void sendRtcpPli(uint32_t ssrc); private: void onSendSockData(const char *buf, size_t len, bool flush = true);