JRTPLIB使用
1.RTP簡介
實時傳輸協(xié)議(Real-time Transport Protocol或簡寫RTP)是一個網(wǎng)絡(luò)傳輸協(xié)議,它是由IETF的多媒體傳輸工作小組1996年在RFC 1889中公布的。
國際電信聯(lián)盟ITU-T也發(fā)布了自己的RTP文檔私蕾,作為H.225.0篙程,但是后來當IETF發(fā)布了關(guān)于它的穩(wěn)定的標準RFC后就被取消了。它作為因特網(wǎng)標準在RFC 3550(該文檔的舊版本是RFC 1889)有詳細說明雅倒。RFC 3551(STD 65,舊版本是RFC 1890)詳細描述了使用最小控制的音頻和視頻會議月培。
RTP協(xié)議詳細說明了在互聯(lián)網(wǎng)上傳遞音頻和視頻的標準數(shù)據(jù)包格式。它一開始被設(shè)計為一個多播協(xié)議恩急,但后來被用在很多單播應(yīng)用中杉畜。RTP協(xié)議常用于流媒體系統(tǒng)(配合RTSP協(xié)議),視頻會議和一鍵通(Push to Talk)系統(tǒng)(配合H.323或SIP)衷恭,使它成為IP電話產(chǎn)業(yè)的技術(shù)基礎(chǔ)寻行。RTP協(xié)議和RTP控制協(xié)議RTCP一起使用,而且它是建立在UDP協(xié)議上的匾荆。實時傳輸協(xié)議------wiki
2.JRTPLIB
RTP 是目前解決流媒體實時傳輸問題的最好辦法拌蜘,如果需要在Linux平臺上進行實時流媒體編程,可以考慮使用一些開放源代碼的RTP庫牙丽,如LIBRTP厚掷、 JRTPLIB等续誉。 JRTPLIB是一個面向?qū)ο蟮腞TP庫弛作,它完全遵循RFC 1889設(shè)計锐墙,在很多場合下是一個非常不錯的選擇,下面就以JRTPLIB為例构罗,講述如何在Linux平臺上運用RTP協(xié)議進行實時流媒體編程铜涉。
JRTPLIB 是一個用C++語言實現(xiàn)的RTP庫,目前已經(jīng)可以運行在Windows遂唧、Linux芙代、FreeBSD、Solaris盖彭、Unix和 VxWorks等多種操作系統(tǒng)上纹烹。------jrtp詳細介紹
3.JRTPLIB編譯
git clone https://github.com/j0r1/JRTPLIB.git
cd JRTPLIB
mkdir build
cd build
cmake .. && make && sudo make install
如果需要啟用JThread支持页滚,需要在編譯JRTPLIB之前編譯JThread
git clone https://github.com/j0r1/JThread.git
cd JRTPLIB
mkdir build
cd build
cmake .. && make && sudo make install
4.JRTPLIB例程
官方歷程參見https://github.com/j0r1/JRTPLIB/tree/master/examples,以下是example1.cpp
铺呵,添加了一些中文注釋
#include "rtpsession.h"
#include "rtpudpv4transmitter.h"
#include "rtpipv4address.h"
#include "rtpsessionparams.h"
#include "rtperrors.h"
#include "rtplibraryversion.h"
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>
using namespace jrtplib;
// 打印錯誤信息
void checkerror(int rtperr)
{
if (rtperr < 0)
{
std::cout << "ERROR: " << RTPGetErrorString(rtperr) << std::endl;
exit(-1);
}
}
// 主循環(huán)
int main(void)
{
// windows相關(guān)裹驰,不需要可以刪了
#ifdef RTP_SOCKETTYPE_WINSOCK
WSADATA dat;
WSAStartup(MAKEWORD(2,2),&dat);
#endif // RTP_SOCKETTYPE_WINSOCK
RTPSession sess;
uint16_t portbase,destport;
uint32_t destip;
std::string ipstr;
int status,i,num;
// 打印JRTPLIB版本
std::cout << "Using version " << RTPLibraryVersion::GetVersion().GetVersionString() << std::endl;
// 獲取本地端口,用以接收
std::cout << "Enter local portbase:" << std::endl;
std::cin >> portbase;
std::cout << std::endl;
// 目標地址片挂,本機使用127.0.0.1
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函數(shù)返回的是網(wǎng)絡(luò)字節(jié)序幻林,需要將網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)化為主機字節(jié)序
destip = ntohl(destip);
// 目標端口,如果發(fā)送給本機音念,與上面的接收端口相同即可
std::cout << "Enter the destination port" << std::endl;
std::cin >> destport;
// 發(fā)包數(shù)量
std::cout << std::endl;
std::cout << "Number of packets you wish to be sent:" << std::endl;
std::cin >> num;
// 創(chuàng)建傳輸參數(shù)和會話參數(shù)
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)
// 設(shè)置時間戳
sessparams.SetOwnTimestampUnit(1.0/10.0);
// 是否接收自己發(fā)送的包
sessparams.SetAcceptOwnPackets(true);
// 設(shè)置接收端口
transparams.SetPortbase(portbase);
// 創(chuàng)建端口
status = sess.Create(sessparams,&transparams);
checkerror(status);
// 寫入IPv4地址和端口
RTPIPv4Address addr(destip,destport);
// 添加目標地址
status = sess.AddDestination(addr);
checkerror(status);
for (i = 1 ; i <= num ; i++)
{
printf("\nSending packet %d/%d\n",i,num);
// 發(fā)包
status = sess.SendPacket((void *)"1234567890",10,0,false,10);
checkerror(status);
sess.BeginDataAccess();
// 檢查收包
if (sess.GotoFirstSourceWithData())
{
do
{
RTPPacket *pack;
while ((pack = sess.GetNextPacket()) != NULL)
{
// 在這里進行數(shù)據(jù)處理
printf("Got packet !\n");
// 不再需要這個包了滋将,刪除之
sess.DeletePacket(pack);
}
} while (sess.GotoNextSourceWithData());
}
sess.EndDataAccess();
// 這部分與JThread庫相關(guān)
#ifndef RTP_SUPPORT_THREAD
status = sess.Poll();
checkerror(status);
#endif // RTP_SUPPORT_THREAD
// 等待一秒,發(fā)包間隔
RTPTime::Wait(RTPTime(1,0));
}
// 銷毀對話
sess.BYEDestroy(RTPTime(10,0),0,0);
// Windows相關(guān)
#ifdef RTP_SOCKETTYPE_WINSOCK
WSACleanup();
#endif // RTP_SOCKETTYPE_WINSOCK
return 0;
}
這里會有問題症昏,怎么讀取收到的packet中的data,需要先包含頭文件
#include "rtppacket.h"
在進行數(shù)據(jù)處理的地方使用以下函數(shù)獲取負載數(shù)據(jù)父丰,和負載長度
pack->GetPayloadData();
pack->GetPayloadLength();
5.CMake配置
在使用CMake進行編譯的時候可能會出現(xiàn)找不到庫的情況肝谭,需要手寫FindJRTPLIB.cmake
# - Find JRTPLIB library
# Once done this will define
# JRTPLIB_FOUND - system has JRTPLIB
# JRTPLIB_INCLUDE_DIR - JRTPLIB include directories
# JRTPLIB_LIBRARY - where to find the JRTPLIB library
if(JRTPLIB_INCLUDE_DIR)
# Already in cache, be silent
set(JRTPLIB_FIND_QUIETLY TRUE)
endif()
find_path(JRTPLIB_INCLUDE_DIR
NAMES rtpsession.h
PATH_SUFFIXES jrtplib jrtplib3
DOC "JRTPLIB include directories"
)
find_library(JRTPLIB_LIBRARY
NAMES jrtp
DOC "JRTPLIB library"
)
# handle the QUIETLY and REQUIRED arguments and set JRTPLIB_FOUND to TRUE if all listed variables are TRUE
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(JRTPLIB
REQUIRED_VARS JRTPLIB_LIBRARY JRTPLIB_INCLUDE_DIR
VERSION_VAR JRTPLIB_VERSION_STRING)
if(JRTPLIB_INCLUDE_DIR AND JRTPLIB_LIBRARY)
set(JRTPLIB_FOUND TRUE)
set(JRTPLIB_LIBRARIES ${JRTPLIB_LIBRARY})
set(JRTPLIB_INCLUDE_DIRS ${JRTPLIB_INCLUDE_DIR})
else()
set (JRTPLIB_FOUND FALSE)
message(FATAL_ERROR "JRTPLIB not found")
endif()
mark_as_advanced(
JRTPLIB_INCLUDE_DIR
JRTPLIB_LIBRARY)
如果前面編譯了JThread庫,或者在編譯的時候提示
This function is not available when using the RTP Poll thread feature.
則還需要將JThread庫進行鏈接蛾扇,FindJTHREAD.cmake
如下
# - Find JTHREAD library
# Once done this will define
# JTHREAD_FOUND - system has JTHREAD
# JTHREAD_INCLUDE_DIR - JTHREAD include directories
# JTHREAD_LIBRARY - where to find the JTHREAD library
if(JTHREAD_INCLUDE_DIR)
# Already in cache, be silent
set(JTHREAD_FIND_QUIETLY TRUE)
endif()
find_path(JTHREAD_INCLUDE_DIR
NAMES jthread.h
PATH_SUFFIXES jthread jthread3
DOC "JTHREAD include directories"
)
find_library(JTHREAD_LIBRARY
NAMES jthread
DOC "JTHREAD library"
)
# handle the QUIETLY and REQUIRED arguments and set JTHREAD_FOUND to TRUE if all listed variables are TRUE
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(JTHREAD
REQUIRED_VARS JTHREAD_LIBRARY JTHREAD_INCLUDE_DIR
VERSION_VAR JTHREAD_VERSION_STRING)
if(JTHREAD_INCLUDE_DIR AND JTHREAD_LIBRARY)
set(JTHREAD_FOUND TRUE)
set(JTHREAD_LIBRARIES ${JTHREAD_LIBRARY})
set(JTHREAD_INCLUDE_DIRS ${JTHREAD_INCLUDE_DIR})
else()
set (JTHREAD_FOUND FALSE)
message(FATAL_ERROR "JTHREAD not found")
endif()
mark_as_advanced(
JTHREAD_INCLUDE_DIR
JTHREAD_LIBRARY)
之后在頂層的CMakeLists.txt
中使用find_package(JRTPLIB)
進行鏈接攘烛,不再贅述。