亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

FreeSWITCH 架構

系統 2286 0

從來章開始,我們正式開始我們的 FreeSWITCH 之旅。今后我們不再用單獨的章節來講述VoIP中的其它要素和概念,而是在用到時穿插于各個章節之中。

總體結構

FreeSWITCH 由一個穩定的核心及外圍模塊組成,下圖來自 FreeSWITCH Wiki:

FreeSWITCH 使用線程模型來處理并發請求,每個連接都在單獨的線程中進行處理。這不僅能提供最大強度的并發,更重要的是,即使某路電話發生問題,也只影響到它所在的線程,而不會影響到其它電話。FreeSWITCH 的核心非常短小精悍,這也是保持穩定的關鍵。所有其它功能都在外圍的模塊中。模塊是可以動態加載(以及卸載)的,在實際應用中可以只加載用到的模塊。外圍模塊通過核心提供的 Public API 與核心進行通信,而核心則通過回調機制執行外圍模塊中的代碼。

核心

FS Core 是 FreeSWITCH 的核心,它包含了關鍵的數據結構和復雜的代碼,但這些代碼只出現在核心中,并保持了最大限度的重用。外圍模塊只能通過 API 調用核心的功能,因而核心運行在一個受保護的環境中,核心代碼都經過精心的編碼和嚴格的測試,最大限度地保持了系統整體的穩定。

核心代碼保持了最高度的抽象,因而它可以調用不同功能,不同協議的模塊。同時,良好的 API 也使得編寫不同的外圍模塊非常容易。

數據庫

FreeSWITCH 的核心除了使用內部的隊列、哈希表存儲數據外,也使用外部的 SQL 數據庫存儲數據。當前,系統的核心數據庫使用 SQLite,默認的存儲位置是 db/core.db 。 使用外部數據庫的好處是--查詢數據不用鎖定內存數據結構,這不僅能提供性能,而且降低了死鎖的風險,保證了系統穩定。命令 show calls、show channels 等都是直接從數據庫中讀取內容并顯示的。由于 SQLite 會進行讀鎖定,因此不建議直接讀取核心數據庫。

系統對數據庫操作做了優化,在高并發狀態時,核心會盡量將幾百條 SQL 一齊執行,這大大提高了性能。但在低并發的狀態下執行顯得稍微有點慢,如一個 channel 已經建立了,但還不能在 show channels 中顯示;或者,一個 channel 已經 destroy 了,還顯示在 show channels 中。但由于這些數據只用于查詢,而不用于決策,所以一般沒什么問題。

除核心數據庫外,系統也支持使用 ODBC 方式連接其它數據庫,如 PostgreSQL、MySQL等。某些模塊,如 mod_sofia、mod_fifo等都有自己的數據庫(表)。如果在 *nix 類系統上使用 ODBC,需要安裝 UnixODBC,并進行正確的配置,如果編譯安裝的話還需要開發包 unixodbc-devel(CentOS) 或 unixodbc-dev(Debian/Ubuntu)。由于 PostgreSQL、MySQL 等都是 Client-Server 的結構,因此,外部程序可以直接查詢數據(但需要清楚數據的準確性,可能會比 FreeSWITCH 核心中的數據有所滯后)。

模塊

FreeSWITCH 主要分為以下幾個部分:

終點

End Points 是終結 FreeSWITCH 的地方,也就是說再往外走就超出 FreeSWITCH 的控制了。它主要包含了不同呼叫控制協議的接口,如 SIP, TDM 硬件,H323 以及 Google Talk 等。這使得 FreeSWITCH 可以與眾多不同的電話系統進行通信。如,可以使用 mod_skypopen 與 Skype 網絡進行通信。另外,前面也講過,它還可以通過 portaudio 驅動本地聲卡,用作一個軟電話。

撥號計劃

Dialplan 主要是為了查找電話路由,主要的是 XML 描述的,但它也支持 Asterisk 格式的配置文件。另外它也持 ENUM 查詢。

XML 接口

XML Interface 支持多種獲取 XML 配置的方式,它可以是本地的配置文件,或從數據庫中讀取,甚至是一個能動態返回 XML 的遠程 HTTP 服務器。

編解碼器

FreeSWITCH 支持最廣泛的 Codec,除了大多數 VoIP 系統支持的 G711、G722、G729、GSM 外,它還支持 iLBC,BV16/32、SILK、CELT等。它可以同時橋接不同采樣頻率的電話,以及電話會議等。

語音識別

支持語音自動識別(ASR)及文本-語音轉換(TTS)。

文件格式

支持不同的聲音文件格式,如 wav,mp3等。

日志

日志可以寫到控制臺、日志文件、系統日志(syslog)以及遠程的日志服務器。

嵌入式語言

通過 swig 包裝支持多種腳本語本語言控制呼叫流程,如 Lua、Javascript、Perl等。

事件套接字

使用 Event Socket 可以使用任何其它語言通過 Socket 方式控制呼叫流程、擴展 FreeSWITCH 功能。

目錄結構

在 *nix 類系統上,FreeSWITCH 默認的安裝位置是 /usr/local/freeswitch ,在 Windows 上可能是 C:/freeswitch ,目錄結構大致相同。

    
      bin         可執行程序
db          系統數據庫(sqlite),FreeSWITCH 把呼叫信息存放到數據庫里以便在查詢時無需對核心數據結構加鎖
htdocs      HTTP Web srver 根目錄
lib         庫文件
mod         可加載模塊
run         運行目錄,存放 PID
sounds      聲音文件,使用 playback() 時默認的尋找路徑
grammar     語法
include     頭文件
log         日志,CDR 等
recordings  錄音,使用 record() 時默認的存放路徑
scripts     嵌入式語言寫的腳本,如使用 lua()、luarun()、jsrun 等默認尋找的路徑
storage     語言留言(Voicemail)的錄音
conf        配置文件,詳見下節

    
  

配置文件

配置文件由許多 XML 文件組成。在系統裝載時,XML解析器會將所有XML文件組織在一起,并讀入內存,稱為XML注冊表。這種設計的好處在于其非常高的可擴展性。由于XML文檔本身非常適合描述復雜的數據結構,在 FreeSWITCH 中 就可以非常靈活的使用這些數據。并且,外部應用程序也可以很簡單地生成XML,FreeSWITCH 在需要時可以動態的裝載這些 XML。另外,系統還允許在某些 XML 節點上安裝回調程序(函數),當這些節點的數據變化時,系統便自動調用這些回調程序。

使用 XML 唯一的不足就是手工編輯這些 XML 比較困難,但正如 其作者所言 ,他絕對不是 XML 的粉絲,但這一缺點與它所帶來的好處相比是微不足道的。而且,將來也許會有圖形化的配置工具,到時候只所高級用戶會去看這些XML了。

目錄結構

配置文件的的目錄結構如下(其中結尾有 “/” 的為目錄):

    
      autoload_configs/
dialplan/
directory/
extensions.conf
freeswitch.xml
fur_elise.ttml
jingle_profiles/
lang/
mime.types
notify-voicemail.tpl
sip_profiles/
tetris.ttml
vars.xml
voicemail.tpl
web-vm.tpl

    
  

其中最重要的是 freeswitch.xml,就是它將所有配置文件“粘”到一起。只要有一點 XML 知識,這些配置是很容易看懂的。其中,X-PRE-PROCESS標簽稱為預處理命令,它用來設置一些變量和裝入其它配置文件。在 XML 加載階段,FreeSWITCH 的 XML 解析器會先將預處理命令進行展開,生成一個大的 XML 文件 log/freeswitch.xml.fsxml。該文件是一個內存鏡像,用戶不應該手工編輯它。但它對調試非常有用,假設你不慎弄錯了某個標簽,又不知道它在哪個地方,FreeSWITCH 在加載時就報 XML 的某一行出錯,在該文件中就行容易找到。

整個XML文件分為幾個重要的部分:configuration (配置)、dialplan (撥號計劃)、directory(用戶目錄)及phrase(分詞)。每一部分又分別裝入不同的 XML。

    
      小知識:XML
XML由標簽(Tag)和屬性構成。<tag> 和 </tag>組成一對標簽,如果該標簽有相關屬性,剛以
<tag attr="value"></tag> 形式指定。有些標簽無須配對,則必須以 “/>”關閉該標簽定義,
如<other/_tag attr="value"/>。

    
  

freeswitch.xml

    
      <?xml version="1.0"?>
<document type="freeswitch/xml">
    <!-- #comment 這是一個配置文件,本行是注釋 -->

    <X-PRE-PROCESS cmd="include" data="vars.xml"/>

    <section name="configuration" description="Various Configuration">
        <X-PRE-PROCESS cmd="include" data="autoload_configs/*.xml"/>
    </section>
</document>

    
  

上面是一個精減了的 freeswitch.xml。它的根是 document ,在 document 中,有許多 section ,每個 section 都對應一部分功能。其中有兩個 X-PRE-PROCESS 預處理指令,它們的作用是將 data 參數指定的文件包含( include )到本文件中來。由于它是一個預處理指令,FreeSWITCH 在加載階段只對其進行簡單替換,并不進行語法分析,因此,對它進行注釋是沒有效果的,這是一個新手常犯的錯誤。假設 vars.xml 的內容如下,它是一個合法的 XML:

    
      <!-- this is vars.xml -->
<var>xxxxx</var>

    
  

若你在調試階段想把一條 X-PRE-PROCESS 指令注釋掉:

    
      <!-- <X-PRE-PROCESS cmd="include" data="vars.xml"/> -->

    
  

當 FreeSWITCH 預處理時,還沒有到達 XML 解析階段,也就是說它還不認識 XML 注釋語法,而僅會機械地將預處理指令替換為 vars.xml 里的內容:

    
      <!-- <!-- this is vars.xml -->
<var>xxxxx</var> -->                                                  

    
  

由于 XML 的注釋不能嵌套,因此便產生錯誤的XML。解決辦法是破壞掉 X-PRE-PROCESS 的定義,如我常用下面兩種方法:

    
      <xX-PRE-PROCESS cmd="include" data="vars.xml"/>
<XPRE-PROCESS cmd="include" data="vars.xml"/>

    
  

由于 FreeSWITCH 不認識 xX-PRE-PROCESS 及 XPRE-PROCESS,因此它會忽略掉該行,相當于注釋掉了。

vars.xml

vars.xml 主要通過 X-PRE-PROCESS 指令定義了一些全局變量。全局變量以 $${var} 表示,臨時變量以 ${var} 表示。有些變量是系統在運行時自動獲取的,如默認情況下 $${base_dir} =/usr/local/freeswitch, $${local_ip_v4} =你機器的IP地址等。

autoload_configs 目錄

autoload_configs目錄下面的各種配置文件會在系統啟動時裝入。一般來說都是模塊級的配置文件,每個模塊對應一個。文件名一般以 模塊名.conf.xxml 方式命名。其中 modules.conf.xml 決定了 FreeSWITCH 啟動時自動加載哪些模塊。

dialplan 目錄

定義 XML 撥號計劃,我們會有專門的章節講解撥號計劃。

directory 目錄

它里面的配置文本決定了 FreeSWITCH 作為注冊服務器時哪些用戶可以注冊上來。FreeSWITCH 支持多個域(Domain),每個域可以寫到一個 XML 文件里。默認的配置包括一個 default.xml,里面定義了 1000 ~ 1019 一共 20 個用戶。

sip_profiles

它定義了 SIP 配置文件,實際上它是由 mod_sofia 模塊在 autoload_configs/sofia.conf.xml 中加載的。但由于它本身比較復雜又是核心的功能,因此單列了一個目錄。我們將會在后面加以詳細解釋。

XML 用戶目錄

XML 用戶目錄決定了哪些用戶可以注冊到 FreeSWITCH 上。當然,SIP 并不要求一定要注冊才可以打電話,但是用戶認證仍需要在用戶目錄中配置。

用戶目錄的默認配置文件在 conf/directory/,系統自帶的配置文件為 default.xml(其中 dial-string 一行由于排版要求人工換行,實際上不應該有換行):

    
      <domain name="$${domain}">
  <params>
    <param name="dial-string" value="{presence_id=${dialed_user}@${dialed_domain}}
        ${sofia_contact(${dialed_user}@${dialed_domain})}"/>
  </params>

  <variables>
    <variable name="record_stereo" value="true"/>
    <variable name="default_gateway" value="$${default_provider}"/>
    <variable name="default_areacode" value="$${default_areacode}"/>
    <variable name="transfer_fallback_extension" value="operator"/>
  </variables>

</domain>

    
  

該配置文件決定了哪些用戶能注冊到 FreeSWITCH 中。一般來說,所有用戶都應該屬于同一個 domain(除非你想使用多 domain,后面我們會有例子)。這里的 $${domain} 全局變量是在 vars.xml 中設置的,它默認是主機的 IP 地址,但也可以修改,使用一個域名。params 中定義了該 domain 中所有用戶的公共參數。在這里只定義了一個 dial-string,這是一個至關重要的參數。當你在使用 user/user_name 或 sofia/internal/user_name 這樣的呼叫字符串時,它會擴展成實際的 SIP 地址。其中 sofia_contact 是一個 API,它會根據用戶的注冊地址擴展成相應的呼叫字符串。

variables 則定義了一些公共變量,在用戶做主叫或被叫時,這些變量會綁定到相應的 Channel 上形成 Channel Variable。

在 domain 中還定義了許多組(group),組里面包含很多用戶(user)。

    
      <groups>
  <group name="default">
    <users>
      <X-PRE-PROCESS cmd="include" data="default/*.xml"/>
    </users>
  </group>
</groups>               

    
  

在這里,組名 default 并沒有什么特殊的意義,它只是隨便起的,你可以修改成任何值。在用戶標簽里,又使用預處理指令裝入了 default/ 目錄中的所有 XML 文件。你可以看到,在 default/ 目錄中,每個用戶都對應一個文件。

你也可以定義其它的用戶組,組中的用戶并不需要是完整的 XML 節點,也可以是一個指向一個已存在用戶的“指針”,如下圖,使用 type="pointer" 可以定義指針。

    
        <group name="sales">
    <users>
      <user id="1000" type="pointer"/>
      <user id="1001" type="pointer"/>
      <user id="1002" type="pointer"/>
    </users>
  </group>

    
  

雖然我們這里設置了組,但使用組并不是必需的。如果你不打算使用組,可以將用戶節點(users)直接放到 domain 的下一級。但使用組可以支持像群呼、代接等業務。使用 group_call 可以同時或順序的呼叫某個組的用戶。

實際用戶相關的設置也很直觀,下面顯示了 alice 這個用戶的設置:

    
      <user id="alice">
  <params>
    <param name="password" value="$${default_password}"/>
    <param name="vm-password" value="alice"/>
  </params>
  <variables>
    <variable name="toll_allow" value="domestic,international,local"/>
    <variable name="accountcode" value="alice"/>
    <variable name="user_context" value="default"/>
    <variable name="effective_caller_id_name" value="Extension 1000"/>
    <variable name="effective_caller_id_number" value="1000"/>
    <variable name="outbound_caller_id_name" value="$${outbound_caller_name}"/>
    <variable name="outbound_caller_id_number" value="$${outbound_caller_id}"/>
    <variable name="callgroup" value="techsupport"/>
  </variables>
</user>

    
  

由上面可以看到,實際上 params 和 variables 可以出現在 user 節點中,也可以出現在 group 或 domain 中。 當它們有重復時,優先級順序為 user,group,domain。

當然,用戶目錄還有一些更復雜的設置,我們留待以后再做研究。

呼叫流程及相關概念

再復習一下,FreeSWITCH是一個B2BUA,我們還是以第四章中的圖為例:

主要呼叫流程有以下兩種:

  • bob 向 FreeSWITCH 發起呼叫,FreeSWTICH 接著啟動另一個 UA 呼叫 alice,兩者通話;
  • FreeSWITCH 同時呼叫 bob 和 alice,兩者接電話后 FreeSWITCH 將 a-leg 和 b-leg 橋接(bridge)到一起,兩者通話。

其中第二種又有一種變種。如市場上有人利用上、下行通話的不對稱性賣電話回撥卡獲取不正當利潤:bob 呼叫 FreeSWITCH,FreeSWITCH 不應答,而是在獲取 bob 的主叫號碼后直接掛機;然后 FreeSWITCH 回撥 bob;bob 接聽后 FreeSWITCH 啟動一個 IVR 程序指示 bob 輸入 alice 的號碼;然后 FreeSWITCH 呼叫 Alice……

在實際應用中,由于涉及回鈴音、呼叫失敗等,實際情況要復雜的多。

Session 與 Channel

對每一次呼叫,FreeSWITCH 都會啟動一個 Session(會話,它包含SIP會話,SIP會在每對UAC-UAS之間生成一個 SIP Session),用于控制整個呼叫,它會一直持續到通話結束。其中,每個 Session 都控制著一個 Channel(信道),Channel 是一對 UA 間通信的實體,相當于 FreeSWITCH 的一條腿(leg),每個 Channel 都有一個唯一的 UUID。另外,Channel 上可以綁定一些呼叫參數,稱為 Channel Variable(信道變量)。Channel 中可能包含媒體(音頻或視頻流),也可能不包含。通話時,FreeSWITCH 的作用是將兩個 Channel(a-leg 和 b-leg,通常先創建的或占主動的叫 a-leg)橋接(bridge)到一起,使雙方可以通話。

通話中,媒體(音頻或視頻)數據流在 RTP 包中傳送(不同于 SIP, RTP是另外的協議)。一般來說,Channel是雙向的,因此,媒體流會有發送(Send/Write)和接收(Receive/Read)兩個方向。

回鈴音與 Early Media

    
      A  ------ |a 交換機 | ---X--- | 交換機 b| -------- B

    
  

為了便于說明,我們假定A與B不在同一臺服務器上(如在PSTN通話中可能不在同一座城市),中間需要經過多級服務器的中轉。

假設上圖是在 PSTN 網絡中,A 呼叫 B,B 話機開始振鈴,A 端聽回鈴音(Ring Back Tone)。在早期,B 端所在的交換機只給 A 端交換機送地址全(ACM)信號,證明呼叫是可以到達 B 的,A 端聽到的回鈴音鈴流是由 A 端所在的交換機生成并發送的。但后來,為了在 A 端能聽到 B 端特殊的回鈴音(如“您撥打的電話正在通話中…” 或 “對方暫時不方便接聽您的電話” 尤其是現代交換機支持各種個性化的彩鈴 - Ring Back Color Tone 等),回鈴音就只能由 B 端交換機發送。在 B 接聽電話前,回鈴音和彩鈴是不收費的(不收取本次通話費。彩鈴費用一般是在 B 端以月租或套餐形式收取的)。這些回鈴音就稱為 Early Media(早期媒體)。它是由 SIP 的183(帶有SDP)消息描述的。

理論上講,B 接聽電話后交換機 b 可以一直不向 a 交換機發送應答消息,而將真正的話音數據偽裝成 Early Media,以實現“免費通話”。

Channel Variable

在每一個 Channel 上都可以設置好多 Variable,稱為信道變量。FreeSWITCH 呼叫過程中,會根據這些變量控制 Channel 的行為。

$${var} 與 ${var}

${var} 是在 dialplan、application 或 directory 中設置的變量,它會影響呼叫流程并且可以動態的改變。而 $${var} 則是全局的變量,它僅在預處理階段(系統啟動時,或重新裝載 - reloadxml時)被求值。后者一般用于設置一些系統一旦啟動就不會輕易改變的量,如 $${domain} 或 $${local_ip_v4}等。所以,兩者最大的區別是,$${var} 只求值一次,而 ${var} 則在每次執行時求值(如一個新電話進來時)。

$variable_xxxx

你會發現,有些變量在顯示時(可以使用dp_tools 中的 info() 顯示,后面會講到)是以“variable_”開頭的,但在實際引用時要去掉這開頭的“variable_”。如“variable_user_name”,引用時要使用“${user_name}”。 http://wiki.freeswitch.org/wiki/Channel_Variables#variable_xxxx 列舉了一些常見的變量顯示與引用時的對應關系。

給 Variable 賦值

在 dialplan 中,有兩個程序可以給 Variable 賦值:

    
      <action application="set" data="my_var=my_value"/>
<action application="export" data="my_var=my_value"/>

    
  

以上兩條命令都可以設置 my_var 變量的值為 my_value。不同的是 -- set 程序僅會作用于“當前”的 Channel (a-leg),而 export 程序則會將變量設置到兩個 Channel (a-leg 和 b-leg)上,如果當時 b-leg 還沒有創建,則會在創建時設置。另外,export 還可以只將變量設置到 b-leg 上:

    
      <action appliction="export" data="nolocal:my_var=my_value"/>

    
  

在實際應用中,如果 a-leg 上已經有一些變量的值(如 var1、var2、var3),而想同時把這些變量都復制到 b-leg 上,可以使用以下幾種辦法:

    
      <action application="export" data="var1=$var1"/>
<action application="export" data="var2=$var2"/>
<action application="export" data="var3=$var3"/>

    
  

或者使用如下等價的方式:

    
      <action application="set" data="export_vars=var1,var2,var3">

    
  

所以,其實 set 也具有能往 b-leg 上賦值的能力,其實,它和 export 一樣,都是操作 export_vars 這個特殊的變量。

取消 Variable 定義

取消 Variable 定義只需對它賦一個特殊的值_undef_”:

    
      <action application="set" data="var1=_undef_">

    
  

截取 Variable 的一部分

可以使用特殊的語法取一個 Variable 的子串,格式是“${var:位置:長度}”。其中 “位置” 從 0 開始計烽,若為負數則從字符串尾部開始計數;如果“長度”為 0 或小于 0,則會從當前“位置”一直取到字符串結尾(或開頭,若“位置”為負的話)。例如 var 的值為 123456789,那么:

    
      ${var}      = 1234567890
${var:0:1}  = 1
${var:1}    = 234567890
${var:-4}   = 7890
${var:-4:2} = 78
${var:4:2}  = 56

    
  

小結

本章描述了 FreeSWITCH 的架構。到這里,讀者應該對 FreeSWITCH 有了一個總體的了解。我們也提到了一些基本元素和概念,簡單介紹了配置文件的基本結構,由于脫離了實際單講配置會比較抽象,因此,我們把具體的配置也寫到后面的章節里,即,用到時再說。

FreeSWITCH 架構


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 国产精品短视频 | 国内色视频 | 国产第一区二区三区在线观看 | www四虎| 久久视频免费 | 成年男女免费视频观看性 | 青草草在线观看免费视频 | 激情网址大全 | 日本一区二区三区四区 | 91精品91久久久久久 | 成人影院免费观看 | 亚洲欧美在线视频免费 | a一级黄 | 久久综合中文字幕一区二区三区 | 欧美一级黄色片在线观看 | 小视频国产| 国产成人免费网站在线观看 | 亚洲综合五月 | 99久久日本一区二区波多野结衣 | 香蕉久人久人青草青草 | 亚洲国产天堂 | 日本一级毛片免费看 | 国产丰满老厨女房乱 | 99热这里只有免费国产精品 | 97se视频| 久久精品视频8 | 97视频免费人人观看人人 | 波多野结衣一二区 | 日韩伦理一区二区 | 玖玖成人 | 特级一级黄色片 | 五月天婷婷在线视频国产在线 | 亚洲成人免费看 | 日产一二三四五六七区麻豆 | 午夜影院在线视频 | 日日干夜夜欢 | 久久精品天天中文字幕人 | 久久91精品综合国产首页 | 精品国产免费福利片 | 奇米影视狠狠久久中文 | 亚洲欧洲中文字幕 |