简单RTP发送类c++实现

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

头文件:

/*!
@brief 简单rtp库
@file easy_rtp.h
*/
#ifndef _EASY_RTP_H
#define _EASY_RTP_H

#include <string>

#include <stdint.h>

#ifdef _WIN32
#include <winsock2.h>
#else
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
#ifndef INVALID_SOCKET
#define INVALID_SOCKET	(SOCKET)(~0)
#endif
#ifndef SOCKET_ERROR
#define SOCKET_ERROR	(-1)
#endif
#ifndef closesocket
#define closesocket(x)	close(x)
#endif
typedef int SOCKET;
#endif

// 默认最大包大小(MTU 1500 - IP头 20 - UDP头 8)
#define DEFAULT_MAX_PACKET_SIZE	1472

/*!
@brief 简单rtp数据包装发送库
*/
class EasyRtp
{
public:
	/*!
	@brief 构造
	@param destIp 目标ip地址
	@param port 目标端口
	@param localport 本地帮定端口,默认端口采用随机值
	*/
	EasyRtp(const std::string& destIp, uint16_t port, uint16_t localPort = 0, int16_t maxpacketsize = DEFAULT_MAX_PACKET_SIZE);
	/*!
	@brief 构造
	@param destIp 目标ip地址
	@param port 目标端口
	@param localport 本地帮定端口,默认端口采用随机值
	*/
	EasyRtp(uint32_t destIp, uint16_t port, uint16_t localPort = 0, int16_t maxpacketsize = DEFAULT_MAX_PACKET_SIZE);
	~EasyRtp();
public:
	/*!
	@brief 发送rtp包给目标
	@param buf 发送的缓冲
	@param len 发送的缓冲大小
	@param pt 负载类型
	@param mark 标记位
	@param timestampInc 时间戳增量
	@param 错误为-1
	*/
	int32_t sendPacket(const char* buf, int32_t len, int8_t pt, bool mark, int32_t timestampInc);
private:
	/// 简单rtp头12字节,不含扩展头,csrc列表等信息
	typedef struct
	{
		uint8_t ver;				/// 版本号(2bit)
		bool p;						/// 填充位,一直置0(1bit)
		bool x;						/// 扩充头位,一直置0(1bit)
		uint8_t cc;					/// csrc列表数量,一直置0(4bit)
		bool mark;					/// 标记位(1bit)
		int8_t pt;					/// 负载类型(7bit)
		uint16_t sn;				/// 序列号(16bit)
		uint32_t ts;				/// 时间戳(32bit)
		uint32_t ssrc;				/// 来源标示(32bit)
	}RtpHeader;

	// 最大包大小
	int16_t _maxPacketSize;
	// 发送的缓冲
	char* _sbuf;
	// 序列号
	uint16_t _sn;
	// 时间戳
	uint32_t _ts;
	// 源标示
	uint32_t _ssrc;
	// 句柄
	SOCKET _socket;
	// 目标地址
	struct sockaddr_in _destTo;
};

#endif	// _EASY_RTP_H

cpp源码:

#include <stdio.h>
#include <string.h>

#include <stdexcept>

#include "easy_rtp.h"
#include "byte_write.h"
#include "utils.h"

// 默认的rtp版本
#define RTP_VERSION			2
// rtp头大小
#define RTP_HEADER_SIZE		12

EasyRtp::EasyRtp( const std::string& destIp, uint16_t port, uint16_t localPort /*= 0*/, int16_t maxpacketsize /*= 1500*/ )
	:_maxPacketSize(maxpacketsize),
	_sbuf(NULL),
	_sn(Utils::createRandam32()),
	_ts(Utils::createRandam32()),
	_ssrc(Utils::createRandam32())
{
	if (maxpacketsize >= RTP_HEADER_SIZE)
		_sbuf = new char[maxpacketsize];
	else
		throw std::runtime_error("[EasyRtp] too small packet size, must more than 12 Byte");

	_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
	if (_socket == INVALID_SOCKET)
		throw std::runtime_error("[EasyRtp] invalid socket");

	_destTo.sin_family = AF_INET;
	_destTo.sin_port = htons(port);
	_destTo.sin_addr.s_addr = inet_addr(destIp.c_str());

	if (localPort != 0)
	{
		struct sockaddr_in sockAddr;
		sockAddr.sin_family = AF_INET;
		sockAddr.sin_port = htons(localPort);
		sockAddr.sin_addr.s_addr = INADDR_ANY;

		if (bind(_socket, (const sockaddr*)&sockAddr, sizeof(sockAddr)) == SOCKET_ERROR)
		{
#ifndef NPRINT
#ifdef _WIN32
			printf("[EasyRtp] bind error: %d\n", WSAGetLastError());
#else
			printf("[EasyRtp] bind error: %d\n", errno);
#endif
#endif
			closesocket(_socket);
			throw std::runtime_error("[EasyRtp] bind error");
		}
	}
}

EasyRtp::EasyRtp( uint32_t destIp, uint16_t port, uint16_t localPort /*= 0*/, int16_t maxpacketsize /*= DEFAULT_MAX_PACKET_SIZE*/ )
	:_maxPacketSize(maxpacketsize),
	_sbuf(NULL),
	_sn(Utils::createRandam32()),
	_ts(Utils::createRandam32()),
	_ssrc(Utils::createRandam32())
{
	if (maxpacketsize >= RTP_HEADER_SIZE)
		_sbuf = new char[maxpacketsize];
	else
		throw std::runtime_error("[EasyRtp] too small packet size, must more than 12 Byte");

	_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
	if (_socket == INVALID_SOCKET)
		throw std::runtime_error("[EasyRtp] invalid socket");

	_destTo.sin_family = AF_INET;
	_destTo.sin_port = htons(port);
	_destTo.sin_addr.s_addr = htonl(destIp);

	if (localPort != 0)
	{
		struct sockaddr_in sockAddr;
		sockAddr.sin_family = AF_INET;
		sockAddr.sin_port = htons(localPort);
		sockAddr.sin_addr.s_addr = INADDR_ANY;

		if (bind(_socket, (const sockaddr*)&sockAddr, sizeof(sockAddr)) == SOCKET_ERROR)
		{
#ifndef NPRINT
#ifdef _WIN32
			printf("[EasyRtp] bind error: %d\n", WSAGetLastError());
#else
			printf("[EasyRtp] bind error: %d\n", errno);
#endif
#endif
			closesocket(_socket);
			throw std::runtime_error("[EasyRtp] bind error");
		}
	}
}

EasyRtp::~EasyRtp()
{
	if (_socket != INVALID_SOCKET)
		closesocket(_socket);
	if (_sbuf != NULL)
		delete [] _sbuf;
}

int32_t EasyRtp::sendPacket( const char* buf, int32_t len, int8_t pt, bool mark, int32_t timestampInc )
{
	if ((len + RTP_HEADER_SIZE) > _maxPacketSize)
		return -1;

	++_sn;
	_ts += timestampInc;

	// 只设置版本号,其它的全是默认0
	_sbuf[0] = 0;
	_sbuf[0] |= RTP_VERSION << 6;
	_sbuf[1] = 0;
	_sbuf[1] |= mark << 7;
	_sbuf[1] |= pt;
	write_be_w(_sbuf + 2, _sn);
	write_be_dw(_sbuf + 4, _ts);
	write_be_dw(_sbuf + 8, _ssrc);
	// 保存数据
	memcpy(_sbuf + RTP_HEADER_SIZE, buf, len);
	int32_t ret = sendto(_socket, (const char*)_sbuf, len + RTP_HEADER_SIZE, 0, (const sockaddr*)&_destTo, sizeof(_destTo));
#ifndef NPRINT
	if (ret < 0)
	{
#ifdef _WIN32
		printf("[EasyRtp] sendto error: %d\n", WSAGetLastError());
#else
		printf("[EasyRtp] sendto error: %d\n", errno);
#endif
	}
#endif
	return ret;
}

注:

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


你可能感兴趣的:(C++,socket,struct,header,null,byte)