jrtplib介绍
程序流程
發(fā)送:獲得接收端的 IP 地址和端口號(hào)??????? 創(chuàng)建 RTP 會(huì)話??????? 指定 RTP 數(shù)據(jù)接收端 設(shè)置 RTP 會(huì)話 默認(rèn)參數(shù)?? 發(fā)送流媒體數(shù)據(jù)
接收:獲得用戶指定的端口號(hào)? 創(chuàng)建RTP會(huì)話? 設(shè)置接收模式? 接受RTP數(shù)據(jù)? 檢索RTP數(shù)據(jù)源? 獲取RTP數(shù)據(jù)報(bào) 刪除RTP數(shù)據(jù)報(bào)
1.初始化
I、在使用 JRTPLIB 進(jìn)行實(shí)時(shí)流媒體數(shù)據(jù)傳輸之前,首先應(yīng)該生成 RTPSession 類的一個(gè)實(shí)例來(lái)表示此次 RTP會(huì)話,然后調(diào)用 Create() 方法來(lái)對(duì)其進(jìn)行初始化操作。RTPSession 類的 Create() 方法只有一個(gè)參數(shù),用來(lái)指明此次 RTP 會(huì)話所采用的端口號(hào)。
RTPSession sess;? sess.Create(5000);JRTPLIB-3.11中已經(jīng)修改了Create(prot)方法。新的Create方法被修改為Create(sessparams,&transparams)。其中的兩個(gè)參數(shù)需要如下先定義:
RTPUDPv4TransmissionParams transparams; RTPSessionParams sessparams;sessparams.SetOwnTimestampUnit(1.0/8000.0);/*設(shè)置時(shí)間戳,1/8000表示1秒鐘采樣8000次,即錄音時(shí)的8KHz*/sessparams.SetAcceptOwnPackets(true);transparams.SetPortbase(portbase);/*本地通訊端口*/II、設(shè)置恰當(dāng)?shù)臅r(shí)戳單元,是 RTP 會(huì)話初始化過(guò)程所要進(jìn)行的另外一項(xiàng)重要工作,這是通過(guò)調(diào)用 RTPSession類的 SetTimestampUnit() 方法來(lái)實(shí)現(xiàn)的,前面已經(jīng)提過(guò)。
?
2.數(shù)據(jù)發(fā)送
I、當(dāng) RTP 會(huì)話成功建立起來(lái)之后,接下去就可以開始進(jìn)行流媒體數(shù)據(jù)的實(shí)時(shí)傳輸了。首先需要設(shè)置好數(shù)據(jù)發(fā)送的目標(biāo)地址,RTP 協(xié)議允許同一會(huì)話存在多個(gè)目標(biāo)地址,這可以通過(guò)調(diào)用 RTPSession 類的AddDestination()、DeleteDestination() 和 ClearDestinations() 方法來(lái)完成。例如,下面的語(yǔ)句表示的是讓 RTP 會(huì)話將數(shù)據(jù)發(fā)送到本地主機(jī)的 6000 端口:
unsigned long addr = ntohl(inet_addr("127.0.0.1"));? sess.AddDestination(addr, 6000);II、目標(biāo)地址全部指定之后,接著就可以調(diào)用 RTPSession 類的 SendPacket() 方法,向所有的目標(biāo)地址發(fā)送流媒體數(shù)據(jù)。SendPacket() 是 RTPSession 類提供的一個(gè)重載函數(shù)對(duì)于同一個(gè) RTP 會(huì)話來(lái)講,負(fù)載類型、標(biāo)識(shí)和時(shí)戳增量通常來(lái)講都是相同的,JRTPLIB 允許將它們?cè)O(shè)置為會(huì)話的默認(rèn)參數(shù),這是通過(guò)調(diào)用 RTPSession 類的 SetDefaultPayloadType()、SetDefaultMark() 和SetDefaultTimeStampIncrement() 方法來(lái)完成的。為 RTP 會(huì)話設(shè)置這些默認(rèn)參數(shù)的好處是可以簡(jiǎn)化數(shù)據(jù)的發(fā)送,例如,如果為 RTP 會(huì)話設(shè)置了默認(rèn)參數(shù):
sess.SetDefaultPayloadType(0); sess.SetDefaultMark(false);?? sess.SetDefaultTimeStampIncrement(10);之后在進(jìn)行數(shù)據(jù)發(fā)送時(shí)只需指明要發(fā)送的數(shù)據(jù)及其長(zhǎng)度就可以了:
sess.SendPacket(buffer, 5);在真正的語(yǔ)音傳輸中,上面的buffer就是我們錄音時(shí)所得到的buffer。使用上面的函數(shù)可以簡(jiǎn)單的發(fā)送,但無(wú)法真正的實(shí)現(xiàn)RTP傳輸,我們需要調(diào)用另一個(gè)接口:sess.SendPacket((void *)buffer,sizeof(buffer),0,false,8000);詳細(xì)的說(shuō)明可以查看JRTPLIB的說(shuō)明文檔。
?
3.數(shù)據(jù)接收
對(duì)于流媒體數(shù)據(jù)的接收端,首先需要調(diào)用 RTPSession 類的 PollData() 方法來(lái)接收發(fā)送過(guò)來(lái)的 RTP 或者RTCP 數(shù)據(jù)報(bào)。
JRTPLIB-3.11中修改PollData()方法為Poll(),使用都一樣
由于同一個(gè) RTP 會(huì)話中允許有多個(gè)參與者(源),你既可以通過(guò)調(diào)用 RTPSession 類的
GotoFirstSource() 和 GotoNextSource() 方法來(lái)遍歷所有的源,也可以通過(guò)調(diào)用 RTPSession 類的GotoFirstSourceWithData() 和 GotoNextSourceWithData() 方法來(lái)遍歷那些攜帶有數(shù)據(jù)的源。在從 RTP 會(huì)話中檢測(cè)出有效的數(shù)據(jù)源之后,接下去就可以調(diào)用 RTPSession 類的 GetNextPacket() 方法從中抽取 RTP 數(shù)據(jù)報(bào),當(dāng)接收到的 RTP 數(shù)據(jù)報(bào)處理完之后,一定要記得及時(shí)釋放。
JRTPLIB 為 RTP 數(shù)據(jù)報(bào)定義了三種接收模式,其中每種接收模式都具體規(guī)定了哪些到達(dá)的 RTP 數(shù)據(jù)報(bào)將會(huì)被接受,而哪些到達(dá)的 RTP 數(shù)據(jù)報(bào)將會(huì)被拒絕。通過(guò)調(diào)用 RTPSession 類的 SetReceiveMode() 方法可以設(shè)置下列這些接收模式:?
RECEIVEMODE_ALL 缺省的接收模式,所有到達(dá)的 RTP 數(shù)據(jù)報(bào)都將被接受;?
RECEIVEMODE_IGNORESOME 除了某些特定的發(fā)送者之外,所有到達(dá)的 RTP 數(shù)據(jù)報(bào)都將被接受,而被拒絕的發(fā)送者列表可以通過(guò)調(diào)用 AddToIgnoreList()、DeleteFromIgnoreList() 和 ClearIgnoreList() 方法來(lái)進(jìn)行設(shè)置;?
RECEIVEMODE_ACCEPTSOME 除了某些特定的發(fā)送者之外,所有到達(dá)的 RTP 數(shù)據(jù)報(bào)都將被拒絕,而被接受的發(fā)送者列表可以通過(guò)調(diào)用 AddToAcceptList ()、DeleteFromAcceptList 和 ClearAcceptList () 方法來(lái)進(jìn)行設(shè)置。 下面是采用第三種接收模式的程序示例。
完整的代碼中,首先需調(diào)用Poll()方法接收RTP數(shù)據(jù)報(bào),然后在BeginDataAccess()和EndDataAccess()之間進(jìn)行數(shù)據(jù)接收的操作。此時(shí),我們?cè)O(shè)定程序一直do-while等待并處理數(shù)據(jù)
do{#ifndef RTP_SUPPORT_THREADerror_status = sess_client.Poll();checkerror(error_status); #endif // RTP_SUPPORT_THREADsess_client.BeginDataAccess();// check incoming packetsif (sess_client.GotoFirstSourceWithData()){printf("Begin play/n");do{RTPPacket *pack;while ((pack = sess_client.GetNextPacket()) != NULL){// You can examine the data hereprintf("Got packet !/n");timestamp1 = pack->GetTimestamp();lengh=pack->GetPayloadLength();RawData=pack->GetPayloadData();?? //得到數(shù)據(jù)printf("? timestamp: %dlengh=%d/n",timestamp1,lengh);int fd = open("/dev/dsp", O_RDWR);int status = write(fd, RawData,lengh );printf("Play bytes:%d/n",status);if (status != lengh)perror("wrote wrong number of bytes");status = ioctl(fd, SOUND_PCM_SYNC, 0);if (status == -1)perror("SOUND_PCM_SYNC ioctl failed");printf("Play end/n");close(fd);sess_client.DeletePacket(pack);}} while (sess_client.GotoNextSourceWithData());//return 0;}sess_client.EndDataAccess();}while(1);說(shuō)明 :?jrtp-3.x?中有兩種數(shù)據(jù)接收方式:
第一種是用 jthread 庫(kù)提供的線程自動(dòng)在后臺(tái)執(zhí)行對(duì)數(shù)據(jù)的接收。
第二種是用戶自己調(diào)用 RTPSession 中的 Poll 方法。
如果采取第一種方法則要安裝 jthread 庫(kù),則安裝 jthread-1.x.tar.gz ,而且 jthread-1.x 必須先與 jrtp-3.x?的安裝。因?yàn)樵?jrtp-3.x 的 configure 中,會(huì)查找系統(tǒng)是否有編譯了 jthread 庫(kù),如果有,那么編譯的 jrtp 庫(kù)會(huì)開啟對(duì) jthread 的支持。因此如果先編譯jrtp 在編譯 jthread ,編譯出來(lái)的 jrtp 是沒有開啟對(duì) jthread 的支持的。如果采用第二種方法,那么可以不用編譯 jthread 庫(kù),而直接編譯 jrtp 庫(kù)。
?
可以加入環(huán)境變量 export LD_LIBRARY_PATH=/XXX/lib,避免將所有l(wèi)ib都放入/usr下
./ example
總結(jié)
- 上一篇: 黑马程序员_毕向东_Java基础视频教程
- 下一篇: java集合类习题_Java集合练习