简单RTP发送类c++实现

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

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

头文件:

 

[cpp]  view plain copy
 
  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 ssrc;              /// 来源标示(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 _ssrc;  
  92.     // 句柄  
  93.     SOCKET _socket;  
  94.     // 目标地址  
  95.     struct sockaddr_in _destTo;  
  96. };  
  97.   
  98. #endif  // _EASY_RTP_H  


cpp源码:

 

 

[cpp]  view plain copy
 
  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.     _ssrc(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.     _ssrc(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, _ssrc);  
  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 类型。

目录
相关文章
|
8月前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
4月前
|
人工智能 机器人 编译器
c++模板初阶----函数模板与类模板
class 类模板名private://类内成员声明class Apublic:A(T val):a(val){}private:T a;return 0;运行结果:注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。return 0;
106 0
|
4月前
|
存储 编译器 程序员
c++的类(附含explicit关键字,友元,内部类)
本文介绍了C++中类的核心概念与用法,涵盖封装、继承、多态三大特性。重点讲解了类的定义(`class`与`struct`)、访问限定符(`private`、`public`、`protected`)、类的作用域及成员函数的声明与定义分离。同时深入探讨了类的大小计算、`this`指针、默认成员函数(构造函数、析构函数、拷贝构造、赋值重载)以及运算符重载等内容。 文章还详细分析了`explicit`关键字的作用、静态成员(变量与函数)、友元(友元函数与友元类)的概念及其使用场景,并简要介绍了内部类的特性。
179 0
|
6月前
|
编译器 C++ 容器
【c++11】c++11新特性(上)(列表初始化、右值引用和移动语义、类的新默认成员函数、lambda表达式)
C++11为C++带来了革命性变化,引入了列表初始化、右值引用、移动语义、类的新默认成员函数和lambda表达式等特性。列表初始化统一了对象初始化方式,initializer_list简化了容器多元素初始化;右值引用和移动语义优化了资源管理,减少拷贝开销;类新增移动构造和移动赋值函数提升性能;lambda表达式提供匿名函数对象,增强代码简洁性和灵活性。这些特性共同推动了现代C++编程的发展,提升了开发效率与程序性能。
203 12
|
7月前
|
设计模式 安全 C++
【C++进阶】特殊类设计 && 单例模式
通过对特殊类设计和单例模式的深入探讨,我们可以更好地设计和实现复杂的C++程序。特殊类设计提高了代码的安全性和可维护性,而单例模式则确保类的唯一实例性和全局访问性。理解并掌握这些高级设计技巧,对于提升C++编程水平至关重要。
138 16
|
7月前
|
编译器 C++
类和对象(中 )C++
本文详细讲解了C++中的默认成员函数,包括构造函数、析构函数、拷贝构造函数、赋值运算符重载和取地址运算符重载等内容。重点分析了各函数的特点、使用场景及相互关系,如构造函数的主要任务是初始化对象,而非创建空间;析构函数用于清理资源;拷贝构造与赋值运算符的区别在于前者用于创建新对象,后者用于已存在的对象赋值。同时,文章还探讨了运算符重载的规则及其应用场景,并通过实例加深理解。最后强调,若类中存在资源管理,需显式定义拷贝构造和赋值运算符以避免浅拷贝问题。
|
7月前
|
存储 编译器 C++
类和对象(上)(C++)
本篇内容主要讲解了C++中类的相关知识,包括类的定义、实例化及this指针的作用。详细说明了类的定义格式、成员函数默认为inline、访问限定符(public、protected、private)的使用规则,以及class与struct的区别。同时分析了类实例化的概念,对象大小的计算规则和内存对齐原则。最后介绍了this指针的工作机制,解释了成员函数如何通过隐含的this指针区分不同对象的数据。这些知识点帮助我们更好地理解C++中类的封装性和对象的实现原理。
|
7月前
|
安全 C++
【c++】继承(继承的定义格式、赋值兼容转换、多继承、派生类默认成员函数规则、继承与友元、继承与静态成员)
本文深入探讨了C++中的继承机制,作为面向对象编程(OOP)的核心特性之一。继承通过允许派生类扩展基类的属性和方法,极大促进了代码复用,增强了代码的可维护性和可扩展性。文章详细介绍了继承的基本概念、定义格式、继承方式(public、protected、private)、赋值兼容转换、作用域问题、默认成员函数规则、继承与友元、静态成员、多继承及菱形继承问题,并对比了继承与组合的优缺点。最后总结指出,虽然继承提高了代码灵活性和复用率,但也带来了耦合度高的问题,建议在“has-a”和“is-a”关系同时存在时优先使用组合。
381 6
|
7月前
|
编译器 C++
类和对象(下)C++
本内容主要讲解C++中的初始化列表、类型转换、静态成员、友元、内部类、匿名对象及对象拷贝时的编译器优化。初始化列表用于成员变量定义初始化,尤其对引用、const及无默认构造函数的类类型变量至关重要。类型转换中,`explicit`可禁用隐式转换。静态成员属类而非对象,受访问限定符约束。内部类是独立类,可增强封装性。匿名对象生命周期短,常用于临时场景。编译器会优化对象拷贝以提高效率。最后,鼓励大家通过重复练习提升技能!
|
8月前
|
安全 编译器 C语言
【C++篇】深度解析类与对象(中)
在上一篇博客中,我们学习了C++类与对象的基础内容。这一次,我们将深入探讨C++类的关键特性,包括构造函数、析构函数、拷贝构造函数、赋值运算符重载、以及取地址运算符的重载。这些内容是理解面向对象编程的关键,也帮助我们更好地掌握C++内存管理的细节和编码的高级技巧。