且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

简单RTP发送类c++实现

更新时间:2022-09-16 09:25:19

我之前编译了jrtplib 3.9.1,并且在项目中使用,结果发现在用这个库时,程序体积有增加了300多K,感觉实在是有点笨重,我无法就是用来发送rtp包而已。想想还是自己重新实现一个简单的类用用拉倒了,所以有了下面的代码。

头文件:

 

[cpp] view plaincopy
 
  1. /*! 
  2. @brief 简单rtp库 
  3. @file easy_rtp.h 
  4. */  
  5. #ifndef _EASY_RTP_H  
  6. #define _EASY_RTP_H  
  7.   
  8. #include <string>  
  9.   
  10. #include <stdint.h>  
  11.   
  12. #ifdef _WIN32  
  13. #include <winsock2.h>  
  14. #else  
  15. #include <netinet/in.h>  
  16. #include <sys/types.h>  
  17. #include <sys/socket.h>  
  18. #include <arpa/inet.h>  
  19. #include <errno.h>  
  20. #ifndef INVALID_SOCKET  
  21. #define INVALID_SOCKET  (SOCKET)(~0)  
  22. #endif  
  23. #ifndef SOCKET_ERROR  
  24. #define SOCKET_ERROR    (-1)  
  25. #endif  
  26. #ifndef closesocket  
  27. #define closesocket(x)  close(x)  
  28. #endif  
  29. typedef int SOCKET;  
  30. #endif  
  31.   
  32. // 默认最大包大小(MTU 1500 - IP头 20 - UDP头 8)  
  33. #define DEFAULT_MAX_PACKET_SIZE 1472  
  34.   
  35. /*! 
  36. @brief 简单rtp数据包装发送库 
  37. */  
  38. class EasyRtp  
  39. {  
  40. public:  
  41.     /*! 
  42.     @brief 构造 
  43.     @param destIp 目标ip地址 
  44.     @param port 目标端口 
  45.     @param localport 本地帮定端口,默认端口采用随机值 
  46.     */  
  47.     EasyRtp(const std::string& destIp, uint16_t port, uint16_t localPort = 0, int16_t maxpacketsize = DEFAULT_MAX_PACKET_SIZE);  
  48.     /*! 
  49.     @brief 构造 
  50.     @param destIp 目标ip地址 
  51.     @param port 目标端口 
  52.     @param localport 本地帮定端口,默认端口采用随机值 
  53.     */  
  54.     EasyRtp(uint32_t destIp, uint16_t port, uint16_t localPort = 0, int16_t maxpacketsize = DEFAULT_MAX_PACKET_SIZE);  
  55.     ~EasyRtp();  
  56. public:  
  57.     /*! 
  58.     @brief 发送rtp包给目标 
  59.     @param buf 发送的缓冲 
  60.     @param len 发送的缓冲大小 
  61.     @param pt 负载类型 
  62.     @param mark 标记位 
  63.     @param timestampInc 时间戳增量 
  64.     @param 错误为-1 
  65.     */  
  66.     int32_t sendPacket(const char* buf, int32_t len, int8_t pt, bool mark, int32_t timestampInc);  
  67. private:  
  68.     /// 简单rtp头12字节,不含扩展头,csrc列表等信息  
  69.     typedef struct  
  70.     {  
  71.         uint8_t ver;                /// 版本号(2bit)  
  72.         bool p;                     /// 填充位,一直置0(1bit)  
  73.         bool x;                     /// 扩充头位,一直置0(1bit)  
  74.         uint8_t cc;                 /// csrc列表数量,一直置0(4bit)  
  75.         bool mark;                  /// 标记位(1bit)  
  76.         int8_t pt;                  /// 负载类型(7bit)  
  77.         uint16_t sn;                /// 序列号(16bit)  
  78.         uint32_t ts;                /// 时间戳(32bit)  
  79.         uint32_t s-s-rc;              /// 来源标示(32bit)  
  80.     }RtpHeader;  
  81.   
  82.     // 最大包大小  
  83.     int16_t _maxPacketSize;  
  84.     // 发送的缓冲  
  85.     char* _sbuf;  
  86.     // 序列号  
  87.     uint16_t _sn;  
  88.     // 时间戳  
  89.     uint32_t _ts;  
  90.     // 源标示  
  91.     uint32_t _s-s-rc;  
  92.     // 句柄  
  93.     SOCKET _socket;  
  94.     // 目标地址  
  95.     struct sockaddr_in _destTo;  
  96. };  
  97.   
  98. #endif  // _EASY_RTP_H  


cpp源码:

 

 

[cpp] view plaincopy
 
  1. #include <stdio.h>  
  2. #include <string.h>  
  3.   
  4. #include <stdexcept>  
  5.   
  6. #include "easy_rtp.h"  
  7. #include "byte_write.h"  
  8. #include "utils.h"  
  9.   
  10. // 默认的rtp版本  
  11. #define RTP_VERSION         2  
  12. // rtp头大小  
  13. #define RTP_HEADER_SIZE     12  
  14.   
  15. EasyRtp::EasyRtp( const std::string& destIp, uint16_t port, uint16_t localPort /*= 0*/, int16_t maxpacketsize /*= 1500*/ )  
  16.     :_maxPacketSize(maxpacketsize),  
  17.     _sbuf(NULL),  
  18.     _sn(Utils::createRandam32()),  
  19.     _ts(Utils::createRandam32()),  
  20.     _s-s-rc(Utils::createRandam32())  
  21. {  
  22.     if (maxpacketsize >= RTP_HEADER_SIZE)  
  23.         _sbuf = new char[maxpacketsize];  
  24.     else  
  25.         throw std::runtime_error("[EasyRtp] too small packet size, must more than 12 Byte");  
  26.   
  27.     _socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);  
  28.     if (_socket == INVALID_SOCKET)  
  29.         throw std::runtime_error("[EasyRtp] invalid socket");  
  30.   
  31.     _destTo.sin_family = AF_INET;  
  32.     _destTo.sin_port = htons(port);  
  33.     _destTo.sin_addr.s_addr = inet_addr(destIp.c_str());  
  34.   
  35.     if (localPort != 0)  
  36.     {  
  37.         struct sockaddr_in sockAddr;  
  38.         sockAddr.sin_family = AF_INET;  
  39.         sockAddr.sin_port = htons(localPort);  
  40.         sockAddr.sin_addr.s_addr = INADDR_ANY;  
  41.   
  42.         if (bind(_socket, (const sockaddr*)&sockAddr, sizeof(sockAddr)) == SOCKET_ERROR)  
  43.         {  
  44. #ifndef NPRINT  
  45. #ifdef _WIN32  
  46.             printf("[EasyRtp] bind error: %d\n", WSAGetLastError());  
  47. #else  
  48.             printf("[EasyRtp] bind error: %d\n", errno);  
  49. #endif  
  50. #endif  
  51.             closesocket(_socket);  
  52.             throw std::runtime_error("[EasyRtp] bind error");  
  53.         }  
  54.     }  
  55. }  
  56.   
  57. EasyRtp::EasyRtp( uint32_t destIp, uint16_t port, uint16_t localPort /*= 0*/, int16_t maxpacketsize /*= DEFAULT_MAX_PACKET_SIZE*/ )  
  58.     :_maxPacketSize(maxpacketsize),  
  59.     _sbuf(NULL),  
  60.     _sn(Utils::createRandam32()),  
  61.     _ts(Utils::createRandam32()),  
  62.     _s-s-rc(Utils::createRandam32())  
  63. {  
  64.     if (maxpacketsize >= RTP_HEADER_SIZE)  
  65.         _sbuf = new char[maxpacketsize];  
  66.     else  
  67.         throw std::runtime_error("[EasyRtp] too small packet size, must more than 12 Byte");  
  68.   
  69.     _socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);  
  70.     if (_socket == INVALID_SOCKET)  
  71.         throw std::runtime_error("[EasyRtp] invalid socket");  
  72.   
  73.     _destTo.sin_family = AF_INET;  
  74.     _destTo.sin_port = htons(port);  
  75.     _destTo.sin_addr.s_addr = htonl(destIp);  
  76.   
  77.     if (localPort != 0)  
  78.     {  
  79.         struct sockaddr_in sockAddr;  
  80.         sockAddr.sin_family = AF_INET;  
  81.         sockAddr.sin_port = htons(localPort);  
  82.         sockAddr.sin_addr.s_addr = INADDR_ANY;  
  83.   
  84.         if (bind(_socket, (const sockaddr*)&sockAddr, sizeof(sockAddr)) == SOCKET_ERROR)  
  85.         {  
  86. #ifndef NPRINT  
  87. #ifdef _WIN32  
  88.             printf("[EasyRtp] bind error: %d\n", WSAGetLastError());  
  89. #else  
  90.             printf("[EasyRtp] bind error: %d\n", errno);  
  91. #endif  
  92. #endif  
  93.             closesocket(_socket);  
  94.             throw std::runtime_error("[EasyRtp] bind error");  
  95.         }  
  96.     }  
  97. }  
  98.   
  99. EasyRtp::~EasyRtp()  
  100. {  
  101.     if (_socket != INVALID_SOCKET)  
  102.         closesocket(_socket);  
  103.     if (_sbuf != NULL)  
  104.         delete [] _sbuf;  
  105. }  
  106.   
  107. int32_t EasyRtp::sendPacket( const char* buf, int32_t len, int8_t pt, bool mark, int32_t timestampInc )  
  108. {  
  109.     if ((len + RTP_HEADER_SIZE) > _maxPacketSize)  
  110.         return -1;  
  111.   
  112.     ++_sn;  
  113.     _ts += timestampInc;  
  114.   
  115.     // 只设置版本号,其它的全是默认0  
  116.     _sbuf[0] = 0;  
  117.     _sbuf[0] |= RTP_VERSION << 6;  
  118.     _sbuf[1] = 0;  
  119.     _sbuf[1] |= mark << 7;  
  120.     _sbuf[1] |= pt;  
  121.     write_be_w(_sbuf + 2, _sn);  
  122.     write_be_dw(_sbuf + 4, _ts);  
  123.     write_be_dw(_sbuf + 8, _s-s-rc);  
  124.     // 保存数据  
  125.     memcpy(_sbuf + RTP_HEADER_SIZE, buf, len);  
  126.     int32_t ret = sendto(_socket, (const char*)_sbuf, len + RTP_HEADER_SIZE, 0, (const sockaddr*)&_destTo, sizeof(_destTo));  
  127. #ifndef NPRINT  
  128.     if (ret < 0)  
  129.     {  
  130. #ifdef _WIN32  
  131.         printf("[EasyRtp] sendto error: %d\n", WSAGetLastError());  
  132. #else  
  133.         printf("[EasyRtp] sendto error: %d\n", errno);  
  134. #endif  
  135.     }  
  136. #endif  
  137.     return ret;  
  138. }  


注:

 

stdint.h是新c++标准中的头文件,定义了int32_t int8_t等typedef 类型。