最近调试jrtplib的示例程序example1,屡调不通, 在一筹莫展之际,突然想起,会不会是ip地址从字符串向长整形转化的时候存在问题 呢。给destip强制写入一个 7f000001 (就是本机回环测试ip:127.0.0.1),再调试,果然通过。嗨,没想到真是这里出了问题。现在把代码贴出来,这里贴的代码经过了一些改动,可以用 了,而且研究了packet类的各个成员,以及如何获取打包后的数据及包头的方法(每包的包头是12字节)。另外,我的jrtplib编译成了无线程版 本,本文给出的两个例子也都是针对无线程支持的jrtplib。初开始,我把jrtplib编译成为有线程版本,结果发现总是有问题,就干脆把线程支持部 分去掉了。
example1 程序如下:
----------------------------------------------------------------------------------------------------------------------------------
/*
Here's a small IPv4 example: it asks for a portbase and a destination and
starts sending packets to that destination.
这是一个小小的IPv4的示例程序:它请求一个起始端口和一个目标地址然后开始发送
一些包到那个目标地址。
*/
#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 <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>
#pragma comment(lib, "jrtplib.lib")
#pragma comment(lib, "Ws2_32.lib")
//
// This function checks if there was a RTP error. If so, it displays an error
// message and exists.
// 这个函数检测是否有一个RTP错误,如果有,它显示一个错误消息,并且退出
//(原注释中怀疑是写错了,应为exits.)
//
void checkerror(int rtperr)
{
if (rtperr < 0)
{
std::cout << "ERROR: " << RTPGetErrorString(rtperr) << std::endl;
getchar();
exit(-1);
}
}
uint32_t str_ip_to_long_ip(char *strip)
{
int i,j=3;
unsigned char byt[4];
long lret;
for ( i=0 ; i < strlen ( strip ) ; i++ )
{
}
return lret;
}
//
// The main routine
// 主例程
int main(void)
{
#ifdef WIN32
WSADATA dat;
//makeword(lobyte,hibyte)把两个字节连成一个字
WSAStartup(MAKEWORD(2,2),&dat);
#endif // WIN32
RTPSession sess;
uint16_t portbase,destport;
uint32_t destip;
std::string ipstr;
int status,i,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 << "Enter the destination IP address(请输入目标IP地址)" << std::endl;
std::cin >> ipstr;
destip = inet_addr(ipstr.c_str());//把字符串转成32位的IP地址
if (destip == INADDR_NONE)
{
std::cerr << "Bad IP address specified(指定了错误的IP地址)" << std::endl;
return -1;
}
// The inet_addr function returns a value in network byte order, but
// we need the IP address in host byte order, so we use a call to
// ntohl
// inet_addr函数返回一个以网络字节序的值,但是我们需要的是主字节序的值,
// 所以我们需要使用一个ntohl的调用。
destip = ntohl(destip); //n (network byte order) to h (host byte order)
//l (long)
//调试
destip=0x7f000001;
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;
// Now, we'll create a RTP session, set the destination, send some
// packets and poll for incoming data.
// 现在,我们可以创建一个rtp会话,设置目标,发送一些包,然后轮询流入的数据。
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)
// 重要:本地时间戳单元必须设置,否则在这种情况下RTCP发送者报告信息将会被计算错误,
//我们将会每秒发送10个样本,所以我们把时间戳单元里面放上(1.0 / 10.0)。
sessparams.SetOwnTimestampUnit(1.0/10.0);
sessparams.SetAcceptOwnPackets(true);
transparams.SetPortbase(portbase);
status = sess.Create(sessparams,&transparams); //创建会话
checkerror(status);
RTPIPv4Address addr(destip,destport);
status = sess.AddDestination(addr); //添加目标ip地址
checkerror(status);
for (i = 1 ; i <= num ; i++)
{
printf("\nSending packet %d/%d/%s \n",i,num,"1234567890");
// send the packet 发送数据包
status = sess.SendPacket((void *)"1234567890",10,0,false,10);
checkerror(status);
sess.BeginDataAccess(); //开始数据访问
// check incoming packets 检查流入的包
if (sess.GotoFirstSourceWithData())
{
do
{
RTPPacket *pack;
while ((pack = sess.GetNextPacket()) != NULL)
{
// You can examine the data here 你可以在这检查数据
printf("Got packet !\n");
// we don't longer need the packet, so
// we'll delete it 我们不再需要这个包,所以我们删除它
delete pack;
}
} while (sess.GotoNextSourceWithData());
}
sess.EndDataAccess(); //结束数据访问;
#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);
#ifdef WIN32
WSACleanup();
#endif // WIN32
getchar();
return 0;
}
----------------------------------------------------------------------------------------------------------------------------------
example3 程序如下:
----------------------------------------------------------------------------------------------------------------------------------
/*
This IPv4 example listens for incoming packets
and automatically adds destinations
for new sources.
这个ipv4示例程序监听流入的数据并且自动的为新的源添加目标地址
*/
#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>
#pragma comment (lib,"Ws2_32.lib")
//
// 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;
getchar();
exit(-1);
}
}
//
// The new class routine
// 新的类例程;继承自RTPSession类
class MyRTPSession : public RTPSession
{
protected:
void OnNewSource(RTPSourceData *dat)
{
if (dat->IsOwnSSRC())
return;
uint32_t ip;
uint16_t port;
if (dat->GetRTPDataAddress() != 0)
{
const RTPIPv4Address *addr = (const RTPIPv4Address *)(dat->GetRTPDataAddress());
ip = addr->GetIP();
port = addr->GetPort();
}
else if (dat->GetRTCPDataAddress() != 0)
{
const RTPIPv4Address *addr = (const RTPIPv4Address *)(dat->GetRTCPDataAddress());
ip = addr->GetIP();
port = addr->GetPort()-1;
}
else
return;
RTPIPv4Address dest(ip,port);
AddDestination(dest);
struct in_addr inaddr;
inaddr.s_addr = htonl(ip);
std::cout << "Adding destination " << std::string(inet_ntoa(inaddr)) << ":" << port << std::endl;
}
void OnBYEPacket(RTPSourceData *dat)
{
if (dat->IsOwnSSRC())
return;
uint32_t ip;
uint16_t port;
if (dat->GetRTPDataAddress() != 0)
{
const RTPIPv4Address *addr = (const RTPIPv4Address *)(dat->GetRTPDataAddress());
ip = addr->GetIP();
port = addr->GetPort();
}
else if (dat->GetRTCPDataAddress() != 0)
{
const RTPIPv4Address *addr = (const RTPIPv4Address *)(dat->GetRTCPDataAddress());
ip = addr->GetIP();
port = addr->GetPort()-1;
}
else
return;
RTPIPv4Address dest(ip,port);
DeleteDestination(dest);
struct in_addr inaddr;
inaddr.s_addr = htonl(ip);
std::cout << "Deleting destination " << std::string(inet_ntoa(inaddr)) << ":" << port << std::endl;
}
void OnRemoveSource(RTPSourceData *dat)
{
if (dat->IsOwnSSRC())
return;
if (dat->ReceivedBYE())
return;
uint32_t ip;
uint16_t port;
if (dat->GetRTPDataAddress() != 0)
{
const RTPIPv4Address *addr = (const RTPIPv4Address *)(dat->GetRTPDataAddress());
ip = addr->GetIP();
port = addr->GetPort();
}
else if (dat->GetRTCPDataAddress() != 0)
{
const RTPIPv4Address *addr = (const RTPIPv4Address *)(dat->GetRTCPDataAddress());
ip = addr->GetIP();
port = addr->GetPort()-1;
}
else
return;
RTPIPv4Address dest(ip,port);
DeleteDestination(dest);
struct in_addr inaddr;
inaddr.s_addr = htonl(ip);
std::cout << "Deleting destination " << std::string(inet_ntoa(inaddr)) << ":" << port << std::endl;
}
};
//
// The main routine
//
int main(void)
{
#ifdef WIN32
WSADATA dat;
WSAStartup(MAKEWORD(2,2),&dat);
#endif // WIN32
MyRTPSession sess;
uint16_t portbase,destport;
uint32_t destip;
std::string ipstr;
int status,i,num,j=0;
char sss[100];
ZeroMemory(sss,100);
// 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.
//现在,我们将创建一个rtp会话,设置目标地址并且轮询流入的数据;
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
// 每秒8000个样本.
/* 重要: */
//sessparams.SetOwnTimestampUnit(1.0/8000.0);
sessparams.SetOwnTimestampUnit(1.0/10.0);
sessparams.SetAcceptOwnPackets(true);
transparams.SetPortbase(portbase);
status = sess.Create(sessparams,&transparams);
checkerror(status);
for (i = 1 ; i <= num ; i++)
{
sess.BeginDataAccess();
//std::cout<<"got packet!"<<std::endl;
// check incoming packets 检查流入的包
if (sess.GotoFirstSourceWithData())
{
do
{
RTPPacket *pack;
while ((pack = sess.GetNextPacket()) != NULL)
{
memcpy(sss,pack->GetPacketData()+12,pack->GetPacketLength()-12);
// You can examine the data here
//printf("Got packet ! %d\n%d\n%s\n\n",j++,pack->GetPacketLength(),sss);
printf("Got packet ! %d\n",j++);
printf("packet len: %d \n",pack->GetPacketLength());
printf("packet data : %s \n" , sss);
for (int k=0;k<12;k++)
printf("RTPHeader bytes: %x\n",pack->GetPacketData()[k]);
// we don't longer need the packet, so
// we'll delete it
delete pack;
}
} while (sess.GotoNextSourceWithData());
}
sess.EndDataAccess();
#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);
#ifdef WIN32
WSACleanup();
#endif // WIN32
return 0;
}