这几天在看关于JRTPLIB方面的东西。在网上看了不少文章linux jrtplib 使用,其中有很大部份使用的JRTPLIB版本在3.0以下。
在网上下载了一个JRTPLIB-3.7的库查看linux是什么系统,发觉上面的函数插口做了一些更改。现奉上一篇基于JRTPLIB-3.7的网路
语音传送实例,希望有兴趣的同学一起参详研究。
——-chuckGao
第一部份JRTPLIB的编译及安装
这是必行的一步,在网上可以找到相关的文章,这儿就不啰嗦了。不过可能有些同事会碰到JRTPLIB
未能正常编译的情况,出现error:'memcpy'wasnotdeclaredinthisscope的错误。这是因为JRTPLIB编
译中未能找到memcpy这个函数。在网上有memcpy的patch。内容如下:
diff--gita/src/rtcpcompoundpacketbuilder.cppb/src/rtcpcompoundpacketbuilder.cpp
index8172007..8fd4510100644
—a/src/rtcpcompoundpacketbuilder.cpp
+++b/src/rtcpcompoundpacketbuilder.cpp
@@-30,6+30,8@@
*/
+#include
#include”rtcpcompoundpacketbuilder.h”
#include”rtcpsrpacket.h”
#include”rtcprrpacket.h”
diff--gita/src/rtppacket.cppb/src/rtppacket.cpp
indexb6d5fda..8c516c7100644
—a/src/rtppacket.cpp
+++b/src/rtppacket.cpp
@@-30,6+30,8@@
*/
+#include
#include”rtppacket.h”
#include”rtpstructs.h”
#include”rtpdefines.h”
+代表添加,-代表删掉相应内容
第二部份JRTPLIB编程
下边先转载一部份网上的手册linux设置环境变量,白色标记是JRTPLIB-3.7修了后的使用方式
linux下基于jrtplib库的实时传送实现
一、RTP是进行实时流媒体传输的标准合同和关键技术
实时传输合同(Real-timeTransportProtocol,PRT)是在Internet上处理多媒体数据流的一种网路合同
,借助它还能在一对一(unicast,时隙)或则一对多(multicast,多播)的网路环境中实现传流媒体数据的
实时传输。RTP一般使用UDP来进行多媒体数据的传输,但若果须要的话可以使用TCP或则ATM等其它协
议。
合同剖析:每一个RTP数据报都由颈部(Header)和负载(Payload)两个部份组成,其中腹部前12个字节
的涵义是固定的,而负载则可以是音频或则视频数据。
RTP是目前解决流媒体实时传输问题的最好办法,要在Linux平台上进行实时传送编程,可以考虑使用
一些开放源代码的RTP库,如LIBRTP、JRTPLIB等。JRTPLIB是一个面向对象的RTP库,它完全遵守RFC
1889设计,在好多场合下是一个十分不错的选择。JRTPLIB是一个用C++语言实现的RTP库,这个库使用
socket机制实现网路通信因而可以运行在Windows、Linux、FreeBSD、Solaris、Unix和VxWorks等多种操
作系统上。
二、JRTPLIB库的使用方式及程序实现
(1)JRTPLIB函数的使用
a、在使用JRTPLIB进行实时流媒体数据传输之前,首先应当生成RTPSession类的一个实例来表示这次RTP
会话,之后调用Create()方式来对其进行初始化操作。RTPSession类的Create()方式只有一个参数,用
来指明这次RTP会话所采用的端标语。
RTPSessionsess;sess.Create(5000);
JRTPLIB-3.7中早已更改了Create(prot)方式。新的Create方式被更改为Crea(sessparams,&transparams)。其中的两个参数须要如下先定义:
RTPUDPv4TransmissionParamstransparams;
RTPSessionParamssessparams;
sessparams.SetOwnTimestampUnit(1.0/8000.0);/*设置时间戳,1/8000表示一秒钟取样8000次,即录音时的8KHz*/
sessparams.SetAcceptOwnPackets(true);
transparams.SetPortbase(portbase);/*本地通信端口*/
b、设置恰当的时戳单元,是RTP会话初始化过程所要进行的另外一项重要工作,这是通过调用RTPSession
类的SetTimestampUnit()方式来实现的,上面早已提过。
c、当RTP会话成功构建上去以后,接下去就可以开始进行流媒体数据的实时传输了。首先须要设置好数据发
送的目标地址,RTP合同容许同一会话存在多个目标地址,这可以通过调用RTPSession类的
AddDestination()、DeleteDestination()和ClearDestinations()方式来完成。诸如,下边的句子表示的
是让RTP会话将数据发送到本地主机的6000端口:
unsignedlongaddr=ntohl(inet_addr(“127.0.0.1”));
sess.AddDestination(addr,6000);
d、目标地址全部指定以后,接着就可以调用RTPSession类的SendPacket()方式,向所有的目标地址发送
流媒体数据。SendPacket()是RTPSession类提供的一个重载函数
对于同一个RTP会话来讲,负载类型、标识和时戳增量一般来讲都是相同的,JRTPLIB准许将它们设置为会
话的默认参数,这是通过调用RTPSession类的SetDefaultPayloadType()、SetDefaultMark()和
SetDefaultTimeStampIncrement()方式来完成的。为RTP会话设置这种默认参数的用处是可以简化数据的发
送,比如,倘若为RTP会话设置了默认参数:
sess.SetDefaultPayloadType(0);
sess.SetDefaultMark(false);
sess.SetDefaultTimeStampIncrement(10);
然后在进行数据发送时只需指明要发送的数据及其厚度就可以了:
sess.SendPacket(buffer,5);
在真正的语音传输中linux jrtplib 使用,前面的buffer就是我们录音时所得到的buffer。使用前面的函数可以简单的发送,但未能真正的实现RTP传输,我们须要调用另一个插口:sess.SendPacket((void*)buffer,sizeof(buffer),0,false,8000);详尽的说明可以查看JRTPLIB的说明文档。
e、对于流媒体数据的接收端,首先须要调用RTPSession类的PollData()方式来接收发送过来的RTP或则
RTCP数据报。
JRTPLIB-3.7中更改PollData()方式为Poll(),使用都一样
因为同一个RTP会话中容许有多个参与者(源),你既可以通过调用RTPSession类的
GotoFirstSource()和GotoNextSource()方式来遍历所有的源,也可以通过调用RTPSession类的
GotoFirstSourceWithData()和GotoNextSourceWithData()方式来遍历这些携带有数据的源。在从RTP会
话中检测出有效的数据源以后,接下去就可以调用RTPSession类的GetNextPacket()方式从中抽取RTP数
据报,当接收到的RTP数据报处理完以后,一定要记得及时释放。
JRTPLIB为RTP数据报定义了三种接收模式,其中每种接收模式都具体规定了什么抵达的RTP数据报将会被
接受,而什么抵达的RTP数据报将会被拒绝。通过调用RTPSession类的SetReceiveMode()方式可以设置
下述这种接收模式:
RECEIVEMODE_ALL缺省的接收模式,所有抵达的RTP数据报都将被接受;
RECEIVEMODE_IGNORESOME不仅个别特定的发送者之外,所有抵达的RTP数据报都将被接受,而被拒绝
的发送者列表可以通过调用AddToIgnoreList()、DeleteFromIgnoreList()和ClearIgnoreList()方式来进
行设置;
RECEIVEMODE_ACCEPTSOME不仅个别特定的发送者之外,所有抵达的RTP数据报都将被拒绝,而被接受
的发送者列表可以通过调用AddToAcceptList()、DeleteFromAcceptList和ClearAcceptList()方式来进
行设置。下边是采用第三种接收模式的程序示例。
if(sess.GotoFirstSourceWithData()){
do{
sess.AddToAcceptList(remoteIP,allports,portbase);
sess.SetReceiveMode(RECEIVEMODE_ACCEPTSOME);
RTPPacket*pack;
pack=sess.GetNextPacket();//处理接收到的数据
deletepack;}
while(sess.GotoNextSourceWithData());
完整的代码中,首先需调用Poll()方式接收RTP数据报,之后在BeginDataAccess()和EndDataAccess()之间进行数据接收的操作。此时,我们设定程序仍然do-while等待并处理数据
do{
#ifndefRTP_SUPPORT_THREAD
error_status=sess_client.Poll();
checkerror(error_status);
#endif//RTP_SUPPORT_THREAD
sess_client.BeginDataAccess();
//checkincomingpackets
if(sess_client.GotoFirstSourceWithData())
printf(“Beginplay/n”);
do
RTPPacket*pack;
while((pack=sess_client.GetNextPacket())!=NULL)
//Youcanexaminethedatahere
printf(“Gotpacket!/n”);
timestamp1=pack->GetTimestamp();
lengh=pack->GetPayloadLength();
RawData=pack->GetPayloadData();//得到数据
printf(“timestamp:%dlengh=%d/n”,timestamp1,lengh);
//wedon'tlongerneedthepacket,so
//we'lldeleteit
//Beginplay
intfd=open(“/dev/dsp”,O_RDWR);
intstatus=write(fd,RawData,lengh);
printf(“Playbytes:%d/n”,status);
if(status!=lengh)
perror(“wrotewrongnumberofbytes”);
status=ioctl(fd,SOUND_PCM_SYNC,0);
if(status==-1)
perror(“SOUND_PCM_SYNCioctlfailed”);
printf(“Playend/n”);
close(fd);
sess_client.DeletePacket(pack);
}while(sess_client.GotoNextSourceWithData());
//return0;
sess_client.EndDataAccess();
}while(1);
(2)程序流程图
发送:获得接收端的IP地址和端标语创建RTP会话指定RTP数据接收端设置RTP会话默认参数发送流媒体数据
接收:获得用户指定的端标语创建RTP会话设置接收模式接受RTP数据检索RTP数据源获取RTP数据报删掉RTP数据报
由于是关于JRTPLIB的文章,所以贴出的录音和放音代码不多。须要的同学可以留下邮箱。