基於JRTPLib的rtp編程常式

來源:互聯網
上載者:User

標籤: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

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.