From 7110dc75ae8237be1a714cb8dbf729273470e4a0 Mon Sep 17 00:00:00 2001 From: ziyue <1213642868@qq.com> Date: Fri, 2 Apr 2021 17:08:11 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=B4=E7=90=86=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- webrtc/Sdp.cpp | 7 ++ webrtc/Sdp.h | 2 + webrtc/WebRtcTransport.cpp | 132 +++++++++++++++++++------------------ webrtc/WebRtcTransport.h | 108 +++++++++++++++++------------- 4 files changed, 142 insertions(+), 107 deletions(-) diff --git a/webrtc/Sdp.cpp b/webrtc/Sdp.cpp index 010aa5af..e96c660c 100644 --- a/webrtc/Sdp.cpp +++ b/webrtc/Sdp.cpp @@ -1237,6 +1237,13 @@ shared_ptr RtcConfigure::createAnswer(const RtcSession &offer){ if (ret->media.empty()) { throw std::invalid_argument("生成的answer sdp中媒体个数为0"); } + + //设置音视频端口复用 + if (!offer.group.mids.empty()) { + for (auto &m : ret->media) { + ret->group.mids.emplace_back(m.mid); + } + } return ret; } diff --git a/webrtc/Sdp.h b/webrtc/Sdp.h index 4d81c8fb..fa3b193c 100644 --- a/webrtc/Sdp.h +++ b/webrtc/Sdp.h @@ -437,6 +437,7 @@ public: class SdpAttrCandidate : public SdpItem { public: + using Ptr = std::shared_ptr; //https://tools.ietf.org/html/rfc5245 //15.1. "candidate" Attribute //a=candidate:4 1 udp 2 192.168.1.7 58107 typ host @@ -656,6 +657,7 @@ public: class RtcConfigure { public: + using Ptr = std::shared_ptr; class RtcTrackConfigure { public: bool enable; diff --git a/webrtc/WebRtcTransport.cpp b/webrtc/WebRtcTransport.cpp index 9468e3d1..f380603d 100644 --- a/webrtc/WebRtcTransport.cpp +++ b/webrtc/WebRtcTransport.cpp @@ -3,19 +3,19 @@ #include "Rtcp/Rtcp.h" WebRtcTransport::WebRtcTransport(const EventPoller::Ptr &poller) { - dtls_transport_ = std::make_shared(poller, this); - ice_server_ = std::make_shared(this, makeRandStr(4), makeRandStr(24)); + _dtls_transport = std::make_shared(poller, this); + _ice_server = std::make_shared(this, makeRandStr(4), makeRandStr(24)); } void WebRtcTransport::onDestory(){ - dtls_transport_ = nullptr; - ice_server_ = nullptr; + _dtls_transport = nullptr; + _ice_server = nullptr; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void WebRtcTransport::OnIceServerSendStunPacket(const RTC::IceServer *iceServer, const RTC::StunPacket *packet, RTC::TransportTuple *tuple) { - onWrite((char *)packet->GetData(), packet->GetSize(), (struct sockaddr_in *)tuple); + onSendSockData((char *) packet->GetData(), packet->GetSize(), (struct sockaddr_in *) tuple); } void WebRtcTransport::OnIceServerSelectedTuple(const RTC::IceServer *iceServer, RTC::TransportTuple *tuple) { @@ -29,9 +29,9 @@ void WebRtcTransport::OnIceServerConnected(const RTC::IceServer *iceServer) { void WebRtcTransport::OnIceServerCompleted(const RTC::IceServer *iceServer) { InfoL; if (_answer_sdp->media[0].role == DtlsRole::passive) { - dtls_transport_->Run(RTC::DtlsTransport::Role::SERVER); + _dtls_transport->Run(RTC::DtlsTransport::Role::SERVER); } else { - dtls_transport_->Run(RTC::DtlsTransport::Role::CLIENT); + _dtls_transport->Run(RTC::DtlsTransport::Role::CLIENT); } } @@ -50,21 +50,21 @@ void WebRtcTransport::OnDtlsTransportConnected( size_t srtpRemoteKeyLen, std::string &remoteCert) { InfoL; - srtp_session_ = std::make_shared(RTC::SrtpSession::Type::OUTBOUND, srtpCryptoSuite, srtpLocalKey, srtpLocalKeyLen); - srtp_session_recv_ = std::make_shared(RTC::SrtpSession::Type::OUTBOUND, srtpCryptoSuite, srtpRemoteKey, srtpRemoteKeyLen); - onDtlsConnected(); + _srtp_session_send = std::make_shared(RTC::SrtpSession::Type::OUTBOUND, srtpCryptoSuite, srtpLocalKey, srtpLocalKeyLen); + _srtp_session_recv = std::make_shared(RTC::SrtpSession::Type::OUTBOUND, srtpCryptoSuite, srtpRemoteKey, srtpRemoteKeyLen); + onStartWebRTC(); } void WebRtcTransport::OnDtlsTransportSendData(const RTC::DtlsTransport *dtlsTransport, const uint8_t *data, size_t len) { - onWrite((char *)data, len); + onSendSockData((char *)data, len); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void WebRtcTransport::onWrite(const char *buf, size_t len){ - auto tuple = ice_server_->GetSelectedTuple(); +void WebRtcTransport::onSendSockData(const char *buf, size_t len){ + auto tuple = _ice_server->GetSelectedTuple(); assert(tuple); - onWrite(buf, len, (struct sockaddr_in *)tuple); + onSendSockData(buf, len, (struct sockaddr_in *) tuple); } string getFingerprint(const string &algorithm_str, const std::shared_ptr &transport){ @@ -77,46 +77,47 @@ string getFingerprint(const string &algorithm_str, const std::shared_ptr(); - _offer_sdp->loadFrom(offer); - - SdpAttrFingerprint fingerprint; - fingerprint.algorithm = _offer_sdp->media[0].fingerprint.algorithm; - fingerprint.hash = getFingerprint(fingerprint.algorithm, dtls_transport_); - - RtcConfigure configure; - configure.setDefaultSetting(ice_server_->GetUsernameFragment(), ice_server_->GetPassword(), RtpDirection::recvonly, fingerprint); - - SdpAttrCandidate candidate; - candidate.foundation = "udpcandidate"; - candidate.component = 1; - candidate.transport = "udp"; - candidate.priority = getSSRC(); - candidate.address = getIP(); - candidate.port = getPort(); - candidate.type = "host"; - configure.addCandidate(candidate); - - _answer_sdp = configure.createAnswer(*_offer_sdp); - +void WebRtcTransport::setRemoteDtlsFingerprint(const RtcSession &remote){ //设置远端dtls签名 RTC::DtlsTransport::Fingerprint remote_fingerprint; remote_fingerprint.algorithm = RTC::DtlsTransport::GetFingerprintAlgorithm(_offer_sdp->media[0].fingerprint.algorithm); remote_fingerprint.value = _offer_sdp->media[0].fingerprint.hash; - dtls_transport_->SetRemoteFingerprint(remote_fingerprint); + _dtls_transport->SetRemoteFingerprint(remote_fingerprint); +} - if (!_offer_sdp->group.mids.empty()) { - for (auto &m : _answer_sdp->media) { - _answer_sdp->group.mids.emplace_back(m.mid); +void WebRtcTransport::onCheckSdp(SdpType type, const RtcSession &sdp) const{ + for (auto &m : sdp.media) { + if (m.type != TrackApplication && !m.rtcp_mux) { + throw std::invalid_argument("只支持rtcp-mux模式"); } - } else { - throw std::invalid_argument("支持group BUNDLE模式"); } + if (sdp.group.mids.empty()) { + throw std::invalid_argument("只支持group BUNDLE模式"); + } +} + +std::string WebRtcTransport::getAnswerSdp(const string &offer){ + //// 解析offer sdp //// + _offer_sdp = std::make_shared(); + _offer_sdp->loadFrom(offer); + onCheckSdp(SdpType::offer, *_offer_sdp); + setRemoteDtlsFingerprint(*_offer_sdp); + + //// sdp 配置 //// + SdpAttrFingerprint fingerprint; + fingerprint.algorithm = _offer_sdp->media[0].fingerprint.algorithm; + fingerprint.hash = getFingerprint(fingerprint.algorithm, _dtls_transport); + RtcConfigure configure; + configure.setDefaultSetting(_ice_server->GetUsernameFragment(), _ice_server->GetPassword(), RtpDirection::recvonly, fingerprint); + configure.addCandidate(*getIceCandidate()); + onRtcConfigure(configure); + + //// 生成answer sdp //// + _answer_sdp = configure.createAnswer(*_offer_sdp); + onCheckSdp(SdpType::answer, *_answer_sdp); auto str = _answer_sdp->toString(); - InfoL << "\r\n" << str; + TraceL << "\r\n" << str; return str; } @@ -134,18 +135,18 @@ bool is_rtcp(char *buf) { return ((header->pt >= 64) && (header->pt < 96)); } -void WebRtcTransport::OnInputDataPacket(char *buf, size_t len, RTC::TransportTuple *tuple) { +void WebRtcTransport::inputSockData(char *buf, size_t len, RTC::TransportTuple *tuple) { if (RTC::StunPacket::IsStun((const uint8_t *) buf, len)) { RTC::StunPacket *packet = RTC::StunPacket::Parse((const uint8_t *) buf, len); if (packet == nullptr) { WarnL << "parse stun error" << std::endl; return; } - ice_server_->ProcessStunPacket(packet, tuple); + _ice_server->ProcessStunPacket(packet, tuple); return; } if (is_dtls(buf)) { - dtls_transport_->ProcessDtlsData((uint8_t *) buf, len); + _dtls_transport->ProcessDtlsData((uint8_t *) buf, len); return; } if (is_rtp(buf)) { @@ -158,14 +159,14 @@ void WebRtcTransport::OnInputDataPacket(char *buf, size_t len, RTC::TransportTup } } -void WebRtcTransport::WritRtpPacket(char *buf, size_t len) { +void WebRtcTransport::sendRtpPacket(char *buf, size_t len) { const uint8_t *p = (uint8_t *) buf; bool ret = false; - if (srtp_session_) { - ret = srtp_session_->EncryptRtp(&p, &len); + if (_srtp_session_send) { + ret = _srtp_session_send->EncryptRtp(&p, &len); } if (ret) { - onWrite((char *) p, len); + onSendSockData((char *) p, len); } } @@ -183,7 +184,7 @@ WebRtcTransportImp::WebRtcTransportImp(const EventPoller::Ptr &poller) : WebRtcT //随机端口,绑定全部网卡 _socket->bindUdpSock(0); _socket->setOnRead([this](const Buffer::Ptr &buf, struct sockaddr *addr, int addr_len) mutable { - OnInputDataPacket(buf->data(), buf->size(), addr); + inputSockData(buf->data(), buf->size(), addr); }); } @@ -196,7 +197,7 @@ void WebRtcTransportImp::attach(const RtspMediaSource::Ptr &src) { _src = src; } -void WebRtcTransportImp::onDtlsConnected() { +void WebRtcTransportImp::onStartWebRTC() { _reader = _src->getRing()->attach(_socket->getPoller(), true); weak_ptr weak_self = shared_from_this(); _reader->setReadCB([weak_self](const RtspMediaSource::RingDataType &pkt){ @@ -207,14 +208,14 @@ void WebRtcTransportImp::onDtlsConnected() { pkt->for_each([&](const RtpPacket::Ptr &rtp) { if(rtp->type == TrackVideo) { //目前只支持视频 - strongSelf->WritRtpPacket(rtp->data() + RtpPacket::kRtpTcpHeaderSize, + strongSelf->sendRtpPacket(rtp->data() + RtpPacket::kRtpTcpHeaderSize, rtp->size() - RtpPacket::kRtpTcpHeaderSize); } }); }); } -void WebRtcTransportImp::onWrite(const char *buf, size_t len, struct sockaddr_in *dst) { +void WebRtcTransportImp::onSendSockData(const char *buf, size_t len, struct sockaddr_in *dst) { auto ptr = BufferRaw::create(); ptr->assign(buf, len); _socket->send(ptr, (struct sockaddr *)(dst), sizeof(struct sockaddr)); @@ -224,13 +225,6 @@ uint32_t WebRtcTransportImp::getSSRC() const { return _src->getSsrc(TrackVideo); } -int WebRtcTransportImp::getPayloadType() const{ - auto sdp = SdpParser(_src->getSdp()); - auto track = sdp.getTrack(TrackVideo); - assert(track); - return track ? track->_pt : 0; -} - uint16_t WebRtcTransportImp::getPort() const { //todo udp端口号应该与外网映射端口相同 return _socket->get_local_port(); @@ -241,6 +235,18 @@ std::string WebRtcTransportImp::getIP() const { return SockUtil::get_local_ip(); } +SdpAttrCandidate::Ptr WebRtcTransportImp::getIceCandidate() const{ + auto candidate = std::make_shared(); + candidate->foundation = "udpcandidate"; + candidate->component = 1; + candidate->transport = "udp"; + candidate->priority = 100; + candidate->address = getIP(); + candidate->port = getPort(); + candidate->type = "host"; + return candidate; +} + /////////////////////////////////////////////////////////////////// diff --git a/webrtc/WebRtcTransport.h b/webrtc/WebRtcTransport.h index 3a26b07b..f37bea0b 100644 --- a/webrtc/WebRtcTransport.h +++ b/webrtc/WebRtcTransport.h @@ -2,12 +2,16 @@ #include #include - #include "DtlsTransport.hpp" #include "IceServer.hpp" #include "SrtpSession.hpp" #include "StunPacket.hpp" #include "Sdp.h" +#include "Poller/EventPoller.h" +#include "Network/Socket.h" +#include "Rtsp/RtspMediaSource.h" +using namespace toolkit; +using namespace mediakit; class WebRtcTransport : public RTC::DtlsTransport::Listener, public RTC::IceServer::Listener { public: @@ -15,33 +19,43 @@ public: WebRtcTransport(const EventPoller::Ptr &poller); ~WebRtcTransport() override = default; - /// 销毁对象 + /** + * 消费对象 + */ virtual void onDestory(); + /** + * 创建webrtc answer sdp + * @param offer offer sdp + * @return answer sdp + */ std::string getAnswerSdp(const string &offer); - /// 收到udp数据 - /// \param buf - /// \param len - /// \param remote_address - void OnInputDataPacket(char *buf, size_t len, RTC::TransportTuple *tuple); + /** + * socket收到udp数据 + * @param buf 数据指针 + * @param len 数据长度 + * @param tuple 数据来源 + */ + void inputSockData(char *buf, size_t len, RTC::TransportTuple *tuple); - /// 发送rtp - /// \param buf - /// \param len - void WritRtpPacket(char *buf, size_t len); + /** + * 发送rtp + * @param buf rtcp内容 + * @param len rtcp长度 + */ + void sendRtpPacket(char *buf, size_t len); protected: - // dtls相关的回调 + //// dtls相关的回调 //// void OnDtlsTransportConnecting(const RTC::DtlsTransport *dtlsTransport) override {}; - void OnDtlsTransportConnected( - const RTC::DtlsTransport *dtlsTransport, - RTC::SrtpSession::CryptoSuite srtpCryptoSuite, - uint8_t *srtpLocalKey, - size_t srtpLocalKeyLen, - uint8_t *srtpRemoteKey, - size_t srtpRemoteKeyLen, - std::string &remoteCert) override; + void OnDtlsTransportConnected(const RTC::DtlsTransport *dtlsTransport, + RTC::SrtpSession::CryptoSuite srtpCryptoSuite, + uint8_t *srtpLocalKey, + size_t srtpLocalKeyLen, + uint8_t *srtpRemoteKey, + size_t srtpRemoteKeyLen, + std::string &remoteCert) override; void OnDtlsTransportFailed(const RTC::DtlsTransport *dtlsTransport) override {}; void OnDtlsTransportClosed(const RTC::DtlsTransport *dtlsTransport) override {}; @@ -49,7 +63,7 @@ protected: void OnDtlsTransportApplicationDataReceived(const RTC::DtlsTransport *dtlsTransport, const uint8_t *data, size_t len) override {}; protected: - //ice相关的回调 + //// ice相关的回调 /// void OnIceServerSendStunPacket(const RTC::IceServer *iceServer, const RTC::StunPacket *packet, RTC::TransportTuple *tuple) override; void OnIceServerSelectedTuple(const RTC::IceServer *iceServer, RTC::TransportTuple *tuple) override; void OnIceServerConnected(const RTC::IceServer *iceServer) override; @@ -57,51 +71,57 @@ protected: void OnIceServerDisconnected(const RTC::IceServer *iceServer) override; protected: - /// 输出udp数据 - /// \param buf - /// \param len - /// \param dst - virtual void onWrite(const char *buf, size_t len, struct sockaddr_in *dst) = 0; + virtual uint32_t getSSRC() const = 0; virtual uint16_t getPort() const = 0; virtual std::string getIP() const = 0; - virtual int getPayloadType() const = 0; - virtual void onDtlsConnected() = 0; + virtual void onStartWebRTC() = 0; + virtual void onRtcConfigure(RtcConfigure &configure) const {} + virtual void onCheckSdp(SdpType type, const RtcSession &sdp) const; + + virtual SdpAttrCandidate::Ptr getIceCandidate() const = 0; + virtual void onSendSockData(const char *buf, size_t len, struct sockaddr_in *dst) = 0; private: - void onWrite(const char *buf, size_t len); + void onSendSockData(const char *buf, size_t len); + void setRemoteDtlsFingerprint(const RtcSession &remote); private: - std::shared_ptr ice_server_; - std::shared_ptr dtls_transport_; - std::shared_ptr srtp_session_; - std::shared_ptr srtp_session_recv_; + std::shared_ptr _ice_server; + std::shared_ptr _dtls_transport; + std::shared_ptr _srtp_session_send; + std::shared_ptr _srtp_session_recv; RtcSession::Ptr _offer_sdp; RtcSession::Ptr _answer_sdp; }; -#include "Poller/EventPoller.h" -#include "Network/Socket.h" -#include "Rtsp/RtspMediaSource.h" -using namespace toolkit; -using namespace mediakit; - class WebRtcTransportImp : public WebRtcTransport, public std::enable_shared_from_this{ public: using Ptr = std::shared_ptr; - - static Ptr create(const EventPoller::Ptr &poller); ~WebRtcTransportImp() override = default; + /** + * 创建WebRTC对象 + * @param poller 改对象需要绑定的线程 + * @return 对象 + */ + static Ptr create(const EventPoller::Ptr &poller); + + /** + * 绑定rtsp媒体源 + * @param src 媒体源 + */ void attach(const RtspMediaSource::Ptr &src); protected: - void onWrite(const char *buf, size_t len, struct sockaddr_in *dst) override; - int getPayloadType() const override; + void onStartWebRTC() override; + void onSendSockData(const char *buf, size_t len, struct sockaddr_in *dst) override; uint32_t getSSRC() const override; uint16_t getPort() const override; std::string getIP() const override; - void onDtlsConnected() override; + SdpAttrCandidate::Ptr getIceCandidate() const override; + +private: WebRtcTransportImp(const EventPoller::Ptr &poller); void onDestory() override;