Darwin Streaming Server 支持UDP打洞
来源:互联网 发布:淘宝网店设计 编辑:程序博客网 时间:2024/06/07 07:17
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 none Assert(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打洞
- Darwin Streaming Server 支持UDP穿透
- Darwin Streaming Server 支持UDP穿透
- Darwin Streaming Server 支持UDP穿透
- Darwin Streaming Server
- Darwin Streaming Server安装
- Darwin Streaming Server 简介
- Darwin Streaming Server编译
- Darwin Streaming Server 介绍
- DSS(Darwin Streaming Server)任务一:让直播支持拖放
- Darwin streaming server 流媒体服务器
- Darwin Streaming Server Relay问题
- Darwin Streaming Server程序结构分析
- Darwin-Streaming-Server On Ubuntu
- Darwin Streaming Server 安装 配置
- Darwin Streaming Server安装教程
- Darwin Streaming Server安装教程
- Darwin Streaming Server 安装流程
- chromium gn 使用备注
- Spring事务管理
- ViewFlipper初体验
- 什么是子网掩码?其与IP地址有何区别?
- 最优布线问题
- Darwin Streaming Server 支持UDP打洞
- 数据库中聚簇索引与非聚簇索引的区别[图文]
- tensorflow pycharm ImportError: libcudart.so.7.5
- MySQL 数据备份与还原
- 递归实现阶乘
- 【Android测试】自动化测试框架简介
- cmake修改vs--release调试
- 【leetcode】384. Shuffle an Array
- source tree 证书