RTP是一个实时通讯网络协议,网络上的音视频传输可以用它来做,像QQ的语音聊天等都是使用这个。real 开发 的在线rm文件播放协议 rstp也是基于RTP协议,可以自己搜索一下, 在网上可找到“RTP 实时网络协议rfc3550.pdf” 文档,有详细介绍。
JRTPLIB 是一个开源的 RTP协议实现库,支持Windows和unix平台,应该也很多人用了,封装的类方式很不错。他的主页是 http://research.edm.uhasselt.be/~jori/page/index.php?n=CS.Jrtplib ,
帮助文档:http://research.edm.uhasselt.be/jori/jrtplib/documentation/index.html
RTPSession Class Reference http://research.edm.uhasselt.be/jori/jrtplib/documentation/classRTPSession.html
从他主页上下载完整的 JRTPLIB 源码包下来解压就行了,不过JRTPLIB 用到了他的JThread库,在主页上可以找到,也把JThread 库下载下来就行了。
解压之后再examples 目录下有几个例子,我试了一下,example2.cpp 和example4.cpp 两个,刚好一个可以作为客户端,一个作为服务器端,在vc2003 中测试了一下。
首先建一个win32 console 项目,把 把JRTPLIB example2.cpp 和 example4.cpp 加进了,再把JRTPLIB 和 JThread 添加到工程中来。 在 include 目下中指定JRTPLIB 和 JThread 的src源码目录。下一步把工程属性中把 “Runtime Library” 改成“Multi-threaded Debug DLL (/MDd)” ,需要改成这个JThread 才能编译通过。最后包含一个 Ws2_32.lib 这个lib库,我是直接在example2.cpp 和example4.cpp 前面添加 #pragma comment (lib, "Ws2_32.lib") 这一句了,在工程属性修改应该一样的。
两个例子的代码如下也贴一下吧:
#pragma comment (lib, "Ws2_32.lib")
#include "rtpsession.h"
#include "rtppacket.h"
#include "rtpudpv4transmitter.h"
#include "rtpipv4address.h"
#include "rtpsessionparams.h"
#include "rtperrors.h"
#ifndef WIN32
#include <netinet/in.h>
#include <arpa/inet.h>
#else
#include <winsock2.h>
#endif // WIN32
#include "rtpsourcedata.h"
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>
#ifdef RTP_SUPPORT_THREAD
This function checks if there was a RTP error. If so, it displays an error
message and exists.
void checkerror(int rtperr)
{
if (rtperr < 0)
{
std::cout << "ERROR: " << RTPGetErrorString(rtperr) << std::endl;
exit(-1);
}
}
The new class routine
class MyRTPSession : public RTPSession
{
protected:
void OnPollThreadStep();
void ProcessRTPPacket(const RTPSourceData &srcdat,const RTPPacket &rtppack);
};
void MyRTPSession::OnPollThreadStep()
{
BeginDataAccess();
check incoming packets
if (GotoFirstSourceWithData())
{
do
{
RTPPacket *pack;
RTPSourceData *srcdat;
srcdat = GetCurrentSourceInfo();
while ((pack = GetNextPacket()) != NULL)
{
ProcessRTPPacket(*srcdat,*pack);
DeletePacket(pack);
}
} while (GotoNextSourceWithData());
}
EndDataAccess();
}
void MyRTPSession::ProcessRTPPacket(const RTPSourceData &srcdat,const RTPPacket &rtppack)
{
You can inspect the packet and the source's info here
std::cout << "Got packet " << rtppack.GetExtendedSequenceNumber() << " from SSRC " << srcdat.GetSSRC() << std::endl;
}
The main routine
int main(void)
{
#ifdef WIN32
WSADATA dat;
WSAStartup(MAKEWORD(2,2),&dat);
#endif // WIN32
MyRTPSession sess;
uint16_t portbase;
std::string ipstr;
int status,num;
First, we'll ask for the necessary information
std::cout << "Enter local portbase:" << std::endl;
std::cin >> portbase;
std::cout << std::endl;
std::cout << std::endl;
std::cout << "Number of seconds you wish to wait:" << std::endl;
std::cin >> num;
Now, we'll create a RTP session, set the destination
and poll for incoming data.
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 just use 8000 samples per second.
sessparams.SetOwnTimestampUnit(1.0/8000.0);
transparams.SetPortbase(portbase);
status = sess.Create(sessparams,&transparams);
checkerror(status);
Wait a number of seconds
RTPTime::Wait(RTPTime(num,0));
sess.BYEDestroy(RTPTime(10,0),0,0);
#ifdef WIN32
WSACleanup();
#endif // WIN32
return 0;
}
#else
int main(void)
{
std::cerr << "Thread support is required for this example" << std::endl;
return 0;
}
#endif // RTP_SUPPORT_THREAD
=============================================================================
#pragma comment (lib, "Ws2_32.lib")
#include "rtpsession.h"
#include "rtpsessionparams.h"
#include "rtpudpv4transmitter.h"
#include "rtpipv4address.h"
#include "rtptimeutilities.h"
#include "rtppacket.h"
#include <stdlib.h>
#include <iostream>
int main(void)
{
#ifdef WIN32
WSADATA dat;
WSAStartup(MAKEWORD(2,2),&dat);
#endif // WIN32
RTPSession session;
RTPSessionParams sessionparams;
sessionparams.SetOwnTimestampUnit(1.0/8000.0);
RTPUDPv4TransmissionParams transparams;
transparams.SetPortbase(8000);
int status = session.Create(sessionparams,&transparams);
if (status < 0)
{
std::cerr << RTPGetErrorString(status) << std::endl;
exit(-1);
}
uint8_t localip[]={127,0,0,1};
RTPIPv4Address addr(localip,9000);
status = session.AddDestination(addr);
if (status < 0)
{
std::cerr << RTPGetErrorString(status) << std::endl;
exit(-1);
}
session.SetDefaultPayloadType(96);
session.SetDefaultMark(false);
session.SetDefaultTimestampIncrement(160);
uint8_t silencebuffer[160];
for (int i = 0 ; i < 160 ; i++)
silencebuffer[i] = 128;
//RTPTime delay(0.020);
RTPTime delay(3.000);
RTPTime starttime = RTPTime::CurrentTime();
bool done = false;
while (!done)
{
status = session.SendPacket(silencebuffer,160);
if (status < 0)
{
std::cerr << RTPGetErrorString(status) << std::endl;
exit(-1);
}
session.BeginDataAccess();
if (session.GotoFirstSource())
{
do
{
RTPPacket *packet;
while ((packet = session.GetNextPacket()) != 0)
{
std::cout << "Got packet with "
<< "extended sequence number "
<< packet->GetExtendedSequenceNumber()
<< " from SSRC " << packet->GetSSRC()
<< std::endl;
session.DeletePacket(packet);
}
} while (session.GotoNextSource());
}
session.EndDataAccess();
RTPTime::Wait(delay);
RTPTime t = RTPTime::CurrentTime();
t -= starttime;
if (t > RTPTime(60.0))
done = true;
}
delay = RTPTime(10.0);
session.BYEDestroy(delay,"Time's up",9);
#ifdef WIN32
WSACleanup();
#endif // WIN32
return 0;
}
JRTPLIB 是一个开源的 RTP协议实现库,支持Windows和unix平台,应该也很多人用了,封装的类方式很不错。他的主页是 http://research.edm.uhasselt.be/~jori/page/index.php?n=CS.Jrtplib ,
帮助文档:http://research.edm.uhasselt.be/jori/jrtplib/documentation/index.html
RTPSession Class Reference http://research.edm.uhasselt.be/jori/jrtplib/documentation/classRTPSession.html
从他主页上下载完整的 JRTPLIB 源码包下来解压就行了,不过JRTPLIB 用到了他的JThread库,在主页上可以找到,也把JThread 库下载下来就行了。
解压之后再examples 目录下有几个例子,我试了一下,example2.cpp 和example4.cpp 两个,刚好一个可以作为客户端,一个作为服务器端,在vc2003 中测试了一下。
首先建一个win32 console 项目,把 把JRTPLIB example2.cpp 和 example4.cpp 加进了,再把JRTPLIB 和 JThread 添加到工程中来。 在 include 目下中指定JRTPLIB 和 JThread 的src源码目录。下一步把工程属性中把 “Runtime Library” 改成“Multi-threaded Debug DLL (/MDd)” ,需要改成这个JThread 才能编译通过。最后包含一个 Ws2_32.lib 这个lib库,我是直接在example2.cpp 和example4.cpp 前面添加 #pragma comment (lib, "Ws2_32.lib") 这一句了,在工程属性修改应该一样的。
两个例子的代码如下也贴一下吧:
#pragma comment (lib, "Ws2_32.lib")
#include "rtpsession.h"
#include "rtppacket.h"
#include "rtpudpv4transmitter.h"
#include "rtpipv4address.h"
#include "rtpsessionparams.h"
#include "rtperrors.h"
#ifndef WIN32
#include <netinet/in.h>
#include <arpa/inet.h>
#else
#include <winsock2.h>
#endif // WIN32
#include "rtpsourcedata.h"
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>
#ifdef RTP_SUPPORT_THREAD
This function checks if there was a RTP error. If so, it displays an error
message and exists.
void checkerror(int rtperr)
{
if (rtperr < 0)
{
std::cout << "ERROR: " << RTPGetErrorString(rtperr) << std::endl;
exit(-1);
}
}
The new class routine
class MyRTPSession : public RTPSession
{
protected:
void OnPollThreadStep();
void ProcessRTPPacket(const RTPSourceData &srcdat,const RTPPacket &rtppack);
};
void MyRTPSession::OnPollThreadStep()
{
BeginDataAccess();
check incoming packets
if (GotoFirstSourceWithData())
{
do
{
RTPPacket *pack;
RTPSourceData *srcdat;
srcdat = GetCurrentSourceInfo();
while ((pack = GetNextPacket()) != NULL)
{
ProcessRTPPacket(*srcdat,*pack);
DeletePacket(pack);
}
} while (GotoNextSourceWithData());
}
EndDataAccess();
}
void MyRTPSession::ProcessRTPPacket(const RTPSourceData &srcdat,const RTPPacket &rtppack)
{
You can inspect the packet and the source's info here
std::cout << "Got packet " << rtppack.GetExtendedSequenceNumber() << " from SSRC " << srcdat.GetSSRC() << std::endl;
}
The main routine
int main(void)
{
#ifdef WIN32
WSADATA dat;
WSAStartup(MAKEWORD(2,2),&dat);
#endif // WIN32
MyRTPSession sess;
uint16_t portbase;
std::string ipstr;
int status,num;
First, we'll ask for the necessary information
std::cout << "Enter local portbase:" << std::endl;
std::cin >> portbase;
std::cout << std::endl;
std::cout << std::endl;
std::cout << "Number of seconds you wish to wait:" << std::endl;
std::cin >> num;
Now, we'll create a RTP session, set the destination
and poll for incoming data.
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 just use 8000 samples per second.
sessparams.SetOwnTimestampUnit(1.0/8000.0);
transparams.SetPortbase(portbase);
status = sess.Create(sessparams,&transparams);
checkerror(status);
Wait a number of seconds
RTPTime::Wait(RTPTime(num,0));
sess.BYEDestroy(RTPTime(10,0),0,0);
#ifdef WIN32
WSACleanup();
#endif // WIN32
return 0;
}
#else
int main(void)
{
std::cerr << "Thread support is required for this example" << std::endl;
return 0;
}
#endif // RTP_SUPPORT_THREAD
=============================================================================
#pragma comment (lib, "Ws2_32.lib")
#include "rtpsession.h"
#include "rtpsessionparams.h"
#include "rtpudpv4transmitter.h"
#include "rtpipv4address.h"
#include "rtptimeutilities.h"
#include "rtppacket.h"
#include <stdlib.h>
#include <iostream>
int main(void)
{
#ifdef WIN32
WSADATA dat;
WSAStartup(MAKEWORD(2,2),&dat);
#endif // WIN32
RTPSession session;
RTPSessionParams sessionparams;
sessionparams.SetOwnTimestampUnit(1.0/8000.0);
RTPUDPv4TransmissionParams transparams;
transparams.SetPortbase(8000);
int status = session.Create(sessionparams,&transparams);
if (status < 0)
{
std::cerr << RTPGetErrorString(status) << std::endl;
exit(-1);
}
uint8_t localip[]={127,0,0,1};
RTPIPv4Address addr(localip,9000);
status = session.AddDestination(addr);
if (status < 0)
{
std::cerr << RTPGetErrorString(status) << std::endl;
exit(-1);
}
session.SetDefaultPayloadType(96);
session.SetDefaultMark(false);
session.SetDefaultTimestampIncrement(160);
uint8_t silencebuffer[160];
for (int i = 0 ; i < 160 ; i++)
silencebuffer[i] = 128;
//RTPTime delay(0.020);
RTPTime delay(3.000);
RTPTime starttime = RTPTime::CurrentTime();
bool done = false;
while (!done)
{
status = session.SendPacket(silencebuffer,160);
if (status < 0)
{
std::cerr << RTPGetErrorString(status) << std::endl;
exit(-1);
}
session.BeginDataAccess();
if (session.GotoFirstSource())
{
do
{
RTPPacket *packet;
while ((packet = session.GetNextPacket()) != 0)
{
std::cout << "Got packet with "
<< "extended sequence number "
<< packet->GetExtendedSequenceNumber()
<< " from SSRC " << packet->GetSSRC()
<< std::endl;
session.DeletePacket(packet);
}
} while (session.GotoNextSource());
}
session.EndDataAccess();
RTPTime::Wait(delay);
RTPTime t = RTPTime::CurrentTime();
t -= starttime;
if (t > RTPTime(60.0))
done = true;
}
delay = RTPTime(10.0);
session.BYEDestroy(delay,"Time's up",9);
#ifdef WIN32
WSACleanup();
#endif // WIN32
return 0;
}