Doubango RTP包传输使用UDT可靠传输协议,解决RTP丢包问题

使用SIP做过VOIP通话的同学,肯定被RTP丢包弄的焦头烂额,必定尝试过不少的办法,比方:
1、丢包重传(NACK)
2、前向纠错(FEC)
3、丢帧处理
但效果往往不尽如人意,那有没有一劳永逸的方法?确实,网络发展到现在,家庭带宽随随便便都是百兆的今天,为什么还有让人困扰不已的丢包问题?为何不换成TCP传输,假如延时容许的情况下,UDT就是为了解决这个问题的。

UDT建立于UDP之上,并引入新的拥塞控制和数据可靠性控制机制。UDT是面向连接的双向的应用层协议。它同时支持可靠的数据流传输和部分可靠的数据报传输,UDT的特点是不用进行开发,直接利用库的发送函数就可以实现可靠的数据传输。

Doubango rtp接收和发送函数修改:

[cpp]  view plain  copy
  1. /* use transport udt*/  
  2. #include "udt_api.h"  
  3.   
  4. void *udt_transport_mainthread(void *param)  
  5. {  
  6.     trtp_manager_t *self = param;  
  7.   
  8.   
  9.     if(!self){  
  10.         TSK_DEBUG_ERROR("udt_transport_mainthread Invalid parameter");  
  11.         return 0;  
  12.     }  
  13.     TSK_DEBUG_INFO("ii udt_transport_mainthread enter, self->is_originated:%d", self->is_originated);  
  14.   
  15.     int rcv_buf = (int)tmedia_defaults_get_rtpbuff_size();  
  16.     int snd_buf = (int)tmedia_defaults_get_rtpbuff_size();  
  17.   
  18.     int clientFD = -1;                 
  19.     int socketfDUDT = -1;           
  20.     int clientSocket = -1;   
  21.     if (self->is_originated){  
  22.         //first listen  
  23.         int ret = init_udt(&socketfDUDT, (self->rtp.public_port), 0);  
  24.         self->serverSocket = socketfDUDT;  
  25.         TSK_DEBUG_INFO("socketfDUDT:%d listent", socketfDUDT);  
  26.   
  27.         set_connect_buff_udt(&socketfDUDT, rcv_buf, snd_buf);//set buff size  
  28.           
  29.         listen_udt(&socketfDUDT);          
  30.         clientFD = accept_udt(&socketfDUDT);  
  31.         if (clientFD == -1){  
  32.             TSK_DEBUG_ERROR("clientFd is failed");  
  33.             tsk_safeobj_lock(self);  
  34.             self->mainThreadId[0] = NULL;  
  35.             tsk_safeobj_unlock(self);//lyz@xdja.com add for crash.  
  36.   
  37.             goto FAILED;  
  38.         }   
  39.         TSK_DEBUG_INFO("clientFD:%d enter", clientFD);  
  40.   
  41.         if (!tmedia_defaults_get_single_connect()){  
  42.             //after connect 2 user  
  43.             ret = init_udt(&clientSocket, (self->rtp.public_port + 3), 0);  
  44.             set_connect_buff_udt(&clientSocket, rcv_buf, snd_buf);//set buff size  
  45.           
  46.             if (0 != ret || clientSocket == -1){  
  47.                 TSK_DEBUG_ERROR("clientSocket connect init is failed");  
  48.                 tsk_safeobj_lock(self);  
  49.                 self->mainThreadId[0] = NULL;  
  50.                 tsk_safeobj_unlock(self);//lyz@xdja.com add for crash.  
  51.   
  52.                 goto FAILED;  
  53.             }  
  54.             ret = connect_udt(&clientSocket, self->rtp.remote_ip, self->rtp.remote_port);  
  55.             if (-1 == ret){  
  56.                 TSK_DEBUG_ERROR("clientSocket connect is failed");  
  57.                 tsk_safeobj_lock(self);  
  58.                 self->mainThreadId[0] = NULL;  
  59.                 tsk_safeobj_unlock(self);//lyz@xdja.com add for crash.  
  60.   
  61.                 goto FAILED;  
  62.             }          
  63.             TSK_DEBUG_INFO("clientSocket:%d enter", clientSocket);  
  64.   
  65.             self->clientSocket = clientSocket;  
  66.         }  
  67.     }else{  
  68.         //first connect 2 user  
  69.         int ret = init_udt(&clientSocket, (self->rtp.public_port + 3), 0);  
  70.         if (0 != ret || clientSocket == -1){  
  71.             TSK_DEBUG_ERROR("ii clientSocket connect init is failed");  
  72.             tsk_safeobj_lock(self);  
  73.             self->mainThreadId[0] = NULL;  
  74.             tsk_safeobj_unlock(self);//lyz@xdja.com add for crash.  
  75.   
  76.             goto FAILED;  
  77.         }  
  78.         set_connect_buff_udt(&clientSocket, rcv_buf, snd_buf);//set buff size  
  79.         ret = connect_udt(&clientSocket, self->rtp.remote_ip, self->rtp.remote_port);  
  80.         if (-1 == ret){  
  81.             TSK_DEBUG_ERROR("clientSocket connect is failed");  
  82.             tsk_safeobj_lock(self);  
  83.             self->mainThreadId[0] = NULL;  
  84.             tsk_safeobj_unlock(self);//lyz@xdja.com add for crash.  
  85.   
  86.             goto FAILED;  
  87.         }  
  88.         self->clientSocket = clientSocket;  
  89.         TSK_DEBUG_INFO("ii clientSocket:%d enter", clientSocket);  
  90.           
  91.         if (!tmedia_defaults_get_single_connect()){  
  92.             //second listen  
  93.             ret = init_udt(&socketfDUDT, (self->rtp.public_port), 0);  
  94.             self->serverSocket = socketfDUDT;  
  95.             TSK_DEBUG_INFO("ii socketfDUDT:%d listent", socketfDUDT);  
  96.               
  97.             set_connect_buff_udt(&socketfDUDT, rcv_buf, snd_buf);//set buff size  
  98.             listen_udt(&socketfDUDT);  
  99.             clientFD = accept_udt(&socketfDUDT);  
  100.             if (clientFD == -1){  
  101.                 TSK_DEBUG_ERROR("clientFd is failed");  
  102.                 tsk_safeobj_lock(self);  
  103.                 self->mainThreadId[0] = NULL;  
  104.                 tsk_safeobj_unlock(self);//lyz@xdja.com add for crash.  
  105.   
  106.                 goto FAILED;  
  107.             }           
  108.             TSK_DEBUG_INFO("ii clientFD:%d enter", clientFD);  
  109.         }else{  
  110.                 tsk_safeobj_lock(self);  
  111.                 self->mainThreadId[0] = NULL;  
  112.                 tsk_safeobj_unlock(self);//lyz@xdja.com add for crash.  
  113.         }   
  114.     }  
  115.   
  116.     if (tmedia_defaults_get_single_connect()){  
  117.         if (self->is_originated){  
  118.             char buffer[4096];  
  119.             while(self->is_started){  
  120.                 int received = recvdata_udt(&clientFD, buffer, sizeof(buffer), 0);  
  121.   
  122.                 if (received <= -1) {  
  123.                     continue;  
  124.                 }  
  125.   
  126.                 _trtp_manager_recv_data(self, buffer, received, -1, NULL);  
  127.             }  
  128.         }  
  129.   
  130.     }else{  
  131.             char buffer[4096];  
  132.             while(self->is_started){  
  133.                 int received = recvdata_udt(&clientFD, buffer, sizeof(buffer), 0);  
  134.   
  135.                 if (received <= -1) {  
  136.                     continue;  
  137.                 }  
  138.   
  139.                 _trtp_manager_recv_data(self, buffer, received, -1, NULL);  
  140.             }  
  141.     }  
  142.   
  143. FAILED:          
  144.     if (-1 !=clientFD){  
  145.         close_udt(clientFD);  
  146.     }  
  147.     if (-1 !=socketfDUDT){  
  148.         close_udt(socketfDUDT);  
  149.     }  
  150.       
  151.     TSK_DEBUG_INFO("udt_transport_mainthread end.");  
  152.     return 0;  
  153. }  
  154.   
  155. int udt_transport_send(trtp_manager_t* self, char* encodedData, int encodedDataLen){  
  156.     TSK_DEBUG_INFO("senddata_udt START:%d", encodedDataLen);  
  157.   
  158.     int ret = senddata_udt(&self->clientSocket, encodedData, encodedDataLen, 0);  
  159.     if (-1 == ret){  
  160.     TSK_DEBUG_ERROR("senddata_udt failed");  
  161.         return -1;  
  162.     }  
  163.     TSK_DEBUG_INFO("senddata_udt ret:%d", ret);  
  164.       
  165.     return ret;  
  166. }  
  167. /* add end */  

启动:在 int trtp_manager_start(trtp_manager_t* self)中:

[cpp]  view plain  copy
  1. if(!self->transport || !self->transport->master){  
  2.              //use other transport --udt:  
  3.              if (tmedia_defaults_get_use_udt_socket() != 0){  
  4.                    //use other transport.  
  5.                    self->clientSocket = -1;  
  6.                    self->serverSocket = -1;  
  7.                    self->is_started = tsk_true;  
  8.   
  9.                    if ((ret = tsk_thread_create(self->mainThreadId, udt_transport_mainthread, self))){ /* More important than "tsk_runnable_start" ==> start it first. */  
  10.                        TSK_DEBUG_FATAL("Failed to create udt main thread [%d]", ret);  
  11.                    }else{             
  12.              TSK_DEBUG_INFO("udt thread create success.");            
  13.                   
  14. if !TNET_UNDER_APPLE  
  15.                        ret = tsk_thread_set_priority(self->mainThreadId[0], TSK_THREAD_PRIORITY_TIME_CRITICAL);  
  16. endif  
  17.                        tsk_safeobj_unlock(self);  
  18.     
  19.                        return 0;  
  20.                    }  
  21.              }  
  22.              //add end.  
  23.                
  24.     TSK_DEBUG_ERROR("RTP/RTCP manager not prepared");  
  25.     ret = -2;  
  26.     goto bail;  
  27. }  
  28.      



UDT协议封装:

[cpp]  view plain  copy
  1. int init_udt(int *usock, int port, bool rendezvous);  
  2. int connect_udt(void* usocket, char *peerip, int port);  
  3. int set_connect_buff_udt(void* usocket, int send_buf_size, int recv_buf_size);  
  4. int recvdata_udt(void* usocket, char* buf, int size, int flags);  
  5. int senddata_udt(void* usocket, char* buf, int size, int flags);  
  6. int listen_udt(void* usocket);  
  7. int accept_udt(void* usocket);  
  8. int close_udt(int usock);  

实现: 

[cpp]  view plain  copy
  1. #include <winsock2.h>  
  2. #include <ws2tcpip.h>  
  3. #include <wspiapi.h>  
  4. #include <iostream>  
  5. #include <udt.h>  
  6. #include <arpa/inet.h>   
  7. #include <android/log.h>  
  8. #define TAG "UDT_API"  
  9.   
  10. extern "C" int init_udt(int *usock, int port, bool rendezvous);  
  11. extern "C" int connect_udt(void* usocket, char *peerip, int port);  
  12. extern "C" int set_connect_buff_udt(void* usocket, int send_buf_size, int recv_buf_size);  
  13. extern "C" int recvdata_udt(void* usocket, char* buf, int size, int flags);  
  14. extern "C" int senddata_udt(void* usocket, char* buf, int size, int flags);  
  15. extern "C" int listen_udt(void* usocket);  
  16. extern "C" int accept_udt(void* usocket);  
  17. extern "C" int close_udt(int usock);  
  18.   
  19. using namespace std;  
  20.   
  21. const int g_IP_Version = AF_INET;  
  22. const int g_Socket_Type = SOCK_DGRAM;  
  23. const char g_Localhost[] = "127.0.0.1";  
  24.     
  25. int init_udt(int *usock, int port, bool rendezvous){  
  26.     addrinfo hints;  
  27.     addrinfo* res;  
  28.     memset(&hints, 0, sizeof(struct addrinfo));  
  29.     hints.ai_flags = AI_PASSIVE;  
  30.     hints.ai_family = AF_INET;  
  31.     hints.ai_socktype = g_Socket_Type;  
  32.   
  33.     if (usock == NULL){  
  34.         return -1;  
  35.     }  
  36.   
  37.     char service[16];  
  38.     sprintf(service, "%d", port);  
  39.   
  40.     if (0 != getaddrinfo(NULL, service, &hints, &res))  
  41.     {  
  42.         cout << "illegal port number or port is busy.\n" << endl;             
  43.              __android_log_print(ANDROID_LOG_WARN, TAG, "illegal port number or port is busy:%s", UDT::getlasterror().getErrorMessage() );  
  44.   
  45.         return -1;  
  46.     }  
  47.   
  48.     UDTSOCKET retFD = UDT::socket(res->ai_family, res->ai_socktype, res->ai_protocol);  
  49.   
  50.     // since we will start a lot of connections, we set the buffer size to smaller value.  
  51.     int snd_buf = 16000;  
  52.     int rcv_buf = 16000;  
  53.     UDT::setsockopt(retFD, 0, UDT_SNDBUF, &snd_buf, sizeof(int));  
  54.     UDT::setsockopt(retFD, 0, UDT_RCVBUF, &rcv_buf, sizeof(int));   
  55.     //int fc = 16;  
  56.     //UDT::setsockopt(retFD, 0, UDT_FC, &fc, sizeof(int));  
  57.     bool reuse = true;  
  58.     UDT::setsockopt(retFD, 0, UDT_REUSEADDR, &reuse, sizeof(bool));  
  59.     UDT::setsockopt(retFD, 0, UDT_RENDEZVOUS, &rendezvous, sizeof(bool));  
  60.   
  61.     if (UDT::ERROR == UDT::bind(retFD, res->ai_addr, res->ai_addrlen))  
  62.     {  
  63.             __android_log_print(ANDROID_LOG_WARN, TAG, "err, init failed:%s", UDT::getlasterror().getErrorMessage() );  
  64.         cout << "bind: " << UDT::getlasterror().getErrorMessage() << endl;  
  65.         return -1;  
  66.     }   
  67.   
  68.     *usock = retFD;//set output socket fd.  
  69.   
  70.     freeaddrinfo(res);  
  71.     return 0;  
  72. }  
  73.    
  74. int connect_udt(void* usocket, char *peerip, int port){  
  75.     if (usocket == NULL || peerip == NULL){  
  76.         return -1;  
  77.     }  
  78.     UDTSOCKET usock = *(UDTSOCKET*)usocket;  
  79.       
  80.     addrinfo hints, *peer;  
  81.     memset(&hints, 0, sizeof(struct addrinfo));  
  82.     hints.ai_flags = AI_PASSIVE;  
  83.     hints.ai_family =  g_IP_Version;  
  84.     hints.ai_socktype = g_Socket_Type;  
  85.   
  86.     char buffer[16];  
  87.     sprintf(buffer, "%d", port);  
  88.    
  89.     if (0 != getaddrinfo(peerip, buffer, &hints, &peer))  
  90.     {  
  91.         return -1;  
  92.     }  
  93.   
  94.        int newsock = UDT::connect(usock, peer->ai_addr, peer->ai_addrlen);  
  95.   
  96.     freeaddrinfo(peer);  
  97.     return newsock;  
  98. }  
  99.   
  100. int recvdata_udt(void* usocket, char* buf, int size, int flags){      
  101.     if (usocket == NULL){  
  102.         return -1;  
  103.     }  
  104.     UDTSOCKET recver = *(UDTSOCKET*)usocket;    
  105.     int rs;    
  106.     //if (UDT::ERROR == (rs = UDT::recv(recver, buf, size, 0)))  
  107.     if (UDT::ERROR == (rs = UDT::recvmsg(recver, buf, size)))  
  108.     {  
  109.         cout << "recv:" << UDT::getlasterror().getErrorMessage() << endl;  
  110.               if (UDT::getlasterror().getErrorCode() == 2001 || UDT::getlasterror().getErrorCode() == 5004){  
  111.                   return  -1;  
  112.               }  
  113.             __android_log_print(ANDROID_LOG_WARN, TAG, "err, recvdata_udt failed:%s", UDT::getlasterror().getErrorMessage() );  
  114.         return -1;  
  115.     }   
  116.     return rs;  
  117. }  
  118.   
  119. int set_connect_buff_udt(void* usocket, int send_buf_size, int recv_buf_size){  
  120.     if (usocket == NULL){  
  121.         return -1;  
  122.     }  
  123.     UDTSOCKET sock = *(UDTSOCKET*)usocket;     
  124.     UDT::setsockopt(sock, 0, UDT_SNDBUF, &send_buf_size, sizeof(int));  
  125.     UDT::setsockopt(sock, 0, UDT_RCVBUF, &recv_buf_size, sizeof(int));   
  126.       
  127.     return 0;  
  128. }  
  129.   
  130. int senddata_udt(void* usocket, char* buf, int size, int flags){  
  131.          
  132.     if (usocket == NULL){  
  133.        return -1;  
  134.     }  
  135.     UDTSOCKET client = *(UDTSOCKET*)usocket;  
  136.       
  137.     int sent = 0;   
  138.     while (sent < size){  
  139.         //int ret = UDT::send(client, (((const char*)buf) + sent), (int)(size - sent), flags);  
  140.         int ret = UDT::sendmsg(client, (((const char*)buf) + sent), (int)(size - sent), -1, true);  
  141.         if (sent < 0)  
  142.         {             
  143.             __android_log_print(ANDROID_LOG_WARN, TAG, "err, senddata_udt failed:%s", UDT::getlasterror().getErrorMessage() );  
  144.   
  145.             cout << "send: " << UDT::getlasterror().getErrorMessage() << endl;  
  146.             return -1;  
  147.         }   
  148.         else{  
  149.             __android_log_print(ANDROID_LOG_WARN, TAG, " senddata_udt ret:%d, size:%d", ret, size);  
  150.   
  151.             sent += ret;  
  152.         }  
  153.     }  
  154.       
  155.     return sent;  
  156. }  
  157.     
  158. int listen_udt(void* usocket){  
  159.     if (usocket == NULL){  
  160.        return -1;  
  161.     }  
  162.     UDTSOCKET serv = *(UDTSOCKET*)usocket;   
  163.       
  164.     return UDT::listen(serv, 1024);  
  165. }  
  166.   
  167. int accept_udt(void* usocket){  
  168.     if (usocket == NULL){  
  169.        return -1;  
  170.     }  
  171.     UDTSOCKET serv = *(UDTSOCKET*)usocket;   
  172.     sockaddr_in  clientaddr;  
  173.     int addrlen = sizeof(clientaddr);  
  174.     UDTSOCKET new_sock = UDT::accept(serv, (sockaddr*)&clientaddr, &addrlen);   
  175.   
  176.     if (new_sock == UDT::INVALID_SOCK)  
  177.     {  
  178.         return -1;  
  179.     }  
  180.     char ip[16];  
  181.     cout << "new connection: " << inet_ntoa(clientaddr.sin_addr) << ":" << ntohs(clientaddr.sin_port) << endl;  
  182.   
  183.       
  184.     return new_sock;  
  185. }  
  186.   
  187. int close_udt(int usock){  
  188.     UDT::close(usock);  
  189.     return 0;  
  190. }  
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值