描述: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
描述: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()函數內的處理片斷爲:
… } |
__tmedia_session_plugins是一個tmedia_session_plugin_def_t類型的全局指針數組,用於存放各類媒體類型的定義。
tmedia_session_create()函數用於更具媒體的類型建立一個tmedia_session_t類型的實例,媒體類型由上層應用指定,記錄在tmedia_session_mgr_t實例的type字段,經常使用的有audio,vedio,audiovideo三個類型。
描述:
這其實也是一個通用結構,被更具體的結構包含着。
而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中。
這個過程的調用堆棧爲:
|
建立時機:
見上一條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(…)函數調用,用於加載編解碼模塊
加載編解碼模塊的代碼片斷爲:
|
描述:
在一個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。
原型:const tsdp_message_t*tmedia_session_mgr_get_lo(tmedia_session_mgr_t*self)
做用:準備SDP信息,給新的通話開一個RTP端口