<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                本人承接 sip/ims 視頻客戶端定制開發,提供IMS硬終端solution,支持接入sip軟交換,ims核心網,支持 語音,視頻,即時通信功能,視頻格式支持 h263,h264,mpeg4 軟編軟解,提供硬件編解碼接口對接,支持基于三星 sp5v210,trident, 海斯芯片H264 硬件編解碼,提供服務器,有興趣請聯系我。 VOIP行業資訊和技術趨勢請參考: www.voip123.cn csdn lidp ?[http://blog.csdn.net/perfectpdl](http://blog.csdn.net/perfectpdl) 1.tinysip?介紹 : 兼容性 :?SIP(RFC 3261)?以及?3GPPIMS/LTE (TS 24.229) implementation 依賴?tinySAK,tinyNET, tinySDP, tinyMEDIA, tinyHTTP and tinyIPSec. 2.SIP協議?- tinysip的實現機制 SIP是一個分層結構的協議,這意味著它的行為是根據一組平等獨立的處理階段來描述,每一階段之間只是松耦合。協議分層描述是為了表達,從而允許功能的描述可在一個部分跨越幾個元素。它不指定任何方式的實現。當我們說某元素包含某層,我們是指它順從該層定義的規則集。 不是協議規定的每個元素都包含各層。而且,由SIP規定的元素是邏輯元素,不是物理元素。一個物理實現可以選擇作為不同的邏輯元素,甚至可能在一個個事務的基礎上。 SIP的最底層是語法和編碼。它的編碼使用增強Backus-Nayr形式語法(BNF)來規定。 第二層是傳輸層。它定義了網絡上一個客戶機如何發送請求和接收響應以及一個服務器如何接收請求和發送響應。所有的SIP元素包含傳輸層。 第三層是事務層。事務是SIP的基本元素。一個事務是由客戶機事務發送給服務器事務的請求(使用傳輸層),以及對應該請求的從服務器事務發送回客戶機的所有響應組成。事務層處理應用層重傳,匹配響應到請求,以及應用層超時。任何用戶代理客戶機(UAC)完成的任務使用一組事務產生。用戶代理包含一個事務層,有狀態的代理也有。無狀態的代理不包含事務層。事務層具有客戶機組成部分(稱為客戶機事務)和服務器組成部分(稱為服務器事務),每個代表有限的狀態機,它被構造來處理特定的請求。 事務層之上的層稱為事務用戶(TU)。每個SIP實體,除了無狀態代理,都是事務用戶。當一個TU希望發送請求,它生成一個客戶機事務實例并且向它傳遞請求和IP地址,端口,和用來發送請求的傳輸機制。一個TU生成客戶機事務也能夠刪除它。當客戶機取消一個事務時,它請求服務器停止進一步的處理,將狀態恢復到事務初始化之前,并且生成特定的錯誤響應到該事務。這由CANCEL請求完成,它構成自己的事務,但涉及要取消的事務。 SIP通過EMAIL形式的地址來標明用戶地址。每一用戶通過一等級化的URL來標識,它通過諸如用戶電話號碼或主機名等元素來構造(例如:SIP:vision-com.com)。因為它與EMAIL地址的相似性,SIPURLs容易與用戶的EMAIL地址關聯。 SIP提供它自己的可靠性機制從而獨立于分組層,并且只需不可靠的數據包服務即可。SIP可典型地用于UDP或TCP之上。 Register,Invite, Options … Nat Tranversal Dialog Layer Transaction Layer Parsing Layer Transport Layer sip?協議棧分層結構圖 根據sip消息流向可以分為incomingmessage?和outgoing message,incoming?消息從 下到上,即TransportLayer → Register,Invite, Options; outgoing message?消息流向與此相反。 3.根據以上定義,tinysip分如下模塊: 1).api外部接口,對sip協議支持的方法的接口封裝,協議棧提供的發起請求及接受請求對應的接口,包括registar layer, presencelayer等上層應用,當前版本支持如下請求: REGISTER,SUBSCRIBE(訂閱),MESSAGE(即時通信),PUBLISH(狀態展示),OPTIONS(查詢服務器能力),INVITE(發起請求),Cancel(取消一個請求), BYE(結束通話)。 2).Nat traversal?:Nat穿越層,tinysip目前支持stun,turn穿透。 3).Dialog,會話模塊,一路呼叫的唯一標識,處于sip事務層之上。 4).parsers,sip消息解析,處于sip?語法層,解析從傳輸層傳遞的數據包為協議棧理解的結構。 5).transactions, 事務層,事務是一個請求以及與此請求相關的所有響應組成,用transaction id唯一標識,由于sip信令一般由udp承載,所以不能保證信息的可靠到達,所以事務層必須提供一種機制處理udp所不能提供的功能,這里一般通過定時器及一個有限狀態機來實現。 6).transports ,傳輸層,即?udp, TCP, TLS, SCTP socket?系統調用系列,此層隱藏了所有傳輸層的細節,對于incomingsip message?, 此層為sip消息的入口,對于outgoingsip message,?此層為sip消息的出口。 4.doubango sip?協議棧使用流程: 1).初始化 doubango sip協議棧依賴于tinyNET模塊,所以必須先調用tnet_startup函數初始化,退出時調用tnet_cleanup清除資源,初始化sip 協議棧之前必須設置用戶的域(realm參見(1))及用戶的私有(IMPI(2))及共有標別(IMPU(3)),這些為ims引入的概念。 (1)realm?解釋:reaml為域名,用來作客戶端認證用(authenticate).必須是一個有效的?sipuri?如:sip:vision-com.com.cn,realm?為sip協議棧啟動之前必須設置的選項,一旦協議棧啟動realm就不可以更改,如果不填寫sip代理服務器地址,則系統會用realm通過?dns NAPTR + SRV?或者DHCP(還沒實現)動態查找機制確定sip?服務器地址。 (2)用戶私有標識,為用戶所屬網絡賦予的唯一值,用來做驗證,為IMS中的概念,如果用doubangosip協議棧作為普通sip功能,即非IMS網絡中的sip功能,此處的impi意義與sip協議棧中的驗證域名相同,私有ID用在身份認證,授權等,主要是安全方面的作用。 (3)用戶公有標識,ims網絡中一個impi可以對應多個impu.,公有ID用在業務配置、計費等,主要是業務方面的作用。 更進一步解釋: IMPU,它更靠近業務層,用于標識業務簽約關系,計費等,還表示用戶身份以及用于路由,但它不能表示用戶實際的位置信息,當然這個是對于非傳統固話來說,傳統固定方式下用戶號碼與位置存在綁定關系,因為用戶線接入是固定的。 然后是IMPI,它是網絡層的東東,用于表示用戶和網絡的簽約關系,一般也可以唯一的表示一個終端。使用IMPI,網絡可以通過鑒權來識別用戶是否可以使用網絡。 最后是用戶的聯系地址,這個是注冊的時候要帶的,它是用戶真實的尋址地址,IMPU和聯系地址分離才能支持移動性,對于傳統GSM網絡,漫游號起到了類似聯系地址的作用,你也可以認為GSM中的位置更新也是一種注冊流程。 注冊后S-CSCF知道IMPU以及聯系地址,當有人呼叫此IMPU,根據聯系地址即可找到實際的用戶,因此注冊維護了一個用戶的尋址通路。 2).創建以及啟動 通過調用?tsip_stack_create創建協議棧, 調用tsip_stack_start啟動, 完整例子: ~~~ tsip_stack_handle_t*stack = tsk_null; intret; constchar* realm_uri = "sip:vision-com.com.cn"; constchar* impi_uri = "lideping@vision-com.com.cn"; constchar* impu_uri = "sip:bob@vision-com.com.cn"; //...必須先初始化tnet工具 tnet_startup(); // ... //創建協議棧,指定回調函數,參數為域名,公有及私有標識。 stack= tsip_stack_create(sip_callback, realm_uri, impi_uri, impu_uri, TSIP_STACK_SET_PASSWORD("yourpassword"), //...other macros... //此處初始化其他信息,比如代理服務器地址,編碼信息等。 tsip_stack_start(stack) //啟動協議棧 TSIP_STACK_SET_NULL());//用來終止傳給app_callback的參數。 TSK_OBJECT_SAFE_FREE(stack); tnet_cleanup(); //釋放資源 //事件回調 intsip_callback(const tsip_event_t *sipevent) { //事件類型 switch(sipevent->type){ casetsip_event_register: { /*REGISTER */ break; } casetsip_event_invite: { /*INVITE */ break } casetsip_event_message: { /*MESSAGE */ break } casetsip_event_publish: {/* PUBLISH */ break } casetsip_event_subscribe: { /*SUBSCRIBE */ break } casetsip_event_options: { /*OPTIONS */ break } casetsip_event_dialog: { /*Common to all dialogs */ break } /*case …*/ } ~~~ 會話事件,協議棧事件放入事件隊列,協議棧啟動時創建一個線程不斷從隊列里取事件,然后通過調用事件回調通知上層用戶。 5.代碼分析 首先調用tsip_stack_create創建協議棧,tsip_stack_create內部首先檢查參數是否合法,然后創建協議棧結構tsip_stack_t,設置realm,IMPI and IMPU,初始化一些協議棧默認值。創建SigComp?信令壓縮模塊(可選)創建dns處理模寬,DHCPcontext?,接下來創建上面提到的sip協議棧各層,分別調用tsip_dialog_layer_create,tsip_transac_layer_create,tsip_transport_layer_create創建會話層,事務層及傳輸層。至此,創建協議棧畢。 在真正啟動協議棧之前,即tsip_stack_create與tsip_stack_start之間可調用協議棧提供的api初始化其他參數,然后調用tsip_stack_start啟動協議棧,首先啟動定時器線程,這里定時器主要在事務層提供狀態機功調度功能。然后設置傳輸層類型,設置是否用ipsec把sip信令加密,然后如果協議棧是處于客戶端模式并且代理服務器地址沒有設置則用認證的域名查找代理服務器的地址(用SNAPTR+SRV),然后設置Runnable回調,啟動run?線程,run內部不斷從消息隊列里取消息,這里的消息是從傳輸層從下到上傳送過來,最終串聯到消息隊列,然后調用協議棧創建時指定的回調sip_callback,所有incomingsip消息以及媒體信息的改變最終都會走到此回調函數,此函數內部根據消息類型的不同調用相應的handler,接下來啟動nat穿越模塊,設置stun地址。然后調用tsip_transport_layer_start啟動傳輸層線程,在sip端口5060接收數據,最后,設置stack->started= tsk_true;?至此協議棧啟動完畢,各層在相應端口或狀態機上監聽,不斷輪詢到來的事件并處理。 驅動過程: 協議棧啟動完畢后,對于每一個incoming及outgoing?消息的入口不一樣,下面分別分析對于呼入請求(incoming)及外乎請求(outgoing)的代碼流程。 a.呼入請求 1)客戶端傳輸層在5060端口上接收到udp包,語法層解析成識別的sip消息后傳給事務層。 2)事務層鎖住本地事務鏈表,根據sip消息的事務id在事務鏈查找是否存在匹配的事務,沒有則創建。 3)一旦找到事務或創建新事務完畢,釋放鎖并把消息傳遞到會話層。 4)會話層收到sip消息后查找會話鏈,找不到則創建會話,同時根據消息類型(invite,ack?等)設置此消息的狀態機,狀態機內指定具體事件的回調。 b.呼出請求 1)構造外乎請求,包括消息頭和消息體. 2)創建會話層,事務層,事務層調用傳輸層接口發出請求。 6. 外部編程接口 為了在android上層通過java訪問doubango核心,imsdroid對doubango voip框架做了面向對象封裝,根據具體模塊功能抽象成具體Java類供應用層使用,應用層通過jni訪問doubango核心,同時,在imsdroid2.0版本中,根據android上應用層的架構抽象出一個類庫,doubango-ngn-stack,利用此類庫我們可以在android上自己開發一些客戶端應用程序,包括語音,視頻,即時通信,多媒體共享,會議等應用。Imsdroid2.0即是構建在?doubango-ngn-stack上的一個具體應用。 Doubango-ngn-stack原理 doubango-ngn-stack是對doubangovoip框架的一個java層封裝,內部通過java本地調用技術實現(jni),這與android上的框架設計是相符的(如java類庫提供的攝像頭功能即依賴于底層驅動,上層通過jni訪問底層驅動), doubango/bindings/java 用SWIG工具把c/C++函數封裝成JAVA中的類,目前SWIG已經可以支持Python,Java, C#,Ruby,PHP,等語言。 7. 代碼實例分析 ???? 注冊過程 1). 注冊流程(java-->C++-->C) register(NgnSipService.java) | register(NgnRegistrationSession.java) | register_(sipsession.cxx) | tsip_action_REGISTER(stip_api_register.c) tsip_action_REGISTER 分三步: _tsip_action_create創建注冊請求, tsip_dialog_layer_new?創建注冊session,為后續進入狀態機作準備,?tsip_dialog_fsm_act?進入狀態機模式。 1._tsip_action_create 創建注冊請求,這里只是創建一個抽象的請求,請求對應sip的方法,sip協議定義了 register,invite,publish,subscribe, bye,message等方法。 然后調用_tsip_action_set初始化上層(java)傳過來的參數。 1. 請求創建成功后創建會話層tsip_dialog_layer_new sip協議中每個請求方法對應一個會話,即session,此函數根據會話類型創建相應會話的session.對于注冊會話,會調用tsip_dialog_register_create創建會話層,然后把創建后的會話保存到協議棧的會話層鏈表。 (1)tsip_dialog_register_create(tsip_dialog_register.c)創建注冊會話 內部new一個注冊對象tsip_dialog_register_def_t,構造函數中執行如下動作。 tsip_dialog_register_ctor內部分三步: a.tsip_dialog_init?初始化基本的會話信息,這里分客戶端及服務器端。同時會創建此會話的狀態機,并初始化狀態機的狀態。 b.tsk_fsm_set_callback_terminated?設置注冊會話結束狀態機回調。 c.tsip_dialog_register_init?初始化具體注冊會話信息 tsip_dialog_register_client_init初始化注冊請求的客戶端狀態機回調。 這里實際上是當一個請求過程中,當請求從一個狀態到另一個狀態時應該調用的回調函數。 tsip_dialog_register_server_init功能相同。 tsip_dialog_register_event_callback設置從傳輸層過來的注冊事件的回調,通知上層。 3. tsip_dialog_fsm_act,是所有sip會話開始進入狀態機的入口。 參數為 會話,會話類型,sip消息,請求。 此函數內部會調用狀態機通用函數tsk_fsm_act。執行一個具體的請求,同時可能改變相應會話的狀態機的狀態。 inttsk_fsm_act(tsk_fsm_t* self, tsk_fsm_action_id action, const void*cond_data1, const void* cond_data2, …) 內部是一個循環,不斷檢測狀態,根據狀態調用相應的回調。 每個狀態機都有一個初始狀態作為運轉入口,對于注冊請求,入口為, TSK_FSM_ADD_ALWAYS(_fsm_state_Started,_fsm_action_oREGISTER, _fsm_state_InProgress,tsip_dialog_register_Started_2_InProgress_X_oRegister,"tsip_dialog_register_Started_2_InProgress_X_oRegister"), tsk_fsm_act一開始會執行tsip_dialog_register_Started_2_InProgress_X_oRegister回調, 此回調是由狀態_fsm_state_Started到_fsm_state_InProgress時執行的操作, 內部先更改自己的當前狀態為_fsm_state_InProgress,這樣給tsk_fsm_act?提供了調用下一個狀態的入口。 函數內部調用tsip_dialog_register_send_REGISTER?創建事務層,初始化事務層狀態機,最后調用傳輸層socket接口把請求發送出去。 由于sip根據請求的類型把事務層分為幾種類型,包括客戶端請求(invite)事務,客戶端非請求事務(如bye,register),服務器端請求事務,服務器端非請求事務。 所以對于注冊請求,會創建非請求客戶端事務層。 tsip_dialog_register_send_REGISTER---> tsip_dialog_request_new --->tsip_dialog_request_send---->tsip_transac_layer_new--->tsip_transac_start --->tsip_transac_nict_start,進入事務層狀態機模式。 這里,在創建事務層時會設置事務層事件回調,tsip_transac_nict_event_callback。 比如發出register請求,服務器端給200ok響應。此時傳輸層會把此響應作為事件給事務層,事務層收到此事件,解析后進入事務層狀態機。 所以對于 一次?sip請求,有兩個狀態機在運轉,一個為會話層狀態機,一個為事務層狀態機。 至此,一個register請求已經發送出去,會話層,事務層狀態機都在運轉, 此時,如果服務器返回注冊成功,則會給客戶端傳輸層發送200OK響應。 tsip_transport_layer_dgram_cb,tsip_transport_layer_handle_incoming_msg, tsip_transac_layer_handle_incoming_msg,tsip_transac_layer_find_client 客戶端傳輸層收到響應后會根據響應的事務id查找是否為已經創建的事務。 ,找到后會根據此事務創建時指定的回調,調用相應事務層的回調函數,這里為tsip_transac_nict_event_callback,此函數內部根據消息類型調用tsip_transac_fsm_act執行事務層狀態機,比如?200ok?,會調用事務層創建時指定的回調。這里為tsip_transac_nict_Trying_2_Completed_X_200_to_699。 內部調用會話層回調通知上層注冊成功。tsip_dialog_register_event_callback 此函數根據狀態調用相應會話層狀態機,tsip_dialog_register_InProgress_2_Connected_X_2xx,修改狀態機當前狀態,為下一個狀態作準備,最后調用TSIP_DIALOG_REGISTER_SIGNAL發射 注冊成功事件給上層用戶。 這里事件機制:TSIP_DIALOG_REGISTER_SIGNAL?通過tsip_register_event_signal創建一個注冊事件,然后把此事件放入協議棧啟動時的事件隊列中, tsip_stack_start內部啟動run線程處理協議棧事件。 /* ===Runnable === */ TSK_RUNNABLE(stack)->run= run; if((ret= tsk_runnable_start(TSK_RUNNABLE(stack), tsip_event_def_t))){ stack_error_desc= "Failed to start timer manager"; TSK_DEBUG_ERROR("%s",stack_error_desc); gotobail; } 在run線程中不斷掃描事件隊列,pop出一個事件,然后送給sip協議棧創建時指定的事件回調,從而把協議棧事件(事務層事件,會話層事件,協議棧事件)返回給上層用戶。 至此,一次正常(沒考慮異常,401認證過程等)的注冊流程分析完畢。 2.)外乎流程: screenAV.java publicstatic boolean makeCall(String remoteUri, NgnMediaType mediaType){ makeCall(StringremoteUri, NgnMediaType mediaType) | createOutgoingSession | makeCall(remoteUri);(NgnAVSession.java) | callAudioVideo | callAudioVideo(sipsession.cxx) | __droid_call(sipsession.cxx) | __droid_call_thread(sipsession.cxx) | tsip_action_INVITE(tsip_api_invite) 至此,由上層調用到底層協議棧。 同樣分三步: _tsip_action_create tsip_dialog_layer_new tsip_dialog_fsm_act 從創建會話層開始分析: tsip_dialog_layer_new tsip_dialog_invite_create tsip_dialog_invite_ctor(tsip_dialog_invite.c) 構造函數內過程: (1)tsip_dialog_init創建相關頭域,創建invitesession狀態機并初始化狀態。 (2)tsk_fsm_set_callback_terminated設置?invite會話狀態機結束的回調函數tsip_dialog_invite_OnTerminated。 (3)tsip_dialog_invite_init初始化invite請求本身,具體如下: a.tsip_dialog_invite_client_init初始化服務器端invite會話信息,實際上為設置客戶端invite會話的狀態機。 Started-> (send INVITE) -> Outgoing-> Connected ...... 狀態轉換過程中調用相應回調。 b.tsip_dialog_invite_server_init?設置服務器端invite會話狀態機。 //Started -> (Bad Extendion) -> Terminated //Started -> (Bad content) -> Terminated //Started -> (Session Interval Too Small) -> Started .......... 1. tsip_dialog_invite_hold_init設置?hold?狀態機,3GPPTS 24.610: CommunicationHold。 d.tsip_dialog_invite_stimers_init ,設置sessiontimer?狀態機,rfc RFC 4028:SessionTimers e.tsip_dialog_invite_qos_init,設置?qos狀態機,RFC 3312 f.初始化其他狀態機。 TSIP_DIALOG(self)->callback= TSIP_DIALOG_EVENT_CALLBACK_F(tsip_dialog_invite_event_callback); 設置invite會話層事件回調,比如服務器響應,則會調用此回調,內部根據響應類型調用狀態機,根據狀態執行相應回調。 tsip_dialog_fsm_act,所有準備階段完成后,第三步進入狀態機模型,輪轉吧。 第一個調用的狀態機回調為c0000_Started_2_Outgoing_X_oINVITE, Started-> (oINVITE) -> Outgoing。 此函數內部: 首先調用tmedia_session_mgr_create初始化自己的媒體信息,后面放到invite請求的 sdp里面。 接下來更新此次請求的狀態機階段,這樣下一個狀態機回調以此為起點。 然后設置invite請求的一些特殊頭域。tmedia_session_mgr_set_qos,/*100rel */ self->supported._100rel等。 最后調用send_INVITE,TSIP_DIALOG_SIGNAL產生invite事件通知上層用戶。 send_INVITE又調用send_INVITEorUPDATE 內部又分如下過程。 a.tsip_dialog_request_new,創建一個通用的sip?請求。 b.tmedia_session_mgr_get_lo創建invite消息的消息體,即sdp信息。 1. 初始化其他頭域 tsip_dialog_request_send發送請求。 創建事務層。 tsip_transac_layer_new,tsip_transac_ict_create tsip_transac_ict_ctor初始化 客戶端invite事務層: tsip_transac_init tsk_fsm_set_callback_terminated tsip_transac_ict_init 最終開啟客戶端請求事務狀態機。 tsip_transac_start 當服務器端返回?200ok后,會調用事務層,事務層又轉給會話層,最終轉到 c0000_Outgoing_2_Connected_X_i2xxINVITE回調函數, 內部對200ok響應做出里: tsip_dialog_update更新會話狀態, tsip_dialog_invite_process_ro處理對端?sdp,建立rtp流。 send_ACK?給?ACK響應。 TSIP_DIALOG_INVITE_SIGNAL最后給上層發射 事件,通知用戶接通。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看