1 從RTPSession類開始session
全部的類和函數都是jrtplib名字空間的一部分,爲了簡化代碼,咱們聲明咱們使用的是以下的名字空間:dom
using namespace jrtplib;函數
爲了使用RTP,首先要建立一個RTPSession對象.這個構造函數接受兩個參數:一個RTPRandom類的實例,一個RTPMemoryManager類的實例.如今,咱們使用最簡單的默認的設置,以下:ui
RTPSession session;
1.1 建立Sessionspa
調用帶有三個參數的Create函數.線程
參數1指針
RTPSessionParams類型.指定這個session的大概的選項.這個類裏面的一個參數必需要設置好,不然session就會建立失敗.就是你要發送的數據的時間戳的單位,這個參數能夠用一個時間段內的採樣數去除以這個時間段的長度.所以,假設咱們要發送一個8000Hz的語音數據,能夠用以下的代碼:code
RTPSessionParams sessionParams; sessionParams.SetOwnTimestampUnit(1.0/8000.0);
參數2對象
這個參數就真的取決於你想要一塊兒用的RTP profile.繼承
它是一個指向RTPTransmissionParams實例的指針,而且爲傳輸部分描述參數.
參數3
選擇要使用的傳輸組件,默認狀況下,使用UDP經過IPV4的transmitter,而且對於這個特定的transmitter,那麼參數2中的傳輸參數應該設爲RTPUDPv4TransmissionParams類型的.所以,假設咱們使用8000端口,咱們可使用以下的代碼:
RTPUDPv4TransmissionParams transparams; transparams.SetPortbase(8000);
如今咱們能夠調用RTPSession類的Create成員函數,代碼以下:
int status = session.Create(sessionparams,&transparams); if (status < 0) { std::cerr << RTPGetErrorString(status) << std::endl; exit(-1); }
若是Create函數出錯,那麼返回一個負值,它指出出錯了.能夠用RTPGetErrorString()函數來得到.
當session建立成功了,此時,要設置RTP和RTCP數據要發送的目的地.這是經過調用RTPSession的成員函數AddDestination來實現的.這個函數帶一個RTPAddress類型的參數,RTPAddress是一個抽象類,對於UDP經過IPV4的transmitter,真正的子類是RTPIPv4Address.假設把數據向運行在9000端口的進程發送,那麼代碼以下:
uint8_t localip[]={127,0,0,1}; RTPIPv4Address addr(localip,9000); status = session.AddDestination(addr); if (status < 0) { std::cerr << RTPGetErrorString(status) << std::endl; exit(-1); }
若是這個庫是用JThread支持編譯的,那麼收到的數據是在後臺處理的.如下兩種狀況:
A JThread支持沒有在編譯時使能
B 在session參數中指定不使用poll線程
下,必須使用RTPSession的成員函數Poll來處理到達的數據而且必要時發送RTCP數據.
如今,咱們先假定咱們使能了poll線程.
假設在一分鐘內,咱們想要發送包含20ms(160個採樣)的silence,而且咱們想要當一個從其餘地方來的包被接收的時候可以被指出來.一樣假定咱們有L8數據,而且要使用負荷類型爲96.首先,咱們將要設定一些默認值:
session.SetDefaultPayloadType(96); session.SetDefaultMark(false); session.SetDefaultTimestampIncrement(160);
下一步,咱們要建立包含160個silence採樣的緩衝區,而且建立一個表示20ms的RTPTime實例.咱們也保存當前時間,這樣咱們能夠知道什麼時候1分鐘已經走完了.
uint8_t silencebuffer[160]; for (int i = 0 ; i < 160 ; i++) silencebuffer[i] = 128; RTPTime delay(0.020); RTPTime starttime = RTPTime::CurrentTime();
下一步,是主循環.這個循環中,要發送一個包含160字節的負載數據.而後,數據處理開始進行,這個稍後闡述.最終,咱們等待20ms並檢測是否60s已通過去.
bool done = false; while (!done) { status = session.SendPacket(silencebuffer,160); if (status < 0) { std::cerr << RTPGetErrorString(status) << std::endl; exit(-1); } // // Inspect incoming data here // RTPTime::Wait(delay); RTPTime t = RTPTime::CurrentTime(); t -= starttime; if (t > RTPTime(60.0)) done = true; }
關於會話參與者的信息,以及得到包等的信息,都必須在調用成員函數BeginDataAccess和EndDataAccess之間完成.這樣能夠保證後臺線程不會在你在訪問數據的時候,同時改變你的數據.咱們逐個訪問會話的參與者經過GotoFirstSource和GotoNextSource成員函數.從當前選中的參與者中取得數據包,能夠經過成員函數GetNextPacket,這個函數能夠返回一個指向RTPPacket類的實例的指針.當你再也不須要這個packet的時候,你要delete它.處理到達的數據的過程能夠以下:
session.BeginDataAccess(); if (session.GotoFirstSource()) { do { RTPPacket *packet; while ((packet = session.GetNextPacket()) != 0) { std::cout << "Got packet with extended sequence number " << packet->GetExtendedSequenceNumber() << " from SSRC " << packet->GetSSRC() << std::endl; session.DeletePacket(packet); } } while (session.GotoNextSource()); } session.EndDataAccess();
當前選中的源的信息能夠經過GetCurrentSourceInfo成員函數RTPSession類的來獲取.這個函數返回一個指針指向RTPSourceData的指針,這個對象包括了全部的關於source的信息:從那個源來的sender reports,receiver reports,SDES信息等等.
當主循環結束的時候,咱們發送一個BYE包來告訴其餘參與者咱們的分離,而且清理RTPSession類.一樣咱們須要等最多10s來讓BYE包被髮送出去,不然,咱們只是簡單地離開會話,而沒有發送BYE包.
delay = RTPTime(10.0); session.BYEDestroy(delay,"Time's up",9);
2 錯誤碼
除非特意指定的,不然都是0或者正返回值表示成功,負值表示出錯.能夠用RTPGetErrorString獲取.
3 內存管理
能夠經過繼承RTPMemoryManager來寫本身的內存管理類.下面是一個簡化的實現代碼:
class MyMemoryManager : public RTPMemoryManager { public: MyMemoryManager() { } ~MyMemoryManager() { } void *AllocateBuffer(size_t numbytes, int memtype) { return malloc(numbytes); } void FreeBuffer(void *p) { free(p); } };
在RTPSession類的構造函數中,能夠指定想要使用這個內存管理:
MyMemoryManager mgr; RTPSession session(0, &mgr);
此時,全部的內存分配和聲明均可以經過使用mgr的AllocateBuffer和FreeBuffer來完成.