本文主要是介绍Darwin Streaming Server 支持UDP打洞,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
RTSP客户端点播Darwin 视频时,SDP协商后的客户端端口可能是在NAT后面,所以需要Darwin支持NAT打洞的功能,从Darwin的源码看,官方的源码是不支持这个能力的。
通过抓取VLC客户端的包发现,VLC在播放RTSP流时,两次SETUP(音频流和视频分别协商端口)之后,会发送4个UDP打洞的包,但Darwin没有接收这些包,并且根据这些包来源的端口修改远端RTP和RTCP的端口。
文章Darwin Streaming Server 支持UDP穿透中给出了修改方法,尝试之后,发现有两个问题:
1、两次SETUP协商后,Darwin给返回的服务器的RTP和RTCP端口两次都一样
2、客户端发送的打洞的RTP和RTCP打洞的包,并没有接收完全。
针对问题1的修改就是将两次SETUP协商后,Darwin返回的端口不同并且唯一
问题2的修改方法是,在接收到SETUP协商后,开启一个线程接收发送到服务器的RTP和RTCP端口的包,并根据接收到的包的源端口更新远端的RTP和RTCP端口,即使没有收到打洞的包,不做任何处理,还是使用之前协商的端口往外发包。
第一个问题是将RTPStream::Setup方法中的:
fSockets = QTSServerInterface::GetServer()->GetSocketPool()->GetUDPSocketPair(sourceAddr, 0, fRemoteAddr,
fRemoteRTCPPort);
修改为:
fSockets = QTSServerInterface::GetServer()->GetSocketPool()->CreateUDPSocketPair(sourceAddr, 0);
并将UDPSocketPool::CreateUDPSocketPair方法中两个变量的初值修改为如下:
UInt16 curPort = kLowestUDPPort + usedNum++;
UInt16 stopPort = kHighestUDPPort -1; // prevent roll over when iterating over port nums
UInt16 socketBPort = curPort + 1;
第二个问题修改,头文件增加下面的方法和变量:
void start_thread_for_nat();void setRemoteRTPPort(int value){fRemoteRTPPort = value; }void setRemoteRTCPPort(int value){fRemoteRTCPPort = value;}UInt16 getRemoteRTPPort(){return fRemoteRTPPort;}UInt32 getRemoteRTPAddr(){return fRemoteAddr;}Bool16 getQuitValue(){return bQuit;}Bool16 getRunningValue(){return bRunning;}void setRunningValue(Bool16 value){ bRunning = value;}UInt16 getRemoteRTCPPort(){return fRemoteRTCPPort;}UDPSocketPair* getUDPSocketPair(){ return fSockets;}Bool16 bQuit;Bool16 bRunning;
在setup方法最后启动一个监听线程:
this->start_thread_for_nat();//errors should only be returned if there is a routing problem, there should be noneAssert(err == QTSS_NoErr);return QTSS_NoErr;
}
实现:
#include <pthread.h>
void* thread_for_nat(void *parms){Bool16 fUpdateRtpPort = false;Bool16 fUpdateRtcpPort = false;SInt64 currentTime = OS::Milliseconds();RTPStream *pRTPStream = (RTPStream *)parms;if (pRTPStream == NULL){return NULL;}if (pRTPStream->getUDPSocketPair() == NULL){return NULL;}if (pRTPStream->getUDPSocketPair()->GetSocketA() == NULL ||pRTPStream->getUDPSocketPair()->GetSocketB() == NULL){return NULL;}qtss_printf("thread_for_nat enter, pRTPStream:%08x, rtp_port:%d\n", pRTPStream, pRTPStream->getRemoteRTPPort());pRTPStream->setRunningValue(true);while(1){UInt32 iRemoteAddr = 0;UInt16 iRemotePort = 0;char szBuff[64];UInt32 iBufLen = sizeof(szBuff);UInt32 iRecvLen = 0;if (pRTPStream->getQuitValue()){break;}if (!fUpdateRtpPort){OS_Error iRet = pRTPStream->getUDPSocketPair()->GetSocketA()->RecvFrom(&iRemoteAddr, &iRemotePort, szBuff, iBufLen, &iRecvLen);if (OS_NoErr == iRet){if (iRemoteAddr == pRTPStream->getRemoteRTPAddr()&& iRemotePort != pRTPStream->getRemoteRTPPort()&& iRecvLen > 0){qtss_printf("thread_for_nat update GetSocketA iRet:%d, fRemoteRTPPort:%d, fRemoteRTCPPort:%d, iRemotePort:%d\n", iRet, pRTPStream->getRemoteRTPPort(), pRTPStream->getRemoteRTCPPort(), iRemotePort);pRTPStream->setRemoteRTPPort(iRemotePort);fUpdateRtpPort = true;}else{qtss_printf("thread_for_nat update GetSocketA received the same port value, fRemoteRTPPort:%d, fRemoteRTCPPort:%d\n", pRTPStream->getRemoteRTPPort(), pRTPStream->getRemoteRTCPPort());fUpdateRtpPort = true;}}else{//qtss_printf("Setup update GetSocketA iRet:%d, fRemoteRTPPort:%d, fRemoteRTCPPort:%d\n", iRet, fRemoteRTPPort, fRemoteRTCPPort);}}if (!fUpdateRtcpPort){OS_Error iRet = pRTPStream->getUDPSocketPair()->GetSocketB()->RecvFrom(&iRemoteAddr, &iRemotePort, szBuff, iBufLen, &iRecvLen);if (OS_NoErr == iRet){if (iRemoteAddr == pRTPStream->getRemoteRTPAddr()&& iRemotePort != pRTPStream->getRemoteRTCPPort()&& iRecvLen > 0){qtss_printf("thread_for_nat update GetSocketB iRet:%d, fRemoteRTPPort:%d, fRemoteRTCPPort:%d, iRemotePort:%d\n", iRet, pRTPStream->getRemoteRTPPort(), pRTPStream->getRemoteRTCPPort(), iRemotePort);pRTPStream->setRemoteRTCPPort(iRemotePort);fUpdateRtcpPort = true;} else{qtss_printf("thread_for_nat update GetSocketB received the same port value, fRemoteRTPPort:%d, fRemoteRTCPPort:%d\n", pRTPStream->getRemoteRTPPort(), pRTPStream->getRemoteRTCPPort());fUpdateRtcpPort = true;}}else{//wait.//qtss_printf("Setup update GetSocketB iRet:%d, fRemoteRTPPort:%d, fRemoteRTCPPort:%d\n", iRet, fRemoteRTPPort, fRemoteRTCPPort);}}if (fUpdateRtcpPort && fUpdateRtpPort){qtss_printf("thread_for_nat exit for update end, break, pRTPStream:%08x, rtp_port:%d\n", pRTPStream, pRTPStream->getRemoteRTPPort());break;}if ( (OS::Milliseconds() - currentTime ) > 2000){qtss_printf("thread_for_nat exaust 2000 ms, break, pRTPStream:%08x, rtp_port:%d\n", pRTPStream, pRTPStream->getRemoteRTPPort());break;}}pRTPStream->setRunningValue(false);gid_thread = -1;return NULL;
}void RTPStream::start_thread_for_nat(){int ret=pthread_create(&gid_thread, NULL, thread_for_nat, (void*)this);if (ret != 0){qtss_printf("err:%d\n", ret);}else{qtss_printf("start_thread_for_nat create OK\n");}
}
这篇关于Darwin Streaming Server 支持UDP打洞的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!