JRTPLIB使用
1.RTP简介
实时传输协议(Real-time Transport Protocol或简写RTP)是一个网络传输协议,它是由IETF的多媒体传输工作小组1996年在RFC 1889中公布的。
国际电信联盟ITU-T也发布了自己的RTP文档,作为H.225.0,但是后来当IETF发布了关于它的稳定的标准RFC后就被取消了。它作为因特网标准在RFC 3550(该文档的旧版本是RFC 1889)有详细说明。RFC 3551(STD 65,旧版本是RFC 1890)详细描述了使用最小控制的音频和视频会议。
RTP协议详细说明了在互联网上传递音频和视频的标准数据包格式。它一开始被设计为一个多播协议,但后来被用在很多单播应用中。RTP协议常用于流媒体系统(配合RTSP协议),视频会议和一键通(Push to Talk)系统(配合H.323或SIP),使它成为IP电话产业的技术基础。RTP协议和RTP控制协议RTCP一起使用,而且它是建立在UDP协议上的。实时传输协议------wiki
2.JRTPLIB
RTP 是目前解决流媒体实时传输问题的最好办法,如果需要在Linux平台上进行实时流媒体编程,可以考虑使用一些开放源代码的RTP库,如LIBRTP、 JRTPLIB等。 JRTPLIB是一个面向对象的RTP库,它完全遵循RFC 1889设计,在很多场合下是一个非常不错的选择,下面就以JRTPLIB为例,讲述如何在Linux平台上运用RTP协议进行实时流媒体编程。
JRTPLIB 是一个用C++语言实现的RTP库,目前已经可以运行在Windows、Linux、FreeBSD、Solaris、Unix和 VxWorks等多种操作系统上。------jrtp详细介绍
3.JRTPLIB编译
git clone https://github.com/j0r1/JRTPLIB.git
cd JRTPLIB
mkdir build
cd build
cmake .. && make && sudo make install
如果需要启用JThread支持,需要在编译JRTPLIB之前编译JThread
git clone https://github.com/j0r1/JThread.git
cd JRTPLIB
mkdir build
cd build
cmake .. && make && sudo make install
4.JRTPLIB例程
官方历程参见https://github.com/j0r1/JRTPLIB/tree/master/examples,以下是example1.cpp
,添加了一些中文注释
#include "rtpsession.h"
#include "rtpudpv4transmitter.h"
#include "rtpipv4address.h"
#include "rtpsessionparams.h"
#include "rtperrors.h"
#include "rtplibraryversion.h"
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>
using namespace jrtplib;
// 打印错误信息
void checkerror(int rtperr)
{
if (rtperr < 0)
{
std::cout << "ERROR: " << RTPGetErrorString(rtperr) << std::endl;
exit(-1);
}
}
// 主循环
int main(void)
{
// windows相关,不需要可以删了
#ifdef RTP_SOCKETTYPE_WINSOCK
WSADATA dat;
WSAStartup(MAKEWORD(2,2),&dat);
#endif // RTP_SOCKETTYPE_WINSOCK
RTPSession sess;
uint16_t portbase,destport;
uint32_t destip;
std::string ipstr;
int status,i,num;
// 打印JRTPLIB版本
std::cout << "Using version " << RTPLibraryVersion::GetVersion().GetVersionString() << std::endl;
// 获取本地端口,用以接收
std::cout << "Enter local portbase:" << std::endl;
std::cin >> portbase;
std::cout << std::endl;
// 目标地址,本机使用127.0.0.1
std::cout << "Enter the destination IP address" << std::endl;
std::cin >> ipstr;
destip = inet_addr(ipstr.c_str());
if (destip == INADDR_NONE)
{
std::cerr << "Bad IP address specified" << std::endl;
return -1;
}
// inet_addr函数返回的是网络字节序,需要将网络字节序转化为主机字节序
destip = ntohl(destip);
// 目标端口,如果发送给本机,与上面的接收端口相同即可
std::cout << "Enter the destination port" << std::endl;
std::cin >> destport;
// 发包数量
std::cout << std::endl;
std::cout << "Number of packets you wish to be sent:" << std::endl;
std::cin >> num;
// 创建传输参数和会话参数
RTPUDPv4TransmissionParams transparams;
RTPSessionParams sessparams;
// IMPORTANT: The local timestamp unit MUST be set, otherwise
// RTCP Sender Report info will be calculated wrong
// In this case, we'll be sending 10 samples each second, so we'll
// put the timestamp unit to (1.0/10.0)
// 设置时间戳
sessparams.SetOwnTimestampUnit(1.0/10.0);
// 是否接收自己发送的包
sessparams.SetAcceptOwnPackets(true);
// 设置接收端口
transparams.SetPortbase(portbase);
// 创建端口
status = sess.Create(sessparams,&transparams);
checkerror(status);
// 写入IPv4地址和端口
RTPIPv4Address addr(destip,destport);
// 添加目标地址
status = sess.AddDestination(addr);
checkerror(status);
for (i = 1 ; i <= num ; i++)
{
printf("\nSending packet %d/%d\n",i,num);
// 发包
status = sess.SendPacket((void *)"1234567890",10,0,false,10);
checkerror(status);
sess.BeginDataAccess();
// 检查收包
if (sess.GotoFirstSourceWithData())
{
do
{
RTPPacket *pack;
while ((pack = sess.GetNextPacket()) != NULL)
{
// 在这里进行数据处理
printf("Got packet !\n");
// 不再需要这个包了,删除之
sess.DeletePacket(pack);
}
} while (sess.GotoNextSourceWithData());
}
sess.EndDataAccess();
// 这部分与JThread库相关
#ifndef RTP_SUPPORT_THREAD
status = sess.Poll();
checkerror(status);
#endif // RTP_SUPPORT_THREAD
// 等待一秒,发包间隔
RTPTime::Wait(RTPTime(1,0));
}
// 销毁对话
sess.BYEDestroy(RTPTime(10,0),0,0);
// Windows相关
#ifdef RTP_SOCKETTYPE_WINSOCK
WSACleanup();
#endif // RTP_SOCKETTYPE_WINSOCK
return 0;
}
这里会有问题,怎么读取收到的packet中的data,需要先包含头文件
#include "rtppacket.h"
在进行数据处理的地方使用以下函数获取负载数据,和负载长度
pack->GetPayloadData();
pack->GetPayloadLength();
5.CMake配置
在使用CMake进行编译的时候可能会出现找不到库的情况,需要手写FindJRTPLIB.cmake
# - Find JRTPLIB library
# Once done this will define
# JRTPLIB_FOUND - system has JRTPLIB
# JRTPLIB_INCLUDE_DIR - JRTPLIB include directories
# JRTPLIB_LIBRARY - where to find the JRTPLIB library
if(JRTPLIB_INCLUDE_DIR)
# Already in cache, be silent
set(JRTPLIB_FIND_QUIETLY TRUE)
endif()
find_path(JRTPLIB_INCLUDE_DIR
NAMES rtpsession.h
PATH_SUFFIXES jrtplib jrtplib3
DOC "JRTPLIB include directories"
)
find_library(JRTPLIB_LIBRARY
NAMES jrtp
DOC "JRTPLIB library"
)
# handle the QUIETLY and REQUIRED arguments and set JRTPLIB_FOUND to TRUE if all listed variables are TRUE
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(JRTPLIB
REQUIRED_VARS JRTPLIB_LIBRARY JRTPLIB_INCLUDE_DIR
VERSION_VAR JRTPLIB_VERSION_STRING)
if(JRTPLIB_INCLUDE_DIR AND JRTPLIB_LIBRARY)
set(JRTPLIB_FOUND TRUE)
set(JRTPLIB_LIBRARIES ${JRTPLIB_LIBRARY})
set(JRTPLIB_INCLUDE_DIRS ${JRTPLIB_INCLUDE_DIR})
else()
set (JRTPLIB_FOUND FALSE)
message(FATAL_ERROR "JRTPLIB not found")
endif()
mark_as_advanced(
JRTPLIB_INCLUDE_DIR
JRTPLIB_LIBRARY)
如果前面编译了JThread库,或者在编译的时候提示
This function is not available when using the RTP Poll thread feature.
则还需要将JThread库进行链接,FindJTHREAD.cmake
如下
# - Find JTHREAD library
# Once done this will define
# JTHREAD_FOUND - system has JTHREAD
# JTHREAD_INCLUDE_DIR - JTHREAD include directories
# JTHREAD_LIBRARY - where to find the JTHREAD library
if(JTHREAD_INCLUDE_DIR)
# Already in cache, be silent
set(JTHREAD_FIND_QUIETLY TRUE)
endif()
find_path(JTHREAD_INCLUDE_DIR
NAMES jthread.h
PATH_SUFFIXES jthread jthread3
DOC "JTHREAD include directories"
)
find_library(JTHREAD_LIBRARY
NAMES jthread
DOC "JTHREAD library"
)
# handle the QUIETLY and REQUIRED arguments and set JTHREAD_FOUND to TRUE if all listed variables are TRUE
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(JTHREAD
REQUIRED_VARS JTHREAD_LIBRARY JTHREAD_INCLUDE_DIR
VERSION_VAR JTHREAD_VERSION_STRING)
if(JTHREAD_INCLUDE_DIR AND JTHREAD_LIBRARY)
set(JTHREAD_FOUND TRUE)
set(JTHREAD_LIBRARIES ${JTHREAD_LIBRARY})
set(JTHREAD_INCLUDE_DIRS ${JTHREAD_INCLUDE_DIR})
else()
set (JTHREAD_FOUND FALSE)
message(FATAL_ERROR "JTHREAD not found")
endif()
mark_as_advanced(
JTHREAD_INCLUDE_DIR
JTHREAD_LIBRARY)
之后在顶层的CMakeLists.txt
中使用find_package(JRTPLIB)
进行链接,不再赘述。