天天看點

關于PJSPI如何實作主備切換的預研

關于PJSPI如何實作主備切換的預研

    • 項目背景
      • 産品介紹
      • 功能框圖
    • 預研任務
    • 設計思路
    • PJSIP
      • 背景介紹
      • 軟體結構
    • 解決思路
    • 調試問題

項目背景

産品介紹

目前我們公司開發的項目是綜合接入網關裝置,它位于IMS網絡的使用者側,負責提供語音和資料傳真業務,将使用者接入到IMS網絡完成相應功能。裝置上行通過GE網口接入IMS網絡,下行通過FXS話機接口提供語音業務。

功能框圖

關于PJSPI如何實作主備切換的預研

預研任務

該項目中我負責如何保證裝置發生故障切換時,整個軟體系統仍能保證正常工作。并且重要的一點是,發生切換時,已經接通的呼叫不應受到影響,仍能保持正常的通話。

設計思路

關于PJSPI如何實作主備切換的預研

基本的通信邏輯是:Master狀态下的闆會定時向Slave狀态的闆發送keepalive消息,當Slave狀态下的闆連續n次接受不到Master闆的Keepalive消息,則發生切換,Slave闆會切換為Master狀态繼續工作,并開始向另外一方發送Keepalive消息。概要的時序如下:

關于PJSPI如何實作主備切換的預研

當發生切換時,切換為Master狀态的辦卡需要向其所在的Base平面發送廣播消息,用以通知SIU切換事件的發生。

主要間的資料同步,主要是指使用者、IMS賬戶、數圖、告警和記錄檔等資料的同步,可通過資料庫同步機制進行解決。

主要間的狀态同步,則包括裝置狀态和會話狀态的同步。其中,對于前者隻需SIU和EIU通過心跳将裝置狀态同時發送到兩台MCU即可實作裝置狀态同步;對于後者,SIP會話如果要保持,最少應支援Reinvite/update和BYE消息,前者負責保持呼叫,後者用于釋放呼叫。

呼叫同步僅考慮保持會話(Dialog)層面,不考慮事務(Transaction)層面,實作會話狀态同步有2個方法:

1.Master MCU和Slave MCU同時工作,Master MCU負責将運作期間産生的會話通知Slave MCU,後者根據消息建立會話,切換後即可直接使用。此方法需要對PJSIP協定棧進行一定程度的修改開發,有一定難度,但是好處是後續的業務(呼叫轉移、傳真等)可以開展;

在PJSIP協定棧中,維持一個會話(Dialog)所必須的資訊,除了最基本的Call-ID/from-tag/to-tag,還包括媒體資訊、位址資訊、路由資訊等大量資料,但是如果僅為了保持呼叫,那麼主備MCU闆間,僅需傳遞Call-ID/from-tag/to-tag以及資源占用情況即可。切換發生後,對目前呼叫的SIP消息的處理,想辦法跳過PJSIP的正常處理過程(因為狀态資料沒有同步過來,正常過程處理不下去)。所幸PJSIP協定棧可非常靈活的設定回調,可對第一點描述的消息編寫特定的回調函數,做一個正确的應答及處理。此方法相對簡單,但局限就是主備切換之後,除了通話保持正常以外,不能正常執行其它業務。

PJSIP

背景介紹

主要闆中運作PJSIP來實作基本通話功能,簡單介紹一下PJSIP:

PJSIP是一個開源的SIP協定庫,它實作了SIP、SDP、RTP、STUN、TURN和ICE。PJSIP作為基于SIP的一個多媒體通信架構提供了非常清晰的API,以及NAT穿越的功能。PJSIP具有非常好的移植性,幾乎支援現今所有系統:從桌面系統、嵌入式系統到智能手機。

軟體結構

首先是傳輸管理,負責接收和發送消息,然後将消息傳遞給endpoit,也就是消息分發子產品,然後endpoit按照優先級輪詢的分發給各個子產品(事務,UA,INV,APP),直到有子產品處理這個消息

解決思路

為了提高項目進度,選擇第二種方案:即主機闆成功建立一個dialog後,将主機闆生成dialog的所需要的參數值寫入到資料庫中,當切換為備用時,軟體初始化的時候,将資料庫中的參數值讀取并調用協定棧,還原主機闆的dialog。

存儲一個dialog所需要的資訊:

1.首先執行個體化一個dialog。

2.本地的URI

3.對端URI

4.本地的TAG

5.本地的CSEQ

6.本地CONTACR_URI

7.對端URI

8.對端CONTACR_URI

9.對端CSEQ

10.SECURE的值

11.CALL-ID

12.路由資訊

13.對端TAG

調試問題

1.在将主機闆的dialog參數還原到備闆上以後,本端(被叫)可以根據dialog來向遠端(主叫)發送結束會話消息,可以成功挂斷。但是遠端(主叫)主動發送結束會話消息時,本端(被叫)報錯,無法處理

解:通過日志列印查詢到,僅僅還原一個dialog是不夠的,因為在pjspi中,成功生成一個dialog後,系統會為這個dialog生成一個session,裡面存放了相關媒體協定和媒體消息,是以接下來就是處理如何建立一個session

2.通過看源碼,發現session裡面存儲了大量的資訊,通過主機闆序列化到資料庫,再反序列化有點複雜。通過pjsip協定棧知道他是分子產品的,我們還原的dialog,通過調用接口生成一個session,但是這個session裡面是空的,需要執行個體化,并且它是一個會話的狀态機。為了能使本端(被叫)可以正确處理遠端(主叫)發送結束會話消息,我采用取巧的方式,将協定棧裡session子產品改為了一個全局變量,然後通過接口,将我們還原dialog生成的session加入到這個子產品中,這樣,就可以正确處理遠端(主叫)的部分消息,完成了方案的實驗。