doubango(6)--Doubango協議棧中對RTP的管理

相關數據結構

1.    tsip_dialog_invite_t

描述:html

一個invite_dialog表明了一個invite期間的全部的信令流程,所以,它首先是一個廣泛的dialog的特殊化結構,在該結構的起始部分,有一個TSIP_DECLARE_DIALOG聲明,該聲明展開後是一個tsip_dilog_t __dialog字段的定義,這是一種在C中一個具化對象對通用對象的繼承機制,tsip_dialog_t對象表明了更通用的實例,而tsip_dialog_invite_t對象則是tsip_dialog_t對象的具化和拓展。數組

一個dialog自己有本身的有限狀態處理機,有本身的當前狀態和當前狀態應執行的動做,還有一個狀態變化時的回調函數。它還須要有一個字段指向它所屬的session,這些字段,反應在數據類型上上,分別是:網絡

tsk_fsm_t(有限狀態機),tsip_action_t(狀態執行動做),tsip_dialog_state_t(當前狀態),session

tsip_dialog_event_callback_f(回調函數),tsip_ssession_t(所屬session)。數據結構

建立時機:app

tsip_action_INVITE()函數是上層應用與底層協議棧的接口,當上層應用發起一個INVITE時,便會分層調用到該接口。ide

tsip_dialog_invite_t類型的實例即是在該接口中建立的,對於建立時,還須要在協議棧的全局dialog隊列中尋找一遍,看是否相關的dialog已經在以前被建立,如果,則沿用老的實例,若否,則用tsip_dialog_layer_new()函數建立一個新的實例,並鏈入到協議棧dialog_layer層的全局隊列中。函數

關鍵點:oop

 

2.    tmedia_session_mgr_t

描述:spa

一個tmedia_session_mgr_t實例是由上述的tsip_dialog_invite_t實例的session_mgr字段記錄的,表明了在一個對話期間各類媒體設置的管理者。

 

當發起一個INVITE時,首先必須存在一個表明信令流程的對象即dialog對象,其次,還要有一個負責管理媒體信息的對象,及該結構的實例。

 

建立時機:

該結構的首次建立是在invite_dialog的狀態轉換過程當中,c0000_Started_2_Outgoing_X_oINVITE()函數是一個狀態轉化函數,它表明着當前dialog由初始狀態向發起INVITE後狀態轉化須要執行的操做,在該函數內部,經過tmedia_session_mgr_create()建立tmedia_session_mgr_t實例,而後填寫本地媒體信息(即sdp中得各個字段),申請rtp端口號,生成表明rtp的網絡傳輸實例(tnet_transport_t對象),最後在該狀態轉換函數中,經過協議棧的表明信令的網絡傳輸實例將INVITE消息傳遞出去。

 

關鍵點:

tmedia_session_mgr_t中,有一個tmedia_sessions_L_t*sessions的字段,這個字段實際上是一個隊列,掛載的表示表明了各類媒體的信息(音頻,視頻),每個隊列節點是一個tmedia_session_t的實例。

關鍵函數:

_tmedia_session_mgr_load_sessions(tmedia_session_mgr_t *mgr)函數

     原型:_tmedia_session_mgr_load_sessions(tmedia_session_mgr_t *mgr)

     做用:用於生成和加載各類類型的tmedia_session_t實例。

 

說明:_tmedia_session_mgr_load_sessions()函數在tmedia_session_mgr_create()函數中被調用,在這個函數內,會生成各個tmedia_session_t實例,掛入tmedia_session_mgr_t實例的sessions隊列。其中在_tmedia_session_mgr_load_sessions()函數內的處理片斷爲:

 

[html]  view plain copy 在CODE上查看代碼片 派生到個人代碼片
  1. int _tmedia_session_mgr_load_sessions(tmedia_session_mgr_t*self){  
  2.   
  3. const tmedia_session_plugin_def_t* plugin;  
  4.   
  5. …  
  6.   
  7. if(TSK_LIST_IS_EMPTY(self->sessions)){  
  8.   
  9.         /* for each registered plugin create a session instance */  
  10.   
  11.         while((i <TMED_SESSION_MAX_PLUGINS) && (plugin =__tmedia_session_plugins[i++])){  
  12.   
  13.             if((plugin->type &self->type) ==plugin->type){  
  14.   
  15.                 if((session =tmedia_session_create(plugin->type))){  
  16.   
  17.                    tsk_list_push_back_data(self->sessions, (void**)(&session));  
  18.   
  19.                 }  
  20.   
  21.            }  
  22.   
  23. }  

 

}

__tmedia_session_plugins是一個tmedia_session_plugin_def_t類型的全局指針數組,用於存放各類媒體類型的定義。

tmedia_session_create()函數用於更具媒體的類型建立一個tmedia_session_t類型的實例,媒體類型由上層應用指定,記錄在tmedia_session_mgr_t實例的type字段,經常使用的有audio,vedio,audiovideo三個類型。

3.    tmedia_session_t

描述:

這其實也是一個通用結構,被更具體的結構包含着。

tdav_session_audio_t,tdav_session_video_t等結構即是更具體的結構,在這些結構的其實,包含了該通用的結構。每個更通用的結構都記錄一個trtp_manager_s的實例,這個結構即是表明語音流和視頻流的管理者。

在建立tmedia_session_t實例時,是根據plugin->objdef來調用tsk_object_new()的,調用語句爲tsk_object_new(plugin->objdef),plugin是上一節所述的__tmedia_session_plugins 所記錄的tmedia_session_plugin_def_t 實例,故當plugin->type爲audio類型時,建立的真正結構爲tdav_session_audio_t,真正的構造函數爲tdav_session_audio_ctor(),定義在tdav_session_audio.c中。

這個過程的調用堆棧爲:

 

[html]  view plain copy 在CODE上查看代碼片 派生到個人代碼片
  1. int _tmedia_session_mgr_load_sessions(tmedia_session_mgr_t*self){  
  2.   
  3. const tmedia_session_plugin_def_t* plugin;  
  4.   
  5. …  
  6.   
  7. if(TSK_LIST_IS_EMPTY(self->sessions)){  
  8.   
  9.         /* for each registered plugin create a session instance */  
  10.   
  11.         while((i <TMED_SESSION_MAX_PLUGINS) && (plugin =__tmedia_session_plugins[i++])){  
  12.   
  13.             if((plugin->type &self->type) ==plugin->type){  
  14.   
  15.                 if((session =tmedia_session_create(plugin->type))){  
  16.   
  17.                    tsk_list_push_back_data(self->sessions, (void**)(&session));  
  18.   
  19.                 }  
  20.   
  21.            }  
  22.   
  23. }  

 

 

 

建立時機:

見上一條tmedia_session_mgr_t的關鍵點。

關鍵點:

在一個tmedia_session_t結構的實例中,承載了這個tmedia_session_t實際類型的編解碼插件,例如tmedia_session_t的type爲video時,在tmedia_session_init(tmedia_session_t*self)函數中會初始化一個tmedia_session_t的實例,而根據多態的原理,這個tmedia_session_t實例的真正類型爲tdav_session_video_t實例,所以,在初始化時,會從__tmedia_codec_plugins數組中加載全部的type爲video的解碼模塊,__tmedia_codec_plugins數組會在啓動協議棧時初始化,具體的初始化函數是tdav_init(),這是也會根據可以加載的編解碼模塊,將各個編解碼插件記錄到該__tmedia_codec_plugins全局指針數組中,數組的每個項都指向了一個plugin,一個plugin表明了一個實際的編解碼模塊。

關鍵函數描述:

tmedia_session_init()函數:

     原型: tmedia_session_init(tmedia_session_t*self,tmedia_type_ttype)

     做用: 初始化一個新生成的tmedia_session_t實例,加載各個編解碼模塊

_tmedia_session_load_codecs(tmedia_session_t  *self)函數;

     描述:該函數被tmedia_session_init(…)函數調用,用於加載編解碼模塊

加載編解碼模塊的代碼片斷爲:

  

[html]  view plain copy 在CODE上查看代碼片 派生到個人代碼片
  1. int _tmedia_session_mgr_load_sessions(tmedia_session_mgr_t*self){  
  2.   
  3. const tmedia_session_plugin_def_t* plugin;  
  4.   
  5. …  
  6.   
  7. if(TSK_LIST_IS_EMPTY(self->sessions)){  
  8.   
  9.         /* for each registered plugin create a session instance */  
  10.   
  11.         while((i <TMED_SESSION_MAX_PLUGINS) && (plugin =__tmedia_session_plugins[i++])){  
  12.   
  13.             if((plugin->type &self->type) ==plugin->type){  
  14.   
  15.                 if((session =tmedia_session_create(plugin->type))){  
  16.   
  17.                    tsk_list_push_back_data(self->sessions, (void**)(&session));  
  18.   
  19.                 }  
  20.   
  21.            }  
  22.   
  23. }  

 

 

4.    tdav_session_audio_t

 

5.    tdav_session_video_t

6.tsip_request_t

描述:

在一個tsip_dialog_invite_t實例被建立,進入它的狀態機執行時,第一個狀態的轉化爲:

Started -> (oINVITE)-> Outgoing

此時由函數int c0000_Started_2_Outgoing_X_oINVITE(va_list*app)進行該狀態的處理,在此函數內部,會爲tsip_dialog_invite_t實例建立tmedia_session_mgr_t實例並記錄在tsip_dialog_invite_t實例的msession_mgr字段,建立msession_mgr的同時,會創建msession_mgr的sessions隊列和加載各類編解碼模塊。完成這一切後,會調用send_INVITEorUPDATE()函數,完成一個sip的invite request。

該函數的原型爲:

int send_INVITEorUPDATE(tsip_dialog_invite_t*self,tsk_bool_tis_INVITE,tsk_bool_tforce_sdp)

從名字能夠看出,函數除了完成INVITE外,還能夠完成一個sip會話的更新操做,例如可能編解碼變動,而不想從新發起一個INVITE請求時,便在原有請求的基礎上進行UPDATE。

具體是一個新的INVITE仍是一個UPDATE,由參數is_INVITE指定。

在一個新的INVITE請求發起時,最重要的結構即是tsip_request_t結構,這個結構表明了一個真正的sip消息。

 

關鍵點:

在一個INVITE請求發起時,生成一個tsip_request_t實例的過程有如下幾步:

a)   用tsip_dialog_request_new()函數生成tsip_request_t結構的實例。並作相應的初始化。

b)   當這個dialog的狀態爲tsip_initial時,須要爲SIP_INVITE消息的消息體生成SDP包,此時分解爲如下幾個小步驟(假設代碼中的self爲tsip_dialog_invite_t實例):

1)   調用用函數tmedia_session_mgr_get_lo(self->msession_mgr),經過msession_mgr中sessions隊列記錄的tmedia_session_t實例和每一個tmedia_session_t實例codecs隊列中記錄的編解碼模塊生成一個tmedia_sdp_t的實例。該實例便攜帶了媒體協商的全部數據。在這個過程當中,還要完成RTP端口的生成,爲之後的音視頻通話搭建真正的通道,這個過程將在後面解析。

2)   調用tsdp_message_tostring()函數將tmedia_sdp_t的實例轉化爲ASCII字符。假設這一步中獲得的字符串爲sdp。

3)   調用tsip_message_add_content()函數將sdp拷貝到tsip_request_t實例的的message_body中。釋放sdp。

 

RTP端口的生成過程

tmedia_session_mgr_get_lo(…)函數

原型:const tsdp_message_t*tmedia_session_mgr_get_lo(tmedia_session_mgr_t*self)

做用:準備SDP信息,給新的通話開一個RTP端口

內存關係圖

 

 

相關文章
相關標籤/搜索