




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、一、源代碼的構建框架 Ortp是一種開源軟件,實現了 RTP 與 RTCP 協議。首先在RTP中有幾種重要的結構體,第一種比較重要的結構體是payload type,該結構用于指定編碼類型,以及與其相關的時鐘速率、采樣率等一些參數,參見下圖。struct _PayloadTypeint type; /*< one of PAYLOAD_* macros*/int clock_rate; /*< rtp clock rate*/char bits_per_sample;/* in case of continuous audio data */char *zero_pattern;i
2、nt pattern_length;/* other useful information for the application*/int normal_bitrate;/*in bit/s */char *mime_type; /*<actually the submime, ex: pcm, pcma, gsm*/int channels; /*< number of channels of audio */char *recv_fmtp; /* various format parameters for the incoming stream */char *send_fm
3、tp; /* various format parameters for the outgoing stream */int flags;void *user_data; 在代碼中,不同的媒體類型有不同的 payloadtype 結構體與之對應,h263,g729,MPEG4等。 因為每種編碼都有其獨有的特點,而且許多參數也不一樣,所以 RTP 包頭中使用 payload 域標記負載的類型,一方面接收端可以就此判斷負載的類型,從而選擇對應的解碼器進行解碼播放;另一方面,代碼在進行時間戳等方面的計算時可以更加方便一點。所有系統當前支持的payload 類型都被放在一個數組中, 由全局變量 av_
4、profile 這個結構體實例統領。 除了 payloadtype 結構體外,一個更重要的結構體是 rtpsession。該結構體即是一個會話的抽象,與會話相關的各種信息都定義在該結構體上或者能夠通過該結構體找到。要使用oRTP 進行媒體數據的傳輸,需要先創建一個會話,之后所有數據的傳輸都在會話上完成或 基于會話完成。rtpsession結構體的定義如下:struct _RtpSessionRtpSession *next;/* next RtpSession, when the session are enqueued by the scheduler */int mask_pos;/* t
5、he position in the scheduler mask of RtpSession : do not move this field: it is part of the ABI since the session_set macros use it*/struct RtpProfile *profile;int pt;unsigned int ssrc;WaitPoint wp;int telephone_events_pt;/* the payload type used for telephony events */ snd,rcv;unsigned int inc_ssrc
6、_candidate;int inc_same_ssrc_count;int hw_recv_pt; /* recv payload type before jitter buffer */int recv_buf_size;RtpSignalTable on_ssrc_changed;RtpSignalTable on_payload_type_changed;RtpSignalTable on_telephone_event_packet;RtpSignalTable on_telephone_event;RtpSignalTable on_timestamp_jump;RtpSignal
7、Table on_network_error;RtpSignalTable on_rtcp_bye;struct _OList *signal_tables;struct _OList *eventqs;msgb_allocator_t allocator;RtpStream rtp;RtcpStream rtcp;RtpSessionMode mode;struct _RtpScheduler *sched;uint32_t flags;int dscp;int multicast_ttl;int multicast_loopback;void * user_data;/* FIXME: S
8、hould be a table for all session participants. */struct timeval last_recv_time; /* Time of receiving the RTP/RTCP packet. */mblk_t *pending;/* telephony events extension */mblk_t *current_tev;/* the pending telephony events */mblk_t *sd;queue_t contributing_sources;unsigned int lost_packets_test_vec
9、tor;unsigned int interarrival_jitter_test_vector;unsigned int delay_test_vector;float rtt;/*last round trip delay calculated*/OrtpNetworkSimulatorCtx *net_sim_ctx;bool_t symmetric_rtp;bool_t permissive; /*use the permissive algorithm*/bool_t use_connect; /* use connect() on the socket */bool_t ssrc_
10、set;Session 的初始化通過接口 rtp_session_init 完成,外部獲得一個新的 session是通過調用接口rtp_session_new 完成。關于 session 的其他有關配置和獲取信息的操作都可以在文件 rtpsession.c 中找到定義。使用 oRTP 進行數據傳輸時,可以在一個任務上完成多個會話流的接收和發送。這得益于oRTP 中調度模塊的支持。要使用調度模塊,應用需要在進行 oRTP 的初始化時對調度進行初始化,將需要調度管理的會話注冊到調度模塊中,這樣當進行接收和發送操作時,先向調度詢問當前會話是否可以進行發送和接收,如果不能進行收發操作,則處理下一個會話
11、。 這有點類似I/O 接口上的 select 操作。調度模塊使用的數據結構主要為 rtpscheduler,定義如下 :struct _RtpScheduler RtpSession *list;/* list of scheduled sessions*/SessionSetall_sessions; /* mask of scheduled sessions */intall_max;/* the highest pos in the all mask */SessionSet r_sessions;/* mask of sessions that have a recv event */
12、intr_max;SessionSetw_sessions;/* mask of sessions that have a send event */int w_max;SessionSete_sessions;/* mask of session that have error event */inte_max;int max_sessions;/* the number of position in the masks */ /* GMutex *unblock_select_mutex; */ortp_cond_t unblock_select_cond;ortp_mutex_tlock
13、;ortp_thread_t thread;int thread_running;struct _RtpTimer *timer;uint32_t time_; /*number of miliseconds elapsed since the start of the thread */uint32_t timer_inc;/* the timer increment in milisec */;調度結構體中的r/w/e分別代表接收,發送,異常。Avprofile.c文件中定義了一些負載類型。接收的 rtp和 rtcp 包的解析處理函數在文件 rtpparse.c 和 rtcpparse.c
14、 文件 中實現。實現的是將包中的事件包取出放入列隊中。rtpsession_inet.c 文件中定義了數據在網絡中傳輸的過程,利用socket 接口完成了。介紹了socket ,遠程地址,端口的建立等設置。其相關的聲明在rtpsession_priv.h 中定義,Rtpsignaltable.c主要實現一些信號量的初始化,加入一個信號量,以及發射信號量。定義一些回調函數等。rtptimer.c,scheduler.c,sessionset.c等文件實現了調度模塊。 port.c 文件中實現常用的任務(如分配內存)的創建及銷毀,條件變量及互斥鎖,進程間的管道通信機制等。文件utils.c 文件中
15、講述了一些數據結構,講述了一些鏈表的操作。Str_utils.c文件中講述了一些隊列的操作。首先,隊列數據結構由三部分組成:隊列頭、消息塊以及數據塊隊列頭指向消息塊,消息塊之間可以構成雙向鏈表,這是隊列的基本要素。消息塊本身不帶buffer,數據是由專門的數據塊來保存的, 并被消息塊指向。 在發送上層應用的 payload 數據之前,oRTP 會構造一個消息塊,數據指針會指向payload, 這避免了數據拷貝。較低層的接口處理數據時依賴于消息塊結構。接收后的數據從消息塊中拷貝到用戶buffer。接收的 rtp和 rtcp 包的解析處理函數在文件 rtpparse.c 和 rtcpparse.c
16、 文件 中實現。在使用oRTP 提供的 rtp 庫之前,需要先對其進行初始化,這部分的實現在 oRTP.c 文件中。oRTP的初始化主要調用兩個接口:ortp_init 和 ortp_scheduler_init。其中 ortp_init完成 了 payload 的注冊,ortp_scheduler_init完成了調度任務的初始化。寫程序首先你要了解你的程序是干什么,要解決的什么問題,需要那些變量,以及各變量的關系。我們RTP的目的是實現對數據的打包輸出,以及對數據的接收,我們前期的工作就是實現各種初始化,將我們的想要的傳輸的數據,地址信息等通過調用庫函數提供的接口將我們的數據傳入內部,在做這
17、些以前,我們還需要判斷我們的系統參數個數是否正確,同時還要注意數據類型的一致性。一系列的初始化結束后就要進行數據的發送與接收了,這些數據都是要經過緩沖區的,再寫入我們的文件系統的,或者發送出去。整個過程結束后,就是要進行資源的釋放。編程的難點是消息是怎樣交換。二、主要函數介紹rtp_session_init函數原型:void rtp_session_init (RtpSession * session, int mode)函數功能:執行rtp會話的一些必要的初始化工作參數含義:session: rtp會話結構體,含有一些rtp會話的基本信息mode: 傳輸模式,有以下幾種,決定本會話的一些特性
18、。RTP_SESSION_RECVONLY:只進行rtp數據的接收RTP_SESSION_SENDONLY:只進行rtp數據的發送RTP_SESSION_SENDRECV:可以進行rtp數據的接收和發送執行的操作:1) 首先判斷會話是否為空,若不是,則將會話初始化,即清零2) 根據傳輸模式設置標志變量的值,在rtpsession中一共設置了14個標志位3) 隨機產生SSRC和同步源描述信息4) 傳入全局的av_profile,即使用默認的profile配置,profile 包含名字與負載類型,負載類型的確認先要得到庫中的所擁有的負載,再比較是否與我們所傳入的負載相匹配,若是傳回類型號5) 套接
19、字的初始化,包含套接字的文件描述符,套接字大小6) 初始化rtp包緩沖區隊列7) 信號量的初始化,包含了7種信號量,分別為ssrc的變化 ;負載類型的改變;電話事件;電話事件包;時間戳的跳變;網絡錯誤;RTCP結束包。8) 發送負載類型默認設置為0(pcmu音頻),接收負載類型默認設置為-1(未定義)9) 將session的其他成員的值均設置一個默認值。10) 還有抖動的設置,rtcp報告的間隔,job運行等一些設置。rtp_session_new 函數原型:RtpSession *rtp_session_new (int mode)函數功能:建立一個會話該函數很簡單,首先為會話分配一個內存,
20、再調用rtp_session_init()進行會話的初始化。成功則返回一個會話。rtp_session_set_scheduling_mode函數原型:void rtp_session_set_scheduling_mode (RtpSession * session, int yesno)函數功能: RtpScheduler管理多個session的調度和收發的控制,本函數設置是否使用該session調度管理功能。參數含義:session: rtp會話結構體yesno: 是否使用rtp session的系統調度功能說明:如果yesno為1,調用ortp_get_scheduler ()得到一個
21、調度器,將會話添加到調度會話集合中則表明使用系統的session調度管理功能,意味著可以使用以下功能:1) 可以使用session_set_select在多個rtp會話之間進行選擇,根據時間戳判定某個會話是否到達了收發的時間。2) 可以使用rtp_session_set_blocking_mode()設置是否使用阻塞模式來進行rtp包的發送和接收。如果yesno為0,則表明該會話不受系統管理和調度。關于rtp session的管理和調度,由全局的變量RtpScheduler *_ortp_scheduler來負責,該變量必須通過ortp_scheduler_init() 來進行初始化操作。在o
22、rtp_scheduler_init()rtp_scheduler_new() rtp_scheduler_init(sched)rtp_session_set_blocking_mode函數原型:void rtp_session_set_blocking_mode (RtpSession * session, int yesno)函數功能:設置是否使用阻塞模式,參數含義:session: rtp會話結構體yesno: 是否使用阻塞模式注意,阻塞模式只有在scheduling mode被開啟的情況下才能使用。rtp_session_set_local_addr函數原型:int rtp_sess
23、ion_set_local_addr( RtpSession * session, const char * addr,int port)函數功能:設置本地rtp數據監聽地址參數含義:session: rtp會話結構體addr: port: 監聽端口,如果設置為-1,則系統為其自動分配端口返回值: 0表示成功rtp_session_set_remote_addr函數原型:int rtp_session_set_remote_addr (RtpSession * session, const char * addr, int port)函數功能:設置RTP發送的目的地址參數含義:session:
24、 rtp會話結構體addr: 目的IP地址port: 目的地址的監聽端口號返回值: 0表示成功rtp_session_set_send_payload_type函數原型:int rtp_session_set_send_payload_type (RtpSession * session, int pt)函數功能:設置RTP發送數據的負載類型(即將外部的負載類型傳入會話中)參數含義:session: rtp會話結構體pt:負載類型返回值: 0表示成功,-1表示負載未定義說明:負載類型在payloadtype.h文件中有詳細的定義,RTP接收端有著類似的負載類型設置函數,int rtp_sess
25、ion_set_recv_payload_type ( RtpSession * session, int paytype ) ,注意,發送的負載類型必須與接收的負載類型一致才能正常完成收發。rtp_session_signal_connect函數原型:int rtp_session_signal_connect (RtpSession * session, const char *signal, RtpCallback cb, unsigned long user_data)函數功能:本函數提供一種方式,用于通知應用程序各種可能發生的RTP事件(信號)。可能通過注冊回調函數的形式來實現本功能
26、。參數含義:session: rtp會話結構體signal: 信號的名稱cb: 回調函數user_data:傳遞給回調函數的數據返回值:0表示成功怎樣實現:將回調函數的地址,用戶數據加入RtpSignalTable表中,若成功則返回0注意參數中的信號是在rtp_session_init()中定義的7種信號量。rtp_session_send_with_ts函數原型:int rp_session_send_with_ts (RtpSession * session, const uint8_t * buffer, int len, uint32_t userts)函數功能:發送RTP數據包參數含
27、義:session: rtp會話結構體buffer: 需要發送的RTP數據的緩沖區len: 需要發送的RTP數據的長度userts: 本RTP數據包的時間戳返回值: 成功發送到網絡中的字節數說明:這個函數定義了外部的接口,內部定義了怎樣為數據打包,將包發送調用了函數_rtp_session_sendm_with_ts ,而這個函數主要的目的是講述包是怎樣在進程中發送,講述了調度的過程。其中調用了底層的發送函數rtp_session_rtp_send,該函數利用SOCKET進行數據的傳輸。rtp_session_recv_with_ts函數原型:int rtp_session_recv_with
28、_ts (RtpSession * session, char * buffer,int len, uint32_t time, int * have_more)函數功能:接收RTP數據包參數含義:session: rtp會話結構體buffer: 存放接收的RTP數據的緩沖區len: 期望接收的RTP數據的長度time: 期望接收的RTP數據的時間戳have_more:標識接收緩沖區是否還有數據沒有傳遞完。當用戶給出的緩沖區不夠大時,為了標識緩沖區數據未取完,則have_more指向的數據為1,期望用戶以同樣的時間戳再次調用本函數;否則為0,標識取完。rtp_session_destroy【原
29、型】: void rtp_session_destroy(RtpSession *session)【功能】:摧毀rtp會話對象,釋放資源【參數】:session已經創建的RTP會話對象三、程序示例本程序選取的是RTP發送的示例#include <ortp/ortp.h>#include <signal.h>#include <stdlib.h>/條件編譯,如果不是win32系統則包含下面的頭文件#ifndef _WIN32 #include <sys/types.h>#include <sys/time.h>#include <
30、stdio.h>#endifint runcond=1;/當一個信號發生時,使請求停止,在下面的退出循環中將使用void stophandler(int signum)runcond=0;static const char *help="usage: rtpsendfilename dest_ip4addr dest_port -with-clockslide <value> -with-jitter <milliseconds>n"int main(int argc, char *argv)RtpSession *session;unsign
31、ed char buffer160;int i;FILE *infile;char *ssrc;uint32_t user_ts=0;int clockslide=0;int jitter=0;/說明了系統參數將大于4個if (argc<4)printf("%s", help);return -1;for(i=4;i<argc;i+)if (strcmp(argvi,"-with-clockslide")=0)i+;if (i>=argc) printf("%s", help);return -1;clockslid
32、e=atoi(argvi);/將字符串換成整數型ortp_message("Using clockslide of %i milisecond every 50 packets.",clockslide);else if (strcmp(argvi,"-with-jitter")=0)ortp_message("Jitter will be added to outgoing stream.");i+;if (i>=argc) printf("%s", help);return -1;jitter=atoi(
33、argvi);/設置抖動/rtp庫的一些基本初始化ortp_init();/profile初始化,全局統計量清零,產生隨機數ortp_scheduler_init();/對一些信號集合的初始化設置,建立并開啟rtp調度器ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR);/設置日記的級別/創建一個rtp會話session=rtp_session_new(RTP_SESSION_SENDONLY);rtp_session_set_scheduling_mode(session,1);rtp_session_set_block
34、ing_mode(session,1);rtp_session_set_connected_mode(session,TRUE); / 設置遠程RTP客戶端的的IP和監聽端口(即本rtp數據包的發送目的地址rtp_session_set_remote_addr(session,argv2,atoi(argv3);/設置希望發送包的負載類型rtp_session_set_payload_type(session,0);/獲取同步標示源ssrc=getenv("SSRC");if (ssrc!=NULL) printf("using SSRC=%i.n",a
35、toi(ssrc);/ 設置輸出流的SSRC。不做此步的話將會給個隨機值rtp_session_set_ssrc(session,atoi(ssrc);/打開一個文件,準備發送文件中的數據#ifndef _WIN32infile=fopen(argv1,"r");#elseinfile=fopen(argv1,"rb");#endifif (infile=NULL) perror("Cannot open file");return -1;/外部的一個動作,內核送一個SIGINT信號給進程,啟動stophandler這個處理函數,即終
36、止進程signal(SIGINT,stophandler);/將文件中的內容讀入緩沖區中,并將緩沖區中的數據發送,/每發送一次,時間戳加160,如果時間片沒有到0 ,繼續發送while( (i=fread(buffer,1,160,infile)>0) && (runcond) )rtp_session_send_with_ts(session,buffer,i,user_ts);user_ts+=160;if (clockslide!=0 && user_ts%(160*50)=0)ortp_message("Clock sliding of
37、%i miliseconds now",clockslide);rtp_session_make_time_distorsion(session,clockslide);/設置時間偏移量/*this will simulate a burst of late packets */利用nanosleep()進行延時減緩抖動if (jitter && (user_ts%(8000)=0) struct timespec pausetime, remtime;ortp_message("Simulating late packets now (%i millise
38、conds)",jitter);pausetime.tv_sec=jitter/1000;pausetime.tv_nsec=(jitter%1000)*1000000;while(nanosleep(&pausetime,&remtime)=-1 && errno=EINTR)pausetime=remtime;/退出,釋放資源fclose(infile);/關閉文件rtp_session_destroy(session);ortp_exit();ortp_global_stats_display();/打印全局統計變量return 0; 文件修改部
39、分,主要是在avprofile.c中av_profile_init()添加了一個負載類型,因為我們的TBCP定義為106,同時在rtpsession_priv.h中將rtcp接收函數部分的返回類型進行了修改為mblk_t*,定義為一個函數指針,目的是為了獲得RTCP包,之前的函數只是返回接收到的數據字節數。Rtpsession_inet.c沒有做多大的修改,只是加了一個TBCP的頭文件。 在源程序中增加了tbcp.c文件和tbcp.h文件,主要講述了一些控制信息功能。四、TBCP首先是tbcp語音沖突發送消息請求,可以包含一個或多個可選域。每個TBCP Talk Burst請求消息可選域應該包含三個子域:第一個子域是可選ID
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
評論
0/150
提交評論