diff --git a/server/main.cpp b/server/main.cpp index 8acd507b..5f6d4d45 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -25,7 +25,11 @@ #include "Rtp/RtpServer.h" #include "WebApi.h" #include "WebHook.h" -#include "../webrtc/Sdp.h" + +#if defined(ENABLE_WEBRTC) +#include "../webrtc/WebRtcTransport.h" +#include "../webrtc/WebRtcSession.h" +#endif #if defined(ENABLE_VERSION) #include "Version.h" @@ -255,13 +259,13 @@ int start_main(int argc,char *argv[]) { //加载配置文件,如果配置文件不存在就创建一个 loadIniConfig(g_ini_file.data()); - if(!File::is_dir(ssl_file.data())){ + if (!File::is_dir(ssl_file.data())) { //不是文件夹,加载证书,证书包含公钥和私钥 SSL_Initor::Instance().loadCertificate(ssl_file.data()); - }else{ + } else { //加载文件夹下的所有证书 - File::scanDir(ssl_file,[](const string &path, bool isDir){ - if(!isDir){ + File::scanDir(ssl_file, [](const string &path, bool isDir) { + if (!isDir) { //最后的一个证书会当做默认证书(客户端ssl握手时未指定主机) SSL_Initor::Instance().loadCertificate(path.data()); } @@ -283,56 +287,67 @@ int start_main(int argc,char *argv[]) { //简单的telnet服务器,可用于服务器调试,但是不能使用23端口,否则telnet上了莫名其妙的现象 //测试方法:telnet 127.0.0.1 9000 - TcpServer::Ptr shellSrv(new TcpServer()); + TcpServer::Ptr shellSrv = std::make_shared(); //rtsp[s]服务器, 可用于诸如亚马逊echo show这样的设备访问 - TcpServer::Ptr rtspSrv(new TcpServer()); - TcpServer::Ptr rtspSSLSrv(new TcpServer()); + TcpServer::Ptr rtspSrv = std::make_shared();; + TcpServer::Ptr rtspSSLSrv = std::make_shared();; //rtmp[s]服务器 - TcpServer::Ptr rtmpSrv(new TcpServer()); - TcpServer::Ptr rtmpsSrv(new TcpServer()); + TcpServer::Ptr rtmpSrv = std::make_shared();; + TcpServer::Ptr rtmpsSrv = std::make_shared();; //http[s]服务器 - TcpServer::Ptr httpSrv(new TcpServer()); - TcpServer::Ptr httpsSrv(new TcpServer()); + TcpServer::Ptr httpSrv = std::make_shared();; + TcpServer::Ptr httpsSrv = std::make_shared();; #if defined(ENABLE_RTPPROXY) //GB28181 rtp推流端口,支持UDP/TCP RtpServer::Ptr rtpServer = std::make_shared(); #endif//defined(ENABLE_RTPPROXY) +#if defined(ENABLE_WEBRTC) + //webrtc udp服务器 + UdpServer::Ptr rtcSrv = std::make_shared(); + uint16_t rtcPort = mINI::Instance()[RTC::kPort]; +#endif//defined(ENABLE_WEBRTC) + try { //rtsp服务器,端口默认554 - if(rtspPort) { rtspSrv->start(rtspPort); } + if (rtspPort) { rtspSrv->start(rtspPort); } //rtsps服务器,端口默认322 - if(rtspsPort) { rtspSSLSrv->start(rtspsPort); } + if (rtspsPort) { rtspSSLSrv->start(rtspsPort); } //rtmp服务器,端口默认1935 - if(rtmpPort) { rtmpSrv->start(rtmpPort); } + if (rtmpPort) { rtmpSrv->start(rtmpPort); } //rtmps服务器,端口默认19350 - if(rtmpsPort) { rtmpsSrv->start(rtmpsPort); } + if (rtmpsPort) { rtmpsSrv->start(rtmpsPort); } //http服务器,端口默认80 - if(httpPort) { httpSrv->start(httpPort); } + if (httpPort) { httpSrv->start(httpPort); } //https服务器,端口默认443 - if(httpsPort) { httpsSrv->start(httpsPort); } + if (httpsPort) { httpsSrv->start(httpsPort); } //telnet远程调试服务器 - if(shellPort) { shellSrv->start(shellPort); } + if (shellPort) { shellSrv->start(shellPort); } #if defined(ENABLE_RTPPROXY) //创建rtp服务器 - if(rtpPort){ rtpServer->start(rtpPort); } + if (rtpPort) { rtpServer->start(rtpPort); } #endif//defined(ENABLE_RTPPROXY) - }catch (std::exception &ex){ +#if defined(ENABLE_WEBRTC) + //webrtc udp服务器 + if (rtcPort) { rtcSrv->start(rtcPort); } +#endif//defined(ENABLE_WEBRTC) + + } catch (std::exception &ex) { WarnL << "端口占用或无权限:" << ex.what() << endl; ErrorL << "程序启动失败,请修改配置文件中端口号后重试!" << endl; sleep(1); #if !defined(_WIN32) - if(pid != getpid()){ - kill(pid,SIGINT); + if (pid != getpid()) { + kill(pid, SIGINT); } #endif return -1; diff --git a/webrtc/WebRtcSession.cpp b/webrtc/WebRtcSession.cpp new file mode 100644 index 00000000..9559f583 --- /dev/null +++ b/webrtc/WebRtcSession.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2016 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 "WebRtcSession.h" +#include "Util/util.h" + +WebRtcSession::WebRtcSession(const Socket::Ptr &sock) : UdpSession(sock) { + socklen_t addr_len = sizeof(_peer_addr); + getpeername(sock->rawFD(), &_peer_addr, &addr_len); + InfoP(this); +} + +WebRtcSession::~WebRtcSession() { + InfoP(this); +} + +void WebRtcSession::onRecv(const Buffer::Ptr &buffer) { + auto buf = buffer->data(); + auto len = buffer->size(); + + if (!_transport && RTC::StunPacket::IsStun((const uint8_t *) buf, len)) { + std::unique_ptr packet(RTC::StunPacket::Parse((const uint8_t *) buf, len)); + if (!packet) { + WarnL << "parse stun error"; + return; + } + if (packet->GetClass() == RTC::StunPacket::Class::REQUEST && + packet->GetMethod() == RTC::StunPacket::Method::BINDING) { + //收到binding request请求 + _transport = createTransport(packet->GetUsername()); + } + } + + if (_transport) { + _transport->inputSockData(buf, len, &_peer_addr); + } +} + +void WebRtcSession::onError(const SockException &err) { + if (_transport) { + _transport->unrefSelf(err); + _transport = nullptr; + } +} + +void WebRtcSession::onManager() { + +} + +std::shared_ptr WebRtcSession::createTransport(const string &user_name) { + if (user_name.empty()) { + return nullptr; + } + auto vec = split(user_name, ":"); + auto ret = WebRtcTransportImp::getTransport(vec[0]); + ret->setSession(this); + return ret; +} diff --git a/webrtc/WebRtcSession.h b/webrtc/WebRtcSession.h new file mode 100644 index 00000000..24b1eb7a --- /dev/null +++ b/webrtc/WebRtcSession.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2016 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_WEBRTCSESSION_H +#define ZLMEDIAKIT_WEBRTCSESSION_H + +#include "Network/Session.h" +#include "IceServer.hpp" +#include "WebRtcTransport.h" + +using namespace toolkit; + +class WebRtcSession : public UdpSession { +public: + WebRtcSession(const Socket::Ptr &sock); + ~WebRtcSession() override; + + void onRecv(const Buffer::Ptr &) override; + void onError(const SockException &err) override; + void onManager() override; + +private: + std::shared_ptr createTransport(const string &user_name); + +private: + struct sockaddr _peer_addr; + std::shared_ptr _transport; +}; + + +#endif //ZLMEDIAKIT_WEBRTCSESSION_H diff --git a/webrtc/WebRtcTransport.cpp b/webrtc/WebRtcTransport.cpp index 43c75d47..23c701b2 100644 --- a/webrtc/WebRtcTransport.cpp +++ b/webrtc/WebRtcTransport.cpp @@ -30,28 +30,59 @@ const string kTimeOutSec = RTC_FIELD"timeoutSec"; const string kExternIP = RTC_FIELD"externIP"; //设置remb比特率,非0时关闭twcc并开启remb。该设置在rtc推流时有效,可以控制推流画质 const string kRembBitRate = RTC_FIELD"rembBitRate"; +//webrtc单端口udp服务器 +const string kPort = RTC_FIELD"port"; static onceToken token([]() { mINI::Instance()[kTimeOutSec] = 15; mINI::Instance()[kExternIP] = ""; mINI::Instance()[kRembBitRate] = 0; + mINI::Instance()[kPort] = 8000; }); }//namespace RTC WebRtcTransport::WebRtcTransport(const EventPoller::Ptr &poller) { _poller = poller; - _dtls_transport = std::make_shared(poller, this); - _ice_server = std::make_shared(this, makeRandStr(4), makeRandStr(28).substr(4)); } void WebRtcTransport::onCreate(){ - + _key = to_string(reinterpret_cast(this)); + _dtls_transport = std::make_shared(_poller, this); + _ice_server = std::make_shared(this, _key, makeRandStr(24)); + refSelf(); } void WebRtcTransport::onDestory(){ _dtls_transport = nullptr; _ice_server = nullptr; + unrefSelf(SockException()); +} + +static mutex s_rtc_mtx; +static unordered_map > s_rtc_map; + +void WebRtcTransport::refSelf() { + _self = shared_from_this(); + + lock_guard lck(s_rtc_mtx); + s_rtc_map[_key] = static_pointer_cast(_self); +} + +void WebRtcTransport::unrefSelf(const SockException &ex) { + _self = nullptr; + + lock_guard lck(s_rtc_mtx); + s_rtc_map.erase(_key); +} + +WebRtcTransportImp::Ptr WebRtcTransportImp::getTransport(const string &key){ + lock_guard lck(s_rtc_mtx); + auto it = s_rtc_map.find(key); + if (it == s_rtc_map.end()) { + return nullptr; + } + return it->second.lock(); } const EventPoller::Ptr& WebRtcTransport::getPoller() const{ @@ -299,18 +330,7 @@ WebRtcTransportImp::Ptr WebRtcTransportImp::create(const EventPoller::Ptr &polle void WebRtcTransportImp::onCreate(){ WebRtcTransport::onCreate(); - _socket = Socket::createSocket(getPoller(), false); - //随机端口,绑定全部网卡 - _socket->bindUdpSock(0); - weak_ptr weak_self = shared_from_this(); - _socket->setOnRead([weak_self](const Buffer::Ptr &buf, struct sockaddr *addr, int addr_len) mutable { - auto strong_self = weak_self.lock(); - if (strong_self) { - strong_self->inputSockData(buf->data(), buf->size(), addr); - } - }); - _self = shared_from_this(); - + weak_ptr weak_self = static_pointer_cast(shared_from_this()); GET_CONFIG(float, timeoutSec, RTC::kTimeOutSec); _timer = std::make_shared(timeoutSec / 2, [weak_self]() { auto strong_self = weak_self.lock(); @@ -346,7 +366,7 @@ void WebRtcTransportImp::onDestory() { << _media_info._streamid << ")结束播放,耗时(s):" << duration; if (_bytes_usage >= iFlowThreshold * 1024) { - NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport, _media_info, _bytes_usage, duration, true, static_cast(*_socket)); + NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport, _media_info, _bytes_usage, duration, true, *static_cast(_session)); } } @@ -357,7 +377,7 @@ void WebRtcTransportImp::onDestory() { << _media_info._streamid << ")结束推流,耗时(s):" << duration; if (_bytes_usage >= iFlowThreshold * 1024) { - NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport, _media_info, _bytes_usage, duration, false, static_cast(*_socket)); + NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport, _media_info, _bytes_usage, duration, false, *static_cast(_session)); } } } @@ -375,7 +395,7 @@ void WebRtcTransportImp::attach(const RtspMediaSource::Ptr &src, const MediaInfo void WebRtcTransportImp::onSendSockData(const char *buf, size_t len, struct sockaddr_in *dst, bool flush) { auto ptr = BufferRaw::create(); ptr->assign(buf, len); - _socket->send(ptr, (struct sockaddr *)(dst), sizeof(struct sockaddr), flush); + _session->send(std::move(ptr)); } /////////////////////////////////////////////////////////////////// @@ -464,7 +484,7 @@ void WebRtcTransportImp::onStartWebRTC() { } if (canSendRtp()) { _reader = _play_src->getRing()->attach(getPoller(), true); - weak_ptr weak_self = shared_from_this(); + weak_ptr weak_self = static_pointer_cast(shared_from_this()); _reader->setReadCB([weak_self](const RtspMediaSource::RingDataType &pkt) { auto strongSelf = weak_self.lock(); if (!strongSelf) { @@ -516,7 +536,9 @@ void WebRtcTransportImp::onCheckSdp(SdpType type, RtcSession &sdp){ m.addr.address = extern_ip.empty() ? SockUtil::get_local_ip() : extern_ip; m.rtcp_addr.reset(); m.rtcp_addr.address = m.addr.address; - m.rtcp_addr.port = _socket->get_local_port(); + + GET_CONFIG(uint16_t, local_port, RTC::kPort); + m.rtcp_addr.port = local_port; m.port = m.rtcp_addr.port; sdp.origin.address = m.addr.address; } @@ -576,7 +598,8 @@ SdpAttrCandidate::Ptr WebRtcTransportImp::getIceCandidate() const{ candidate->priority = 100; GET_CONFIG(string, extern_ip, RTC::kExternIP); candidate->address = extern_ip.empty() ? SockUtil::get_local_ip() : extern_ip; - candidate->port = _socket->get_local_port(); + GET_CONFIG(uint16_t, local_port, RTC::kPort); + candidate->port = local_port; candidate->type = "host"; return candidate; } @@ -871,7 +894,7 @@ void WebRtcTransportImp::onSortedRtp(MediaTrack &track, const string &rid, RtpPa auto src_imp = std::make_shared(_push_src->getVhost(), _push_src->getApp(), stream_id); src_imp->setSdp(_push_src->getSdp()); src_imp->setProtocolTranslation(_push_src->isRecording(Recorder::type_hls),_push_src->isRecording(Recorder::type_mp4)); - src_imp->setListener(shared_from_this()); + src_imp->setListener(static_pointer_cast(shared_from_this())); src = src_imp; } src->onWrite(std::move(rtp), false); @@ -943,7 +966,11 @@ void WebRtcTransportImp::onBeforeEncryptRtp(const char *buf, int &len, void *ctx void WebRtcTransportImp::onShutdown(const SockException &ex){ WarnL << ex.what(); - _self = nullptr; + unrefSelf(ex); + if (_session) { + _session->shutdown(ex); + _session = nullptr; + } } ///////////////////////////////////////////////////////////////////////////////////////////// @@ -975,27 +1002,9 @@ string WebRtcTransportImp::getOriginUrl(MediaSource &sender) const { } std::shared_ptr WebRtcTransportImp::getOriginSock(MediaSource &sender) const { - return const_cast(this)->shared_from_this(); + return static_pointer_cast(const_cast(_session)->shared_from_this()); } -///////////////////////////////////////////////////////////////////////////////////////////// - -string WebRtcTransportImp::get_local_ip() { - return getSdp(SdpType::answer).media[0].candidate[0].address; -} - -uint16_t WebRtcTransportImp::get_local_port() { - return _socket->get_local_port(); -} - -string WebRtcTransportImp::get_peer_ip() { - return SockUtil::inet_ntoa(((struct sockaddr_in *) getSelectedTuple())->sin_addr); -} - -uint16_t WebRtcTransportImp::get_peer_port() { - return ntohs(((struct sockaddr_in *) getSelectedTuple())->sin_port); -} - -string WebRtcTransportImp::getIdentifier() const { - return StrPrinter << this; +void WebRtcTransportImp::setSession(Session *session) { + _session = session; } \ No newline at end of file diff --git a/webrtc/WebRtcTransport.h b/webrtc/WebRtcTransport.h index 94e9c8ec..2c1394a2 100644 --- a/webrtc/WebRtcTransport.h +++ b/webrtc/WebRtcTransport.h @@ -23,16 +23,24 @@ #include "Rtcp/RtcpContext.h" #include "Rtcp/RtcpFCI.h" #include "Nack.h" +#include "Network/Session.h" using namespace toolkit; using namespace mediakit; -class WebRtcTransport : public RTC::DtlsTransport::Listener, public RTC::IceServer::Listener { +//RTC配置项目 +namespace RTC { +extern const string kPort; +}//namespace RTC + +class WebRtcTransport : public RTC::DtlsTransport::Listener, public RTC::IceServer::Listener, public std::enable_shared_from_this { public: using Ptr = std::shared_ptr; WebRtcTransport(const EventPoller::Ptr &poller); ~WebRtcTransport() override = default; + void unrefSelf(const SockException &ex); + /** * 创建对象 */ @@ -115,9 +123,11 @@ protected: private: void onSendSockData(const char *buf, size_t len, bool flush = true); void setRemoteDtlsFingerprint(const RtcSession &remote); + void refSelf(); private: uint8_t _srtp_buf[2000]; + string _key; EventPoller::Ptr _poller; std::shared_ptr _ice_server; std::shared_ptr _dtls_transport; @@ -125,6 +135,8 @@ private: std::shared_ptr _srtp_session_recv; RtcSession::Ptr _offer_sdp; RtcSession::Ptr _answer_sdp; + //保持自我强引用 + WebRtcTransport::Ptr _self; }; class RtpChannel; @@ -149,7 +161,7 @@ public: std::shared_ptr getRtpChannel(uint32_t ssrc) const; }; -class WebRtcTransportImp : public WebRtcTransport, public MediaSourceEvent, public SockInfo, public std::enable_shared_from_this{ +class WebRtcTransportImp : public WebRtcTransport, public MediaSourceEvent{ public: using Ptr = std::shared_ptr; ~WebRtcTransportImp() override; @@ -160,6 +172,9 @@ public: * @return 对象 */ static Ptr create(const EventPoller::Ptr &poller); + static Ptr getTransport(const string &key); + + void setSession(Session *session); /** * 绑定rtsp媒体源 @@ -193,18 +208,6 @@ protected: // 获取媒体源客户端相关信息 std::shared_ptr getOriginSock(MediaSource &sender) const override; - ///////SockInfo override/////// - //获取本机ip - string get_local_ip() override; - //获取本机端口号 - uint16_t get_local_port() override; - //获取对方ip - string get_peer_ip() override; - //获取对方端口号 - uint16_t get_peer_port() override; - //获取标识符 - string getIdentifier() const override; - private: WebRtcTransportImp(const EventPoller::Ptr &poller); void onCreate() override; @@ -225,16 +228,14 @@ private: uint64_t _bytes_usage = 0; //媒体相关元数据 MediaInfo _media_info; - //保持自我强引用 - Ptr _self; //检测超时的定时器 Timer::Ptr _timer; //刷新计时器 Ticker _alive_ticker; //pli rtcp计时器 Ticker _pli_ticker; - //复合udp端口,接收一切rtp与rtcp - Socket::Ptr _socket; + //udp session + Session *_session; //推流的rtsp源 RtspMediaSource::Ptr _push_src; unordered_map _push_src_simulcast;