天天看點

JRTPLIB使用執行個體

這幾天在看關于JRTPLIB方面的東西。在網上看了不少文章,其中有很大部分使用的JRTPLIB版本在3.0以下。

在網上下載下傳了一個JRTPLIB-3.7的庫,發現裡面的函數接口做了一些修改。現奉上一篇基于JRTPLIB-3.7的網絡

語音傳送執行個體,希望有興趣的朋友一起參詳研究。

                                                                                                               -------chuckGao

第一部分 JRTPLIB的編譯及安裝

 這是必行的一步,在網上可以找到相關的文章,這裡就不啰嗦了。不過可能有些朋友會遇到JRTPLIB

無法正常編譯的情況,出現error: 'memcpy' was not declared in this scope的錯誤。這是由于JRTPLIB編

譯中無法找到memcpy這個函數。在網上有memcpy的patch。内容如下:

diff --git a/src/rtcpcompoundpacketbuilder.cpp b/src/rtcpcompoundpacketbuilder.cpp

index 8172007..8fd4510 100644

--- a/src/rtcpcompoundpacketbuilder.cpp

+++ b/src/rtcpcompoundpacketbuilder.cpp

@@ -30,6 +30,8 @@

 */

+#include <cstring>

+

 #include "rtcpcompoundpacketbuilder.h"

 #include "rtcpsrpacket.h"

 #include "rtcprrpacket.h"

diff --git a/src/rtppacket.cpp b/src/rtppacket.cpp

index b6d5fda..8c516c7 100644

--- a/src/rtppacket.cpp

+++ b/src/rtppacket.cpp

 #include "rtppacket.h"

 #include "rtpstructs.h"

 #include "rtpdefines.h"

+代表添加,-代表删除相應内容

第二部分 JRTPLIB程式設計

下面先轉載一部分網上的指南,紅色标記是JRTPLIB-3.7修了後的使用方法

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

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

RTPUDPv4TransmissionParams transparams;

RTPSessionParams sessparams;

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

sessparams.SetAcceptOwnPackets(true);

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

b、設定恰當的時戳單元,是 RTP 會話初始化過程所要進行的另外一項重要工作,這是通過調用 RTPSession

類的 SetTimestampUnit() 方法來實作的,前面已經提過。

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

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

e、對于流媒體資料的接收端,首先需要調用 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: %d lengh=%d/n",timestamp1,lengh);

                                        // we don't longer need the packet, so

                                        // we'll delete it

                                        //Begin play

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

 (2)程式流程圖

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

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

因為是關于JRTPLIB的文章,是以貼出的錄音和放音代碼不多。需要的朋友可以留下郵箱。

本文轉自einyboy部落格園部落格,原文連結:http://www.cnblogs.com/einyboy/archive/2012/12/01/2796950.html,如需轉載請自行聯系原作者。

繼續閱讀