diff --git a/src/Rtsp/Rtsp.cpp b/src/Rtsp/Rtsp.cpp index 03c24c7d..f4d79462 100644 --- a/src/Rtsp/Rtsp.cpp +++ b/src/Rtsp/Rtsp.cpp @@ -365,5 +365,43 @@ bool RtspUrl::setup(bool isSSL, const string &strUrl, const string &strUser, con return true; } -}//namespace mediakit +std::pair makeSockPair_l(const EventPoller::Ptr &poller, const string &local_ip){ + auto pSockRtp = std::make_shared(poller); + if (!pSockRtp->bindUdpSock(0, local_ip.data())) { + //分配端口失败 + throw runtime_error("open udp socket failed"); + } + //是否是偶数 + bool even_numbers = pSockRtp->get_local_port() % 2 != 0; + auto pSockRtcp = std::make_shared(poller); + if (!pSockRtcp->bindUdpSock(pSockRtp->get_local_port() + (even_numbers ? 1 : -1), local_ip.data())) { + //分配端口失败 + throw runtime_error("open udp socket failed"); + } + + if (!even_numbers) { + //如果rtp端口不是偶数,那么与rtcp端口互换,目的是兼容一些要求严格的播放器或服务器 + Socket::Ptr tmp = pSockRtp; + pSockRtp = pSockRtcp; + pSockRtcp = tmp; + } + + return std::make_pair(pSockRtp, pSockRtcp); +} + +std::pair makeSockPair(const EventPoller::Ptr &poller, const string &local_ip){ + int try_count = 0; + while (true) { + try { + return makeSockPair_l(poller, local_ip); + } catch (...) { + if (++try_count == 3) { + throw; + } + WarnL << "open udp socket failed, retry: " << try_count; + } + } +} + +}//namespace mediakit \ No newline at end of file diff --git a/src/Rtsp/Rtsp.h b/src/Rtsp/Rtsp.h index 102bae11..7eb55a66 100644 --- a/src/Rtsp/Rtsp.h +++ b/src/Rtsp/Rtsp.h @@ -271,5 +271,7 @@ private: _StrPrinter _printer; }; +std::pair makeSockPair(const EventPoller::Ptr &poller, const string &local_ip); + } //namespace mediakit #endif //RTSP_RTSP_H_ diff --git a/src/Rtsp/RtspPlayer.cpp b/src/Rtsp/RtspPlayer.cpp index 52b77a45..dad4abe2 100644 --- a/src/Rtsp/RtspPlayer.cpp +++ b/src/Rtsp/RtspPlayer.cpp @@ -214,29 +214,10 @@ void RtspPlayer::handleResDESCRIBE(const Parser& parser) { void RtspPlayer::createUdpSockIfNecessary(int track_idx){ auto &rtpSockRef = _apRtpSock[track_idx]; auto &rtcpSockRef = _apRtcpSock[track_idx]; - if(!rtpSockRef){ - rtpSockRef.reset(new Socket(getPoller())); - //rtp随机端口 - if (!rtpSockRef->bindUdpSock(0, get_local_ip().data())) { - rtpSockRef.reset(); - throw std::runtime_error("open rtp sock failed"); - } - } - - if(!rtcpSockRef){ - rtcpSockRef.reset(new Socket(getPoller())); - //rtcp端口为rtp端口+1,目的是为了兼容某些服务器,其实更推荐随机端口 - if (!rtcpSockRef->bindUdpSock(rtpSockRef->get_local_port() + 1, get_local_ip().data())) { - rtcpSockRef.reset(); - throw std::runtime_error("open rtcp sock failed"); - } - } - - if(rtpSockRef->get_local_port() % 2 != 0){ - //如果rtp端口不是偶数,那么与rtcp端口互换,目的是兼容一些要求严格的服务器 - Socket::Ptr tmp = rtpSockRef; - rtpSockRef = rtcpSockRef; - rtcpSockRef = tmp; + if (!rtpSockRef || !rtcpSockRef) { + auto pr = makeSockPair(getPoller(), get_local_ip()); + rtpSockRef = pr.first; + rtcpSockRef = pr.second; } } diff --git a/src/Rtsp/RtspSession.cpp b/src/Rtsp/RtspSession.cpp index 37e7aaf6..c1baafa2 100644 --- a/src/Rtsp/RtspSession.cpp +++ b/src/Rtsp/RtspSession.cpp @@ -627,29 +627,18 @@ void RtspSession::handleReq_Setup(const Parser &parser) { } break; case Rtsp::RTP_UDP: { - //我们用trackIdx区分rtp和rtcp包 - auto pSockRtp = std::make_shared(_sock->getPoller()); - if (!pSockRtp->bindUdpSock(0,get_local_ip().data())) { + std::pair pr; + try{ + pr = makeSockPair(_sock->getPoller(), get_local_ip()); + }catch(std::exception &ex) { //分配端口失败 send_NotAcceptable(); - throw SockException(Err_shutdown, "open rtp socket failed"); - } - auto pSockRtcp = std::make_shared(_sock->getPoller()); - if (!pSockRtcp->bindUdpSock(pSockRtp->get_local_port() + 1,get_local_ip().data())) { - //分配端口失败 - send_NotAcceptable(); - throw SockException(Err_shutdown, "open rtcp socket failed"); + throw SockException(Err_shutdown, ex.what()); } - if(pSockRtp->get_local_port() % 2 != 0){ - //如果rtp端口不是偶数,那么与rtcp端口互换,目的是兼容一些要求严格的播放器 - Socket::Ptr tmp = pSockRtp; - pSockRtp = pSockRtcp; - pSockRtcp = tmp; - } + _apRtpSock[trackIdx] = pr.first; + _apRtcpSock[trackIdx] = pr.second; - _apRtpSock[trackIdx] = pSockRtp; - _apRtcpSock[trackIdx] = pSockRtcp; //设置客户端内网端口信息 string strClientPort = FindField(parser["Transport"].data(), "client_port=", NULL); uint16_t ui16RtpPort = atoi( FindField(strClientPort.data(), NULL, "-").data()); @@ -661,24 +650,24 @@ void RtspSession::handleReq_Setup(const Parser &parser) { peerAddr.sin_port = htons(ui16RtpPort); peerAddr.sin_addr.s_addr = inet_addr(get_peer_ip().data()); bzero(&(peerAddr.sin_zero), sizeof peerAddr.sin_zero); - pSockRtp->setSendPeerAddr((struct sockaddr *)(&peerAddr)); + pr.first->setSendPeerAddr((struct sockaddr *)(&peerAddr)); //设置rtcp发送目标地址 peerAddr.sin_family = AF_INET; peerAddr.sin_port = htons(ui16RtcpPort); peerAddr.sin_addr.s_addr = inet_addr(get_peer_ip().data()); bzero(&(peerAddr.sin_zero), sizeof peerAddr.sin_zero); - pSockRtcp->setSendPeerAddr((struct sockaddr *)(&peerAddr)); + pr.second->setSendPeerAddr((struct sockaddr *)(&peerAddr)); //尝试获取客户端nat映射地址 startListenPeerUdpData(trackIdx); //InfoP(this) << "分配端口:" << srv_port; sendRtspResponse("200 OK", - {"Transport",StrPrinter << "RTP/AVP/UDP;unicast;" - << "client_port=" << strClientPort << ";" - << "server_port=" << pSockRtp->get_local_port() << "-" << pSockRtcp->get_local_port() << ";" - << "ssrc=" << printSSRC(trackRef->_ssrc) + {"Transport", StrPrinter << "RTP/AVP/UDP;unicast;" + << "client_port=" << strClientPort << ";" + << "server_port=" << pr.first->get_local_port() << "-" << pr.second->get_local_port() << ";" + << "ssrc=" << printSSRC(trackRef->_ssrc) }); } break;