天天看點

jrtplib介紹

程式流程

發送:獲得接收端的 IP 位址和端口号        建立 RTP 會話        指定 RTP 資料接收端 設定 RTP 會話 預設參數   發送流媒體資料

接收:獲得使用者指定的端口号  建立RTP會話  設定接收模式  接受RTP資料  檢索RTP資料源  擷取RTP資料報 删除RTP資料報

1.初始化

I、在使用 JRTPLIB 進行實時流媒體資料傳輸之前,首先應該生成 RTPSession 類的一個執行個體來表示此次 RTP會話,然後調用 Create() 方法來對其進行初始化操作。RTPSession 類的 Create() 方法隻有一個參數,用來指明此次 RTP 會話所采用的端口号。

RTPSession sess;  
sess.Create(5000);
           

JRTPLIB-3.11中已經修改了Create(prot)方法。新的Create方法被修改為Create(sessparams,&transparams)。其中的兩個參數需要如下先定義:

RTPUDPv4TransmissionParams transparams;
RTPSessionParams sessparams;

sessparams.SetOwnTimestampUnit(1.0/8000.0);/*設定時間戳,1/8000表示1秒鐘采樣8000次,即錄音時的8KHz*/

sessparams.SetAcceptOwnPackets(true);

transparams.SetPortbase(portbase);/*本地通訊端口*/
           

II、設定恰當的時戳單元,是 RTP 會話初始化過程所要進行的另外一項重要工作,這是通過調用 RTPSession類的 SetTimestampUnit() 方法來實作的,前面已經提過。

2.資料發送

I、當 RTP 會話成功建立起來之後,接下去就可以開始進行流媒體資料的實時傳輸了。首先需要設定好資料發送的目标位址,RTP 協定允許同一會話存在多個目标位址,這可以通過調用 RTPSession 類的AddDestination()、DeleteDestination() 和 ClearDestinations() 方法來完成。例如,下面的語句表示的是讓 RTP 會話将資料發送到本地主機的 6000 端口:

unsigned long addr = ntohl(inet_addr("127.0.0.1")); 
sess.AddDestination(addr, 6000);
           

II、目标位址全部指定之後,接着就可以調用 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);
           

在真正的語音傳輸中,上面的buffer就是我們錄音時所得到的buffer。使用上面的函數可以簡單的發送,但無法真正的實作RTP傳輸,我們需要調用另一個接口:sess.SendPacket((void *)buffer,sizeof(buffer),0,false,8000);詳細的說明可以檢視JRTPLIB的說明文檔。

3.資料接收

對于流媒體資料的接收端,首先需要調用 RTPSession 類的 PollData() 方法來接收發送過來的 RTP 或者RTCP 資料報。

JRTPLIB-3.11中修改PollData()方法為Poll(),使用都一樣

由于同一個 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()); 
 }
           

完整的代碼中,首先需調用Poll()方法接收RTP資料報,然後在BeginDataAccess()和EndDataAccess()之間進行資料接收的操作。此時,我們設定程式一直do-while等待并處理資料

do{

#ifndef RTP_SUPPORT_THREAD
                error_status = sess_client.Poll();
                checkerror(error_status);
#endif // RTP_SUPPORT_THREAD
                sess_client.BeginDataAccess();

                // check incoming packets
                if (sess_client.GotoFirstSourceWithData())
                {
                         printf("Begin play/n");
                        do
                        {
                                RTPPacket *pack;

                                while ((pack = sess_client.GetNextPacket()) != NULL)
                                {
                                        // You can examine the data here
                                        printf("Got packet !/n");
                                        timestamp1 = pack->GetTimestamp();
                                        lengh=pack->GetPayloadLength();
                                        RawData=pack->GetPayloadData();   //得到資料

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);
           

說明 : jrtp-3.x 中有兩種資料接收方式:

第一種是用 jthread 庫提供的線程自動在背景執行對資料的接收。

第二種是使用者自己調用 RTPSession 中的 Poll 方法。

如果采取第一種方法則要安裝 jthread 庫,則安裝 jthread-1.x.tar.gz ,而且 jthread-1.x 必須先與 jrtp-3.x 的安裝。因為在 jrtp-3.x 的 configure 中,會查找系統是否有編譯了 jthread 庫,如果有,那麼編譯的 jrtp 庫會開啟對 jthread 的支援。是以如果先編譯jrtp 在編譯 jthread ,編譯出來的 jrtp 是沒有開啟對 jthread 的支援的。如果采用第二種方法,那麼可以不用編譯 jthread 庫,而直接編譯 jrtp 庫。

可以加入環境變量 export LD_LIBRARY_PATH=/XXX/lib,避免将所有lib都放入/usr下

./ example