流媒體協議之JRTPLIB的使用20170919


主要介紹JRTPLIB 2.x系列和3.x系列兩種版本,它們的區別是2.x系列代碼量少使用簡單,但是只支持RFC 1889不支持RFC 3550,3.x支持RFC 3550,但代碼量稍多,以及使用也稍顯復雜。

一、JRTPLIB的編譯及安裝

1. JRTPLIB-2.X系列版本:

1.1.下載

下載鏈接:http://research.edm.uhasselt.be/jori/jrtplib/jrtplib_old.html

或我的github: https://github.com/fengweiyu/JRTPLIB

1.2.解壓

Linux下使用命令:tar –xvf  jrtplib-2.9.tar.bz2

1.3.編譯及安裝

分別執行:

./configure

make

make install

1.4查看編譯及安裝的結果

查看編譯完的文件

  1. /usr/local/lib 目錄下放置着編譯的jrtplib的庫,主要的是libjrtp.a  靜態庫, libjrtp.so.2.9動態庫,libjrtp.so鏈接

  2. /usr/local/incude  多了兩個文件夾:jrtplib

 

2. JRTPLIB-3.X系列版本:

2.1.下載三個文件

I、jrtplib:http://research.edm.uhasselt.be/jori/page/CS/Jrtplib.html

II、jthread:http://research.edm.uhasselt.be/jori/page/CS/Jthread.html

III、cmake:http://www.cmake.org

或我的github: https://github.com/fengweiyu/JRTPLIB

2.2.解壓

把下載的文件全部放到Linux下並解壓:tar –xvf  XXX.tar.bz2

2.3.編譯及安裝

I、cmake:

進入cmake目錄:分別輸入命令

./bootstrap         

make

make install

make -version查看安裝是否成功

II、jthread和jrtplib:

jthread和jrtplib是配合使用的,jthread負責線程調用函數和mutex,所以要先編譯jthread,因為編譯jrtplib時會用到jthread的編譯好的頭文件。

a.進入jthread目錄分別執行下列命令

    cmake  CMakeLists.txt   生成makefile

    make

    make install

b.進入jrtplib目錄,執行命令同上。

2.4查看編譯及安裝的結果

查看編譯完的文件

  1. /usr/local/lib 目錄下放置着編譯的jrtplib和jthread的庫,主要的是libjrtp.a  libjthread.a靜態庫, libjrtp.so.3.9.1 libjthread.so.1.3.1動態庫,libjrtp.so libjthread.so 鏈接

  2. /usr/local/incude  多了兩個文件夾:jrtplib3  jthread

 

二、基於JRTPLIB編程

1. JRTPLIB-2.X系列版本:

1.1.初始化

在使用JRTPLIB進行實時流媒體數據傳輸之前,首先應該生成RTPSession類的一個實例來表示此次RTP會話,然后調用Create()方法來對其進行初始化操作。RTPSession類的Create()方法只有一個參數,用來指明此次RTP會話所采用的端口號。清單1給出了一個最簡單的初始化框架,它只是完成了RTP會話的初始化工作,還不具備任何實際的功能。

代碼清單1initial.cpp

#include "rtpsession.h"

 

int main(void)

{

        RTPSession sess;

        sess.Create(5000);

        return 0;

}

如果RTP會話創建過程失敗,Create()方法將會返回一個負數,通過它雖然可以很容易地判斷出函數調用究竟是成功的還是失敗的,但卻很難明白出錯的原因到底什么。JRTPLIB采用了統一的錯誤處理機制,它提供的所有函數如果返回負數就表明出現了某種形式的錯誤,而具體的出錯信息則可以通過調用 RTPGetErrorString()函數得到。RTPGetErrorString()函數將錯誤代碼作為參數傳入,然后返回該錯誤代碼所對應的錯誤信息。清單2給出了一個更加完整的初始化框架,它可以對RTP會話初始化過程中所產生的錯誤進行更好的處理:

代碼清單2framework.cpp

#include <stdio.h>

#include "rtpsession.h"

 

int main(void)

{

  RTPSession sess;

  int status;

  char* msg;

 

  sess.Create(6000);

  msg = RTPGetErrorString(status);

  printf("Error String: %s\\n", msg);

  return 0;

}

設置恰當的時戳單元,是RTP會話初始化過程所要進行的另外一項重要工作,這是通過調用RTPSession類的 SetTimestampUnit()方法來實現的,該方法同樣也只有一個參數,表示的是以秒為單元的時戳單元。例如,當使用RTP會話傳輸8000Hz 采樣的音頻數據時,由於時戳每秒鍾將遞增8000,所以時戳單元相應地應該被設置成1/8000:

sess.SetTimestampUnit(1.0/8000.0);

 

1.2.數據發送

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

unsigned long addr = ntohl(inet_addr("127.0.0.1"));

sess.AddDestination(addr, 6000);

目標地址全部指定之后,接着就可以調用RTPSession類的SendPacket()方法,向所有的目標地址發送流媒體數據。SendPacket()是RTPSession類提供的一個重載函數,它具有下列多種形式:

int SendPacket(void *data,int len)

int SendPacket(void *data,int len,unsigned char pt,bool mark,unsigned long timestampinc)

int SendPacket(void *data,int len,unsigned short hdrextID,void *hdrextdata,int numhdrextwords)

int SendPacket(void *data,int len,unsigned char pt,bool mark,unsigned long timestampinc,

                               unsigned short hdrextID,void *hdrextdata,int numhdrextwords)

SendPacket()最典型的用法是類似於下面的語句,其中第一個參數是要被發送的數據,而第二個參數則指明將要發送數據的長度,再往后依次是RTP負載類型、標識和時戳增量。

sess.SendPacket(buffer, 5, 0, false, 10);

對於同一個RTP會話來講,負載類型、標識和時戳增量通常來講都是相同的,JRTPLIB允許將它們設置為會話的默認參數,這是通過調用 RTPSession類的SetDefaultPayloadType()、SetDefaultMark()和 SetDefaultTimeStampIncrement()方法來完成的。為RTP會話設置這些默認參數的好處是可以簡化數據的發送,例如,如果為 RTP會話設置了默認參數:

sess.SetDefaultPayloadType(0);

sess.SetDefaultMark(false);

sess.SetDefaultTimeStampIncrement(10);

之后在進行數據發送時只需指明要發送的數據及其長度就可以了:

sess.SendPacket(buffer, 5);

 

1.3.數據接收

對於流媒體數據的接收端,首先需要調用RTPSession類的PollData()方法來接收發送過來的RTP或者 RTCP數據報。由於同一個RTP會話中允許有多個參與者(源),你既可以通過調用RTPSession類的GotoFirstSource()和 GotoNextSource()方法來遍歷所有的源,也可以通過調用RTPSession類的GotoFirstSourceWithData()和 GotoNextSourceWithData()方法來遍歷那些攜帶有數據的源。在從RTP會話中檢測出有效的數據源之后,接下去就可以調用 RTPSession類的GetNextPacket()方法從中抽取RTP數據報,當接收到的RTP數據報處理完之后,一定要記得及時釋放。下面的代碼示范了該如何對接收到的RTP數據報進行處理:

if (sess.GotoFirstSourceWithData()) {

  do {

    RTPPacket *pack;                                

    pack = sess.GetNextPacket();                                    

    // 處理接收到的數據

    delete pack;

  } while (sess.GotoNextSourceWithData());

}

JRTPLIB為RTP數據報定義了三種接收模式,其中每種接收模式都具體規定了哪些到達的RTP數據報將會被接受,而哪些到達的RTP數據報將會被拒絕。通過調用RTPSession類的SetReceiveMode()方法可以設置下列這些接收模式:

  • RECEIVEMODE_ALL  缺省的接收模式,所有到達的RTP數據報都將被接受;
  • RECEIVEMODE_IGNORESOME  除了某些特定的發送者之外,所有到達的RTP數據報都將被接受,而被拒絕的發送者列表可以通過調用AddToIgnoreList()、DeleteFromIgnoreList()和ClearIgnoreList()方法來進行設置;
  • RECEIVEMODE_ACCEPTSOME  除了某些特定的發送者之外,所有到達的RTP數據報都將被拒絕,而被接受的發送者列表可以通過調用AddToAcceptList ()、DeleteFromAcceptList和ClearAcceptList ()方法來進行設置。

 

1.4.控制信息

JRTPLIB 是一個高度封裝后的RTP庫,程序員在使用它時很多時候並不用關心RTCP數據報是如何被發送和接收的,因為這些都可以由JRTPLIB自己來完成。只要 PollData()或者SendPacket()方法被成功調用,JRTPLIB就能夠自動對到達的 RTCP數據報進行處理,並且還會在需要的時候發送RTCP數據報,從而能夠確保整個RTP會話過程的正確性。

 

而另一方面,通過調用RTPSession類提供的SetLocalName()、SetLocalEMail()、 SetLocalLocation()、SetLocalPhone()、SetLocalTool()和SetLocalNote()方法, JRTPLIB又允許程序員對RTP會話的控制信息進行設置。所有這些方法在調用時都帶有兩個參數,其中第一個參數是一個char型的指針,指向將要被設置的數據;而第二個參數則是一個int型的數值,表明該數據中的前面多少個字符將會被使用。例如下面的語句可以被用來設置控制信息中的電子郵件地址:

sess.SetLocalEMail("
xiaowp@linuxgam.comxiaowp@linuxgam.com
 
",19);

在RTP 會話過程中,不是所有的控制信息都需要被發送,通過調用RTPSession類提供的 EnableSendName()、EnableSendEMail()、EnableSendLocation()、EnableSendPhone ()、EnableSendTool()和EnableSendNote()方法,可以為當前RTP會話選擇將被發送的控制信息。

1.5.實際應用

最后通過一個簡單的流媒體發送-接收實例,介紹如何利用JRTPLIB來進行實時流媒體的編程。清單3給出了數據發送端的完整代碼,它負責向用戶指定的IP地址和端口,不斷地發送RTP數據包:

代碼清單3sender.cpp

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

}

 

也可以參考官方自帶的例子,解壓后在examples目錄下。

使用examples目錄下的sample1,

I、編譯:

g++ -rdynamic /usr/local/lib/libjrtp.so.2.9 -o sample1 sample1.cpp

或 g++ -L/usr/local/lib -ljrtp -o sample1 sample1.cpp

 

說明:

a、出現錯誤:undefined reference to jrtplib::RTPGetErrorString(int) ...........................................

解決:這是因為編譯的時候鏈接庫沒有找到所致

所以編譯時添加上鏈接庫:-rdynamic /usr/local/lib/libjrtp.so.2.9或-L/usr/local/lib -ljrtp

b、出現錯誤:rtpsession.h 沒有那個文件或目錄........................

原因:Linux系統默認查找的頭文件在usr/include下面,我們編譯后的頭文件在usr/local/include下面,所以找不到是情有可源的

解決1:直接將usr/local/include下的兩個文件夾復制到/usr/include目錄下

解決2:或者做個軟連接:

       ln -s /usr/local/include/jrtplib   /usr/include/jrtplib 

通過1/2這兩種其實還是解決不了的,因為默認需找的是/usr/include文件夾下的內容,現在相當於放在/usr/include/jrtplib目錄下了,所以要講源程序sample1.cpp中的“”頭文件加上jrtplib/    

或者,簡單點:直接在編譯的時候指定,即:-I/usr/local/include/jrtplib

 

II、執行:

export LD_LIBRARY_PATH=/usr/local/lib

./sample1

說明:

a、LD_LIBRARY_PATH 這個環境變量是大家最為熟悉的,它告訴loader:在哪些目錄中可以找到共享庫。可以設置多個搜索目錄,這些目錄之間用冒號分隔開。export LD_LIBRARY_PATH=/usr/local/lib,然后再運行編譯,即可通過。這種方法只是暫時修改路徑,在重啟shell后會失效。或者是配置在環境變量文件/etc/profile中,重啟或者source /etc/profile 生效,source 只在本控制台生效。

b、永久生效的方法為修改動態鏈接庫配置文件/etc/ld.so.conf,或者在/etc/ld.so.conf.d里創建一個新文件,並把需要的目錄加到這個文件里。具體方法如下:(說明:這種修改動態鏈接庫配置的方式需要使用超級用戶權限,不然沒有對共享庫配置文件的寫權限)

#cd /etc/ld.so.conf.d

#vim jrtplib在編輯環境下加入/usr/local/lib,保存退出。

#ldconfig 重新加載動態鏈接庫。

然后再執行編譯鏈接,成功生成sample1文件。

然后運行./ sample1成功。

 

III、實測JRTPLIB發送出來的數據如下:

RTP:

17:51:01 收到數據:{80 00 C4 96 FE D5 2B CD 4D B9 72 1F 31 32 33 34 35 36 37 38 39 30 }

17:51:23 收到數據:{80 00 C4 97 FE D5 2B D7 4D B9 72 1F 31 32 33 34 35 36 37 38 39 30 }

17:51:25 收到數據:{80 00 C4 98 FE D5 2B E1 4D B9 72 1F 31 32 33 34 35 36 37 38 39 30 }

17:51:26 收到數據:{80 00 C4 99 FE D5 2B EB 4D B9 72 1F 31 32 33 34 35 36 37 38 39 30 }

 

RTCP:

17:51:01 收到數據:{80 C8 00 06 4D B9 72 1F DD 66 2F 0C 05 6D 3B 6C FE EF A0 E5 00 00 00 07 00 00 00 46 81 CA 00 06 4D B9 72 1F 01 11 62 6F 6F 6B 40 62 6F 6F 6B 2D 64 65 73 6B 74 6F 70 00 }

17:51:23 收到數據:{80 C8 00 06 4D B9 72 1F DD 66 2F 22 1B F5 E8 4F FE F2 53 26 00 00 00 08 00 00 00 50 81 CA 00 06 4D B9 72 1F 01 11 62 6F 6F 6B 40 62 6F 6F 6B 2D 64 65 73 6B 74 6F 70 00 }

17:51:26 收到數據:{80 C8 00 06 4D B9 72 1F DD 66 2F 25 09 57 8A 2A FE F2 AE A0 00 00 00 0A 00 00 00 64 81 CA 00 06 4D B9 72 1F 01 11 62 6F 6F 6B 40 62 6F 6F 6B 2D 64 65 73 6B 74 6F 70 00 81 CB 00 01 4D B9 72 1F }

 

2. JRTPLIB-3.X系列版本:

程序流程圖
發送:獲得接收端的 IP 地址和端口號        創建 RTP 會話        指定 RTP 數據接收端 設置 RTP 會話 默認參數   發送流媒體數據
接收:獲得用戶指定的端口號  創建RTP會話  設置接收模式  接受RTP數據  檢索RTP數據源  獲取RTP數據報 刪除RTP數據報

2.1.初始化

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

 

JRTPLIB-3.7中已經修改了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.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的說明文檔。

 

2.3.數據接收

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

 

JRTPLIB-3.7中修改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.2.1.tar.gz ,而且 jthread-1.2.1 必須先與 jrtp-3.7.1 的安裝。因為在 jrtp-3.7.1 的 configure 中,會查找系統是否有編譯了 jthread 庫,如果有,那么編譯的 jrtp 庫會開啟對 jthread 的支持。因此如果先編譯jrtp 在編譯 jthread ,編譯出來的 jrtp 是沒有開啟對 jthread 的支持的。如果采用第二種方法,那么可以不用編譯 jthread 庫,而直接編譯 jrtp 庫。

 

2.4.實際應用

可以參考官方自帶的例子,解壓后在examples目錄下。

使用examples目錄下的example1,

I、編譯:

g++ -rdynamic /usr/local/lib/libjrtp.so.3.11.1 -I/usr/local/include/jrtplib3 -o example example1.cpp

說明:

a、出現錯誤:undefined reference to jrtplib::RTPGetErrorString(int) ...........................................

解決:這是因為編譯的時候鏈接庫沒有找到所致

所以編譯時添加上鏈接庫:-rdynamic /usr/local/lib/libjrtp.so.3.11.1或-l jrtp

b、出現錯誤:rtpsession.h 沒有那個文件或目錄........................

原因:Linux系統默認查找的頭文件在usr/include下面,我們編譯后的頭文件在usr/local/include下面,所以找不到是情有可源的

解決1:直接將usr/local/include下的兩個文件夾復制到/usr/include目錄下

解決2:或者做個軟連接:

       ln -s /usr/local/include/jrtplib3   /usr/include/jrtplib 

       ln -s /usr/local/include/jthread   /usr/include/jthread

通過1/2這兩種其實還是解決不了的,因為默認需找的是/usr/include文件夾下的內容,現在相當於放在/usr/include/jrtplib目錄下了,所以要講源程序example1.cpp中的“”頭文件加上jrtplib/     eg:"jrtplib/rtpsession.h"當有調用jthread頭文件的地方要添加“jthread/”

或者,簡單點:直接在編譯的時候指定,即:-I/usr/local/include/jrtplib3

 

II、執行:

export LD_LIBRARY_PATH=/usr/local/lib

./ example

說明:

a、LD_LIBRARY_PATH 這個環境變量是大家最為熟悉的,它告訴loader:在哪些目錄中可以找到共享庫。可以設置多個搜索目錄,這些目錄之間用冒號分隔開。export LD_LIBRARY_PATH=/usr/local/lib,然后再運行編譯,即可通過。這種方法只是暫時修改路徑,在重啟shell后會失效。或者是配置在環境變量文件/etc/profile中,重啟或者source /etc/profile 生效,source 只在本控制台生效。

b、永久生效的方法為修改動態鏈接庫配置文件/etc/ld.so.conf,或者在/etc/ld.so.conf.d里創建一個新文件,並把需要的目錄加到這個文件里。具體方法如下:(說明:這種修改動態鏈接庫配置的方式需要使用超級用戶權限,不然沒有對共享庫配置文件的寫權限)

#cd /etc/ld.so.conf.d

#vim jrtplib在編輯環境下加入/usr/local/lib,保存退出。

#ldconfig 重新加載動態鏈接庫。

然后再執行編譯鏈接,成功生成example文件。

然后運行./example成功。

 

III、實測JRTPLIB發送出來的數據如下:

RTP:

16:36:22 收到數據:{80 00 89 1F AB 94 D4 1F 18 D7 D0 74 31 32 33 34 35 36 37 38 39 30 }

16:36:23 收到數據:{80 00 89 20 AB 94 D4 29 18 D7 D0 74 31 32 33 34 35 36 37 38 39 30 }

16:36:24 收到數據:{80 00 89 21 AB 94 D4 33 18 D7 D0 74 31 32 33 34 35 36 37 38 39 30 }

16:36:25 收到數據:{80 00 89 22 AB 94 D4 3D 18 D7 D0 74 31 32 33 34 35 36 37 38 39 30 }

16:36:26 收到數據:{80 00 89 23 AB 94 D4 47 18 D7 D0 74 31 32 33 34 35 36 37 38 39 30 }

16:36:27 收到數據:{80 00 89 24 AB 94 D4 51 18 D7 D0 74 31 32 33 34 35 36 37 38 39 30 }

16:36:28 收到數據:{80 00 89 25 AB 94 D4 5B 18 D7 D0 74 31 32 33 34 35 36 37 38 39 30 }

16:36:29 收到數據:{80 00 89 26 AB 94 D4 65 18 D7 D0 74 31 32 33 34 35 36 37 38 39 30 }

16:36:30 收到數據:{80 00 89 27 AB 94 D4 6F 18 D7 D0 74 31 32 33 34 35 36 37 38 39 30 }

16:36:31 收到數據:{80 00 89 28 AB 94 D4 79 18 D7 D0 74 31 32 33 34 35 36 37 38 39 30 }

 

RTCP:

16:36:25 收到數據:{80 C8 00 06 18 D7 D0 74 DD 6A 03 FF 5F 27 DC BD AB 94 D4 3D 00 00 00 04 00 00 00 28 81 CA 00 06 18 D7 D0 74 01 11 62 6F 6F 6B 40 62 6F 6F 6B 2D 64 65 73 6B 74 6F 70 00 }

16:36:31 收到數據:{80 C8 00 06 18 D7 D0 74 DD 6A 04 05 64 AD 03 D9 AB 94 D4 79 00 00 00 0A 00 00 00 64 81 CA 00 06 18 D7 D0 74 01 11 62 6F 6F 6B 40 62 6F 6F 6B 2D 64 65 73 6B 74 6F 70 00 }

16:36:32 收到數據:{80 C8 00 06 18 D7 D0 74 DD 6A 04 06 65 7A 02 FB AB 94 D4 83 00 00 00 0A 00 00 00 64 81 CA 00 06 18 D7 D0 74 01 11 62 6F 6F 6B 40 62 6F 6F 6B 2D 64 65 73 6B 74 6F 70 00 81 CB 00 01 18 D7 D0 74 }

 

三、參考的原文:

使用JRTPLIB

2.9系列版本:

http://blog.csdn.net/pu1030/article/details/7619908

http://research.edm.uhasselt.be/jori/jrtplib/jrtplib_old.html

 

3.11系列版本:

http://research.edm.uhasselt.be/jori/page/CS/Jrtplib.html

http://jrtplib.readthedocs.io/en/stable/

http://blog.csdn.net/zhangjikuan/article/details/27974733

http://blog.sina.com.cn/s/blog_712a04260101c2bm.html

http://blog.csdn.net/asklw/article/details/73555796

http://www.cnblogs.com/einyboy/archive/2012/12/01/2796950.html

http://yebaoshan.blog.163.com/blog/static/204231167201232455825452/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM