最近調試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;
}
-----------------------------------------------------------------------------------------------------------------------------------