標籤:des blog http 使用 strong os
這裡示範了在linux環境下使用JRTPlib庫完成rtp協議的封裝,此常式可以作為流媒體傳輸的基本常式。
這裡只給出源碼(這些在JRtplib的官方檔案中都可以找到)
發送端:
/*
* 發送端程式(windows,linux通用)
* 基於IPv4的傳輸常式,需要提供一個連接埠號碼和目的地址
* 參考:http://blog.csdn.net/ipromiseu/article/details/4531656
*/
#include "rtpsession.h" //定義了rtpsession的一些實現
#include "rtppacket.h" //定義了rtppacket資料包
#include "rtpudpv4transmitter.h"//定義了RTPSession的第二個參數類
#include "rtpipv4address.h"//定義了rtpipv4address
#include "rtpsessionparams.h"//定義了rtpsession的第一個參數類
#include "rtperrors.h" //定義了RTP中的錯誤資訊
#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>
//檢查是否出現rtp錯誤,如果出錯就列印出錯資訊
void checkerror(int rtperr)
{
if (rtperr < 0)
{
std::cout << "ERROR: " << RTPGetErrorString(rtperr) << std::endl;
exit(-1);
}
}
//主迴圈
int main(void)
{
//windows環境下我們需要首次載入通訊端
#ifdef WIN32
WSADATA dat;
WSAStartup(MAKEWORD(2,2),&dat);
#endif // WIN32
RTPSession sess;
//RTPSession類來執行個體化此次的RTP會話
uint16_t portbase,destport;
//本機連接埠號碼,目的連接埠號碼
uint32_t destip;
//目的IP
std::string ipstr;
int status,i,num;
//首先獲得必須的資訊
std::cout << "Enter local portbase:" << std::endl;
std::cin >> portbase;
std::cout << std::endl;
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返回一個基於網路位元組序列,我們需要的是一個基於本機位元組序列的,
//還需要使用ntohl
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;
//下面建立一個RTP會話,發送傳入的資料包
//這是rtpsession的第二個參數類,他的成員函數可以設定監聽連接埠
RTPUDPv4TransmissionParams transparams;
//這是rtpsession的第一個參數類,他的成員函數可以設定恰當的時戳單元
RTPSessionParams sessparams;
//設定恰當的時戳單元,每秒我們需要發送10次,故參數為1.0/10
sessparams.SetOwnTimestampUnit(1.0/10.0);
//下面設定是不是接收我們自訂的資料包,這裡選是
sessparams.SetAcceptOwnPackets(true);
//設定本機連接埠
transparams.SetPortbase(portbase);
//初始化,建立rtp會話
status = sess.Create(sessparams,&transparams);
checkerror(status);
//組合目的地址
RTPIPv4Address addr(destip,destport);
//設定目的地址,增加發送的目的地址。當然可以增加很多地址完成多播的功能
//另外還可以使用DeleteDestination()和 ClearDestinations()來刪除和清楚目的地址
//也可以寫成: unsigned long addr = ntohl(inet_addr("127.0.0.1"));
// sess.AddDestination(addr,6000);
status = sess.AddDestination(addr);
checkerror(status);
for (i = 1 ; i <= num ; i++)
{
printf("\nSending packet %d/%d\n",i,num);
//發送流媒體資料.第一個參數是發送的資料,二個是資料長度,往後是rtp負載類型,標識,時戳量
//當然JRTPLIB允許將他們設定成會話的預設參數,這是調用RTPSession類的setDefaultpayloadtype(),setDefaultmark,等方法類完成的,如果那樣設定之後,我們可以這樣來發送資料:
//status = sess.SendPacket((void *)"1234567890",10);
status = sess.SendPacket((void *)"1234567890",10,0,false,10);
checkerror(status);
/*
sess.BeginDataAccess();
//收到的報文,遍曆所有攜帶資料的源(因為一個rtp會話允許有多個參與者(源))
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
sess.DeletePacket(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);
//windows環境下我們最後還有卸載通訊端
#ifdef WIN32
WSACleanup();
#endif // WIN32
return 0;
}
接收端:
/*
* JRTPLIB接收資料常式
* http://blog.sina.com.cn/s/blog_57e2e18901008s4h.html
*/
#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>
//檢查錯誤
void checkerror(int rtperr)
{
if (rtperr < 0)
{
std::cout << "ERROR: " << RTPGetErrorString(rtperr) << std::endl;
exit(-1);
}
}
//重新封裝一個類
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;
std::string ipstr;
int status,i,num;
unsigned char *payloadpointer;
int j,len;
// 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;
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);
sessparams.SetAcceptOwnPackets(true);
transparams.SetPortbase(portbase);
status = sess.Create(sessparams,&transparams);
checkerror(status);
for (i = 1 ; i <= num ; i++)
{
sess.BeginDataAccess();
//遍曆所有的帶資料的源
if (sess.GotoFirstSourceWithData())
{
do
{
RTPPacket *pack;
while ((pack = sess.GetNextPacket()) != NULL)
{
// You can examine the data here
printf("Got packet !\n");
payloadpointer = pack->GetPayloadData();//獲得資料指標
len = pack->GetPayloadLength();//獲得資料長度
for(j=0;j<len;j++)
{
printf("%c ",*(payloadpointer+j));//列印資料
}
printf("\n");
//刪除獲得的資料
sess.DeletePacket(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;
}
編譯:g++ -o example1 example1.cpp -I /usr/local/include/jrtplib3/ -ljrtp