linux?下基于jrtplib庫的實時傳送實現
一、RTP?是進行實時流媒體傳輸的標準協議和關鍵技術
?實時傳輸協議(Real-time?Transport?Protocol,PRT)是在?Internet?上處理多媒體數據流的一種網絡協議,利用它能夠在一對一(unicast,單播)或者一對多(multicast,多播)的網絡環境中實現傳流媒體數據的實時傳輸。RTP?通常使用?UDP?來進行多媒體數據的傳輸,但如果需要的話可以使用?TCP?或者?ATM?等其它協議。
?協議分析?:每一個RTP數據報都由頭部(Header)和負載(Payload)兩個部分組成,其中頭部前?12?個字節的含義是固定的,而負載則可以是音頻或者視頻數據。
??????RTP?是目前解決流媒體實時傳輸問題的最好辦法,要在?Linux?平臺上進行實時傳送編程,可以考慮使用一些開放源代碼的?RTP?庫,如?LIBRTP、JRTPLIB?等。JRTPLIB?是一個面向對象的?RTP?庫,它完全遵循?RFC?1889?設計,在很多場合下是一個非常不錯的選擇。JRTPLIB?是一個用?C++?語言實現的?RTP?庫,這個庫使用socket?機制實現網絡通訊?因此可以運行在?Windows、Linux、FreeBSD、Solaris、Unix和VxWorks?等多種操作系統上。
二、JRTPLIB?庫的使用方法及程序實現
?(1)JRTPLIB??函數?的使用
?a、在使用?JRTPLIB?進行實時流媒體數據傳輸之前,首先應該生成?RTPSession?類的一個實例來表示此次?RTP?會話,然后調用?Create()?方法來對其進行初始化操作。RTPSession?類的?Create()?方法只有一個參數,用來指明此次?RTP?會話所采用的端口號。
?RTPSession?sess;??sess.Create(5000);?
?b、設置恰當的時戳單元,是?RTP?會話初始化過程所要進行的另外一項重要工作,這是通過調用?RTPSession?類的?SetTimestampUnit()?方法來實現的,該方法同樣也只有一個參數,表示的是以秒為單元的時戳單元。
?sess.SetTimestampUnit(1.0/8000.0);
?c、當?RTP?會話成功建立起來之后,接下去就可以開始進行流媒體數據的實時傳輸了。首先需要設置好數據發送的目標地址,RTP?協議允許同一會話存在多個目標地址,這可以通過調用?RTPSession?類的?AddDestination()、DeleteDestination()?和?ClearDestinations()?方法來完成。例如,下面的語句表示的是讓?RTP?會話將數據發送到本地主機的?6000?端口:?
?unsigned?long?addr?=?ntohl(inet_addr("127.0.0.1"));?
?sess.AddDestination(addr,?6000);
?
?d、目標地址全部指定之后,接著就可以調用?RTPSession?類的?SendPacket()?方法,向所有的目標地址發送流媒體數據。SendPacket()?是?RTPSession?類提供的一個重載函數
對于同一個?RTP?會話來講,負載類型、標識和時戳增量通常來講都是相同的,JRTPLIB?允許將它們設置為會話的默認參數,這是通過調用?RTPSession?類的?SetDefaultPayloadType()、SetDefaultMark()?和?SetDefaultTimeStampIncrement()?方法來完成的。為?RTP?會話設置這些默認參數的好處是可以簡化數據的發送,例如,如果為?RTP?會話設置了默認參數:?
?sess.SetDefaultPayloadType(0);
??sess.SetDefaultMark(false);??
?sess.SetDefaultTimeStampIncrement(10);
?
之后在進行數據發送時只需指明要發送的數據及其長度就可以了:?
?sess.SendPacket(buffer,?5);?
?e、對于流媒體數據的接收端,首先需要調用?RTPSession?類的?PollData()?方法來接收發送過來的?RTP?或者?RTCP?數據報。由于同一個?RTP?會話中允許有多個參與者(源),你既可以通過調用?RTPSession?類的?GotoFirstSource()?和?GotoNextSource()?方法來遍歷所有的源,也可以通過調用?RTPSession?類的?GotoFirstSourceWithData()?和?GotoNextSourceWithData()?方法來遍歷那些攜帶有數據的源。在從?RTP?會話中檢測出有效的數據源之后,接下去就可以調用?RTPSession?類的?GetNextPacket()?方法從中抽取?RTP?數據報,當接收到的?RTP?數據報處理完之后,一定要記得及時釋放。
JRTPLIB?為?RTP?數據報定義了三種接收模式,其中每種接收模式都具體規定了哪些到達的?RTP?數據報將會被接受,而哪些到達的?RTP?數據報將會被拒絕。通過調用?RTPSession?類的?SetReceiveMode()?方法可以設置下列這些接收模式:?
??RECEIVEMODE_ALL 缺省的接收模式,所有到達的?RTP?數據報都將被接受;?
??RECEIVEMODE_IGNORESOME 除了某些特定的發送者之外,所有到達的?RTP?數據報都將被接受,而被拒絕的發送者列表可以通過調用?AddToIgnoreList()、DeleteFromIgnoreList()?和?ClearIgnoreList()?方法來進行設置;?
??RECEIVEMODE_ACCEPTSOME 除了某些特定的發送者之外,所有到達的?RTP?數據報都將被拒絕,而被接受的發送者列表可以通過調用?AddToAcceptList?()、DeleteFromAcceptList?和?ClearAcceptList?()?方法來進行設置。?下面是采用第三種接收模式的程序示例。
?if?(sess.GotoFirstSourceWithData())?{???
??do?{???
???sess.AddToAcceptList(remoteIP,?allports,portbase);
??????????sess.SetReceiveMode(RECEIVEMODE_ACCEPTSOME);
?
????RTPPacket?*pack;?????????
????pack?=?sess.GetNextPacket();????????????//?處理接收到的數據????
????delete?pack;???}?
??while?(sess.GotoNextSourceWithData());?
??}
??(2)程序流程圖
發送:獲得接收端的?IP?地址和端口號????????創建?RTP?會話????????指定?RTP?數據接收端?設置?RTP?會話默認參數???發送流媒體數據
接收:獲得用戶指定的端口號??創建RTP會話??設置接收模式??接受RTP數據??檢索RTP數據源??獲取RTP數據報??刪除RTP數據報
三、環境搭建及編譯方法
(1)Toolchain的安裝
?首先找到xscale-arm-toolchain.tgz文件,假設該文件包放在/tmp/下
?#cd?/
?#tar?-zxvf?/tmp/xscale-arm-toolchain.tgz
?再設置環境變量
?#export?PATH=/usr/local/arm-linux/bin:$PATH
?最后檢查一下交叉編譯工具是否安裝成功
?#arm-linux-g++?--version
?看是否顯示arm-linux-g++的版本,如有則安裝成功。
(2)JRTPLIB?庫的交叉編譯及安裝
?首先從?JRTPLIB?的網站(http://lumumba.luc.ac.be/jori/jrtplib/jrtplib.htmll)?下載最新的源碼包,此處使用的是jrtplib-2.8.tar,假設下載后的源碼包放在/tmp下,執?行下面的命令對其解壓縮:
?#cd?/tmp
?#tar?-zxvf?jrtplib-2.8.tar
?然后要對jrtplib進行配置和編譯
?#cd?jrtplib-2.8
?#./configure?CC=arm-linux-g++?cross-compile=yes
?修改Makefile文件
?將鏈接命令ld?和ar改為arm-linux-ld和?arm-linux-ar
?#make
?最后再執行如下命令就可以完成?JRTPLIB?的安裝:
?#make?install
(3)程序編譯
?a、配置編譯環境
?可以用export來配置,也可以用編寫Makefile的方法。這里采用Makefile。
?編寫Makefile&:
INCL?=?-I/usr/local/include
CFLAGS?=?-pipe?-O2?-fno-strength-reduce
LFLAGS?=?/usr/local/lib/libjrtp.a?-L/usr/X11R6/lib
LIBS?=?-LX11?-LXext?/usr/local/lib/libjrtp.a
CC?=?arm-linux-g++
main:main.o
?$(CC)?$(LFLAGS)?$(INCL)?-o?main?main.o?$(LIBS)
main.o:main.cpp
clean:
?rm?-f?main
?rm?-f?*.o
?
.SUFFIXES:.cpp
.cpp.o:
?$(CC)?-c?$(CFLAGS)?$(INCL)?-o?$@?$<?????????/*??$@表示目標的完整名字??????*/
??????????/*?$<表示第一個依賴文件的名字?*/
?b、編譯
?假設發送和接收程序分別放在/tmp/send和/tmp/receive目錄下
?#cd?/tmp/send
?#make
?#cd?/tmp/receive
?#make
四、易出錯誤及注意問題
?1、找不到一些標準的最?基本的一些頭文件。
??主要是因為Toolchain路徑沒安裝對,要?嚴格按照步驟安裝。
?2、找不到使用的jrtplib庫中的一些頭文件。
??在?jrtplib的安裝目錄下,include路徑下不能再有別的目錄。
?3、recieve函數接收數據包不能正確提出所要數據。
??由于每一個RTP數據報都由頭部(Header)和負載(Payload)兩個部分組成,若使用getrawdata()是返回整個數據包的數據,包含傳輸媒體的類型、格式、序列號、時間戳以及是否有附加數據等信息。getpayload()函數是返回所發送的數據。兩者一定要分清。
?4、設置RECEIVEMODE_ACCEPTSOME 接收模式后,運行程序接收端不能接包。
??IP地址格式出了問題。iner_addr()與ntohl()函數要用對,否則參數傳不進去,接受列表中無值,當然接收不了數據包。
?5、編譯通過,但測試時接收端不能接收到數據。
??可能是接收機防火墻未關閉。運行:
??#iptables?-F
??也可能是IP地址沒有設置好。運行:
??#ifocnfig?eth0??*.*.*.*??netmask?*.*.*.*
?6、使用jrtolib庫時,在程序中include?后最好加上庫所在的路徑。
五、程序
send:
#include?<stdio.h>
#include?<string.h>
#include?"rtpsession.h"
//?錯誤處理函數
void?checkerror(int?err)
{
??if?(err?<?0)?{
????char*?errstr?=?RTPGetErrorString(err);
????printf("Error:%s\\n",?errstr);
????exit(-1);
??}
}
int?main(int?argc,?char**?argv)
{
??RTPSession?sess;
??unsigned?long?destip;
??int?destport;
??int?portbase?=?6000;
??int?status,?index;
??char?buffer[128];
??if?(argc?!=?3)?{
????printf("Usage:?./sender?destip?destport\\n");
????return?-1;
??}
??//?獲得接收端的IP地址和端口號
??destip?=?inet_addr(argv[1]);
??if?(destip?==?INADDR_NONE)?{
????printf("Bad?IP?address?specified.\\n");
????return?-1;
??}
??destip?=?ntohl(destip);
??destport?=?atoi(argv[2]);
??//?創建RTP會話
??status?=?sess.Create(portbase);
??checkerror(status);
??//?指定RTP數據接收端
??status?=?sess.AddDestination(destip,?destport);
??checkerror(status);
??//?設置RTP會話默認參數
??sess.SetDefaultPayloadType(0);
??sess.SetDefaultMark(false);
??sess.SetDefaultTimeStampIncrement(10);
??//?發送流媒體數據
??index?=?1;
??do?{
????sprintf(buffer,?"%d:?RTP?packet",?index?++);
????sess.SendPacket(buffer,?strlen(buffer));
????printf("Send?packet?!\\n");
??}?while(1);
??return?0;
}
receive:
#include?<stdio.h>
#include?"rtpsession.h"
#include?"rtppacket.h"
//?錯誤處理函數
void?checkerror(int?err)
{
??if?(err?<?0)?{
????char*?errstr?=?RTPGetErrorString(err);
????printf("Error:%s\\n",?errstr);
????exit(-1);
??}
}
int?main(int?argc,?char**?argv)
{
??RTPSession?sess;
??int?localport,portbase;
??int?status;
??unsigned?long?remoteIP;
??if?(argc?!=?4)?{
????printf("Usage:?./sender?localport\\n");
????return?-1;
??}
???//?獲得用戶指定的端口號
???
??remoteIP?=?inet_addr(argv[1]);
??localport?=?atoi(argv[2]);
??portbase?=?atoi(argv[3]);
??//?創建RTP會話
??status?=?sess.Create(localport);
??checkerror(status);
??
??//RTPHeader?*rtphdr;
??unsigned?long?timestamp1;
??unsigned?char?*?RawData;
??unsigned?char?temp[30];
??int?lengh?,i;
??bool?allports?=?1;
??
??sess.AddToAcceptList(remoteIP,?allports,portbase);
??
?????do?{
?//設置接收模式
????????sess.SetReceiveMode(RECEIVEMODE_ACCEPTSOME);
???sess.AddToAcceptList(remoteIP,?allports,portbase);
????//?接受RTP數據
????status?=?sess.PollData();
????
?//?檢索RTP數據源
????if?(sess.GotoFirstSourceWithData())?{
??????do?{
????????
????????RTPPacket*?packet;
????????//?獲取RTP數據報
????????while?((packet?=?sess.GetNextPacket())?!=?NULL)?{
??????????printf("Got?packet?!\n");
???timestamp1?=?packet->GetTimeStamp();
???lengh=packet->GetPayloadLength();
???RawData=packet->GetPayload();
???
???for(i=0;i<lengh;i++){
??????temp[i]=RawData[i];
??printf("%c",temp[i]);
???}
???temp[i]='\0';
???printf("??timestamp:?%d?lengh=%d?data:%s\n",timestamp1,lengh,&temp);
??????????//?刪除RTP數據報
???
??????????delete?packet;
????????}
??????}?while?(sess.GotoNextSourceWithData());
????}
??}?while(1);
??return?0;
}
一、RTP?是進行實時流媒體傳輸的標準協議和關鍵技術
?實時傳輸協議(Real-time?Transport?Protocol,PRT)是在?Internet?上處理多媒體數據流的一種網絡協議,利用它能夠在一對一(unicast,單播)或者一對多(multicast,多播)的網絡環境中實現傳流媒體數據的實時傳輸。RTP?通常使用?UDP?來進行多媒體數據的傳輸,但如果需要的話可以使用?TCP?或者?ATM?等其它協議。
?協議分析?:每一個RTP數據報都由頭部(Header)和負載(Payload)兩個部分組成,其中頭部前?12?個字節的含義是固定的,而負載則可以是音頻或者視頻數據。
??????RTP?是目前解決流媒體實時傳輸問題的最好辦法,要在?Linux?平臺上進行實時傳送編程,可以考慮使用一些開放源代碼的?RTP?庫,如?LIBRTP、JRTPLIB?等。JRTPLIB?是一個面向對象的?RTP?庫,它完全遵循?RFC?1889?設計,在很多場合下是一個非常不錯的選擇。JRTPLIB?是一個用?C++?語言實現的?RTP?庫,這個庫使用socket?機制實現網絡通訊?因此可以運行在?Windows、Linux、FreeBSD、Solaris、Unix和VxWorks?等多種操作系統上。
二、JRTPLIB?庫的使用方法及程序實現
?(1)JRTPLIB??函數?的使用
?a、在使用?JRTPLIB?進行實時流媒體數據傳輸之前,首先應該生成?RTPSession?類的一個實例來表示此次?RTP?會話,然后調用?Create()?方法來對其進行初始化操作。RTPSession?類的?Create()?方法只有一個參數,用來指明此次?RTP?會話所采用的端口號。
?RTPSession?sess;??sess.Create(5000);?
?b、設置恰當的時戳單元,是?RTP?會話初始化過程所要進行的另外一項重要工作,這是通過調用?RTPSession?類的?SetTimestampUnit()?方法來實現的,該方法同樣也只有一個參數,表示的是以秒為單元的時戳單元。
?sess.SetTimestampUnit(1.0/8000.0);
?c、當?RTP?會話成功建立起來之后,接下去就可以開始進行流媒體數據的實時傳輸了。首先需要設置好數據發送的目標地址,RTP?協議允許同一會話存在多個目標地址,這可以通過調用?RTPSession?類的?AddDestination()、DeleteDestination()?和?ClearDestinations()?方法來完成。例如,下面的語句表示的是讓?RTP?會話將數據發送到本地主機的?6000?端口:?
?unsigned?long?addr?=?ntohl(inet_addr("127.0.0.1"));?
?sess.AddDestination(addr,?6000);
?
?d、目標地址全部指定之后,接著就可以調用?RTPSession?類的?SendPacket()?方法,向所有的目標地址發送流媒體數據。SendPacket()?是?RTPSession?類提供的一個重載函數
對于同一個?RTP?會話來講,負載類型、標識和時戳增量通常來講都是相同的,JRTPLIB?允許將它們設置為會話的默認參數,這是通過調用?RTPSession?類的?SetDefaultPayloadType()、SetDefaultMark()?和?SetDefaultTimeStampIncrement()?方法來完成的。為?RTP?會話設置這些默認參數的好處是可以簡化數據的發送,例如,如果為?RTP?會話設置了默認參數:?
?sess.SetDefaultPayloadType(0);
??sess.SetDefaultMark(false);??
?sess.SetDefaultTimeStampIncrement(10);
?
之后在進行數據發送時只需指明要發送的數據及其長度就可以了:?
?sess.SendPacket(buffer,?5);?
?e、對于流媒體數據的接收端,首先需要調用?RTPSession?類的?PollData()?方法來接收發送過來的?RTP?或者?RTCP?數據報。由于同一個?RTP?會話中允許有多個參與者(源),你既可以通過調用?RTPSession?類的?GotoFirstSource()?和?GotoNextSource()?方法來遍歷所有的源,也可以通過調用?RTPSession?類的?GotoFirstSourceWithData()?和?GotoNextSourceWithData()?方法來遍歷那些攜帶有數據的源。在從?RTP?會話中檢測出有效的數據源之后,接下去就可以調用?RTPSession?類的?GetNextPacket()?方法從中抽取?RTP?數據報,當接收到的?RTP?數據報處理完之后,一定要記得及時釋放。
JRTPLIB?為?RTP?數據報定義了三種接收模式,其中每種接收模式都具體規定了哪些到達的?RTP?數據報將會被接受,而哪些到達的?RTP?數據報將會被拒絕。通過調用?RTPSession?類的?SetReceiveMode()?方法可以設置下列這些接收模式:?
??RECEIVEMODE_ALL 缺省的接收模式,所有到達的?RTP?數據報都將被接受;?
??RECEIVEMODE_IGNORESOME 除了某些特定的發送者之外,所有到達的?RTP?數據報都將被接受,而被拒絕的發送者列表可以通過調用?AddToIgnoreList()、DeleteFromIgnoreList()?和?ClearIgnoreList()?方法來進行設置;?
??RECEIVEMODE_ACCEPTSOME 除了某些特定的發送者之外,所有到達的?RTP?數據報都將被拒絕,而被接受的發送者列表可以通過調用?AddToAcceptList?()、DeleteFromAcceptList?和?ClearAcceptList?()?方法來進行設置。?下面是采用第三種接收模式的程序示例。
?if?(sess.GotoFirstSourceWithData())?{???
??do?{???
???sess.AddToAcceptList(remoteIP,?allports,portbase);
??????????sess.SetReceiveMode(RECEIVEMODE_ACCEPTSOME);
?
????RTPPacket?*pack;?????????
????pack?=?sess.GetNextPacket();????????????//?處理接收到的數據????
????delete?pack;???}?
??while?(sess.GotoNextSourceWithData());?
??}
??(2)程序流程圖
發送:獲得接收端的?IP?地址和端口號????????創建?RTP?會話????????指定?RTP?數據接收端?設置?RTP?會話默認參數???發送流媒體數據
接收:獲得用戶指定的端口號??創建RTP會話??設置接收模式??接受RTP數據??檢索RTP數據源??獲取RTP數據報??刪除RTP數據報
三、環境搭建及編譯方法
(1)Toolchain的安裝
?首先找到xscale-arm-toolchain.tgz文件,假設該文件包放在/tmp/下
?#cd?/
?#tar?-zxvf?/tmp/xscale-arm-toolchain.tgz
?再設置環境變量
?#export?PATH=/usr/local/arm-linux/bin:$PATH
?最后檢查一下交叉編譯工具是否安裝成功
?#arm-linux-g++?--version
?看是否顯示arm-linux-g++的版本,如有則安裝成功。
(2)JRTPLIB?庫的交叉編譯及安裝
?首先從?JRTPLIB?的網站(http://lumumba.luc.ac.be/jori/jrtplib/jrtplib.htmll)?下載最新的源碼包,此處使用的是jrtplib-2.8.tar,假設下載后的源碼包放在/tmp下,執?行下面的命令對其解壓縮:
?#cd?/tmp
?#tar?-zxvf?jrtplib-2.8.tar
?然后要對jrtplib進行配置和編譯
?#cd?jrtplib-2.8
?#./configure?CC=arm-linux-g++?cross-compile=yes
?修改Makefile文件
?將鏈接命令ld?和ar改為arm-linux-ld和?arm-linux-ar
?#make
?最后再執行如下命令就可以完成?JRTPLIB?的安裝:
?#make?install
(3)程序編譯
?a、配置編譯環境
?可以用export來配置,也可以用編寫Makefile的方法。這里采用Makefile。
?編寫Makefile&:
INCL?=?-I/usr/local/include
CFLAGS?=?-pipe?-O2?-fno-strength-reduce
LFLAGS?=?/usr/local/lib/libjrtp.a?-L/usr/X11R6/lib
LIBS?=?-LX11?-LXext?/usr/local/lib/libjrtp.a
CC?=?arm-linux-g++
main:main.o
?$(CC)?$(LFLAGS)?$(INCL)?-o?main?main.o?$(LIBS)
main.o:main.cpp
clean:
?rm?-f?main
?rm?-f?*.o
?
.SUFFIXES:.cpp
.cpp.o:
?$(CC)?-c?$(CFLAGS)?$(INCL)?-o?$@?$<?????????/*??$@表示目標的完整名字??????*/
??????????/*?$<表示第一個依賴文件的名字?*/
?b、編譯
?假設發送和接收程序分別放在/tmp/send和/tmp/receive目錄下
?#cd?/tmp/send
?#make
?#cd?/tmp/receive
?#make
四、易出錯誤及注意問題
?1、找不到一些標準的最?基本的一些頭文件。
??主要是因為Toolchain路徑沒安裝對,要?嚴格按照步驟安裝。
?2、找不到使用的jrtplib庫中的一些頭文件。
??在?jrtplib的安裝目錄下,include路徑下不能再有別的目錄。
?3、recieve函數接收數據包不能正確提出所要數據。
??由于每一個RTP數據報都由頭部(Header)和負載(Payload)兩個部分組成,若使用getrawdata()是返回整個數據包的數據,包含傳輸媒體的類型、格式、序列號、時間戳以及是否有附加數據等信息。getpayload()函數是返回所發送的數據。兩者一定要分清。
?4、設置RECEIVEMODE_ACCEPTSOME 接收模式后,運行程序接收端不能接包。
??IP地址格式出了問題。iner_addr()與ntohl()函數要用對,否則參數傳不進去,接受列表中無值,當然接收不了數據包。
?5、編譯通過,但測試時接收端不能接收到數據。
??可能是接收機防火墻未關閉。運行:
??#iptables?-F
??也可能是IP地址沒有設置好。運行:
??#ifocnfig?eth0??*.*.*.*??netmask?*.*.*.*
?6、使用jrtolib庫時,在程序中include?后最好加上庫所在的路徑。
五、程序
send:
#include?<stdio.h>
#include?<string.h>
#include?"rtpsession.h"
//?錯誤處理函數
void?checkerror(int?err)
{
??if?(err?<?0)?{
????char*?errstr?=?RTPGetErrorString(err);
????printf("Error:%s\\n",?errstr);
????exit(-1);
??}
}
int?main(int?argc,?char**?argv)
{
??RTPSession?sess;
??unsigned?long?destip;
??int?destport;
??int?portbase?=?6000;
??int?status,?index;
??char?buffer[128];
??if?(argc?!=?3)?{
????printf("Usage:?./sender?destip?destport\\n");
????return?-1;
??}
??//?獲得接收端的IP地址和端口號
??destip?=?inet_addr(argv[1]);
??if?(destip?==?INADDR_NONE)?{
????printf("Bad?IP?address?specified.\\n");
????return?-1;
??}
??destip?=?ntohl(destip);
??destport?=?atoi(argv[2]);
??//?創建RTP會話
??status?=?sess.Create(portbase);
??checkerror(status);
??//?指定RTP數據接收端
??status?=?sess.AddDestination(destip,?destport);
??checkerror(status);
??//?設置RTP會話默認參數
??sess.SetDefaultPayloadType(0);
??sess.SetDefaultMark(false);
??sess.SetDefaultTimeStampIncrement(10);
??//?發送流媒體數據
??index?=?1;
??do?{
????sprintf(buffer,?"%d:?RTP?packet",?index?++);
????sess.SendPacket(buffer,?strlen(buffer));
????printf("Send?packet?!\\n");
??}?while(1);
??return?0;
}
receive:
#include?<stdio.h>
#include?"rtpsession.h"
#include?"rtppacket.h"
//?錯誤處理函數
void?checkerror(int?err)
{
??if?(err?<?0)?{
????char*?errstr?=?RTPGetErrorString(err);
????printf("Error:%s\\n",?errstr);
????exit(-1);
??}
}
int?main(int?argc,?char**?argv)
{
??RTPSession?sess;
??int?localport,portbase;
??int?status;
??unsigned?long?remoteIP;
??if?(argc?!=?4)?{
????printf("Usage:?./sender?localport\\n");
????return?-1;
??}
???//?獲得用戶指定的端口號
???
??remoteIP?=?inet_addr(argv[1]);
??localport?=?atoi(argv[2]);
??portbase?=?atoi(argv[3]);
??//?創建RTP會話
??status?=?sess.Create(localport);
??checkerror(status);
??
??//RTPHeader?*rtphdr;
??unsigned?long?timestamp1;
??unsigned?char?*?RawData;
??unsigned?char?temp[30];
??int?lengh?,i;
??bool?allports?=?1;
??
??sess.AddToAcceptList(remoteIP,?allports,portbase);
??
?????do?{
?//設置接收模式
????????sess.SetReceiveMode(RECEIVEMODE_ACCEPTSOME);
???sess.AddToAcceptList(remoteIP,?allports,portbase);
????//?接受RTP數據
????status?=?sess.PollData();
????
?//?檢索RTP數據源
????if?(sess.GotoFirstSourceWithData())?{
??????do?{
????????
????????RTPPacket*?packet;
????????//?獲取RTP數據報
????????while?((packet?=?sess.GetNextPacket())?!=?NULL)?{
??????????printf("Got?packet?!\n");
???timestamp1?=?packet->GetTimeStamp();
???lengh=packet->GetPayloadLength();
???RawData=packet->GetPayload();
???
???for(i=0;i<lengh;i++){
??????temp[i]=RawData[i];
??printf("%c",temp[i]);
???}
???temp[i]='\0';
???printf("??timestamp:?%d?lengh=%d?data:%s\n",timestamp1,lengh,&temp);
??????????//?刪除RTP數據報
???
??????????delete?packet;
????????}
??????}?while?(sess.GotoNextSourceWithData());
????}
??}?while(1);
??return?0;
}