SIP 模塊是 FreeSWITCH 的主要模塊,所以,值得拿出專門一章來講解。
在前幾章時里,你肯定見過幾次 sofia 這個詞,只是或許還不知道是什么意思。是這樣的,Sofia-SIP 是由諾基亞公司開發的 SIP 協議棧,它以開源的許可證 LGPL 發布,為了避免重復發明輪子,FreeSWITCH 便直接使用了它。
在 FreeSWITCH 中,實現一些互聯協議接口的模塊稱為 Endpoint。FreeSWITH 支持很多的 Endpoint, 如 SIP、H232等。那么實現 SIP 的模塊為什么不支持叫 mod_sip呢?這是由于 FreeSWITCH 的 Endpoint 是一個抽象的概念,你可以用任何的技術來實現。實際上 mod_sofia 只是對 Sofia-SIP 庫的一個粘合和封裝。除 Sofia-SIP 外,還有很多開源的 SIP 協議棧,如 pjsip、osip 等。最初選型的時候,FreeSWITCH 的開發團隊也對比過許多不同的 SIP 協議棧,最終選用了 Sofia-SIP。FreeSWITCH 是一個高度模塊化的結構,如果你不喜歡,可以自己實現 mod_pjsip 或 mod_osip 等,它們是互不影響的。這也正是 FreeSWITCH 架構設計的精巧之處。
Sofia-SIP 遵循 RFC3261 標準,因而 FreeSWITCH 也是。
Sofia 的配置文件是 conf/autoload_configs/sofia.conf.xml,不過,你一般不用直接修改它,因為它實際上直接使用一條預處理指令裝入了 conf/sip_profiles/ 目錄中的 XML 文件:
<X-PRE-PROCESS cmd="include" data="../sip_profiles/*.xml"/>
所以,從現在起,可以認為所有的 Sofia 配置文件都在 conf/sip_profiles/ 中。
Sofia 支持多個 profile,而一個 profile 相當于一個 SIP UA,在啟動后它會監聽一個 “IP地址:端口” 對。讀到這里細心的讀者或許會發現我們前面的一個錯誤。我們在講 B2BUA 的概念時,實際上只用到了一個 profile,也就是一個 UA,但我們還是說 FreeSWITCH 啟動了兩個 UA(一對背靠背的 UA)來為 alice 和 bob 服務。是的,從物理上來講,它確實只是一個 UA,但由于它同時支持多個 Session,在邏輯上就是相當于兩個 UA,為了不使用讀者太糾結于這種概念問題中,我在前面沒有太多的分析。但到了本章,你應該非常清楚 UA 的含義了。
FreeSWITCH 默認的配置帶了三個 profile(也就是三個 UA),在這里,我們不討論 IPv6,因此只剩下 internal 和 external 兩個。 internal 和 external 的區別就是一個運行在 5060 端口上,另一個是在 5080 端口上。當然,還有其它區別,我們慢慢講。
internal.xml
internel.xml 定義了一個 profile,在本節,我們以系統默認的配置逐行來解釋:
<profile name="internal">
profile 的名字就叫 internal,這個名字本身并沒有特殊的意義,也不需要與文件名相同,你可以改成任何你喜歡的名字,只是需要記住它,因為很多地方要使用這個名字。
<aliases>
<!-- <alias name="default"/> -->
</aliases>
如果你喜歡,可以為該 profile 起一個別名。注意默認是加了注釋的,也就是說不起作用。再說一遍,“<!-- -->”在 XML 中的含義是注釋。
<gateways>
<X-PRE-PROCESS cmd="include" data="internal/*.xml"/>
</gateways>
即然 profile 是一個 UA,它就可以注冊到別的 SIP 服務器上去,它要注冊的 SIP 服務器就稱為 Gateway。我們一般不在 internal 這個 profile 上使用 Gateway,這個留到 external 時再講。
<domains>
<!--<domain name="$${domain}" parse="true"/>-->
<domain name="all" alias="true" parse="false"/>
</domains>
定義該 profile 所屬的 domain。它可以是 IP 地址,或一個 DNS 域名。需要注意,直接在 hosts 文件中設置的 IP-域名可能不好用。
<settings>
settings 部分設置 profile 的參數。
<!--<param name="media-option" value="resume-media-on-hold"/> -->
如果 FreeSWITCH 是沒有媒體(no media)的,那么如果設置了該參數,當你在話機上按下 hold 鍵時,FreeSWITCH 將會回到有媒體的狀態。
那么什么叫有媒體無媒體呢?如下圖,bob 和 alice 通過 FreeSWITCH 使用 SIP 接通了電話,他們談話的語音(或視頻)數據要通過 RTP 包傳送的。RTP 可以 像 SIP 一樣經過 FreeSWITCH 轉發,但是,RTP 占用很大的帶寬,如果 FreeSWITCH 不需要“偷聽”他們談話的話,為了節省帶寬,完全可以讓 RTP 直接在兩者間傳送,這種情況對 FreeSWITCH 來講就是沒有 media 的,在 FreeSWITCH 中也稱 bypass media(繞過媒體)。
FreeSWITCH
SIP / \ SIP
/ \
bob ------RTP------ alice
.
<!--<param name="media-option" value="bypass-media-after-att-xfer"/>-->
Attended Transfer 稱為出席轉移,它需要 media 才能完成工作。但如果在執行 att-xfer 之前沒有媒體,該參數能讓 att-xfer 執行時有 media,轉移結束后再回到 bypass media 狀態。
<!-- <param name="user-agent-string" value="FreeSWITCH Rocks!"/> -->
不用解釋,就是設置 SIP 消息中顯示的 User-Agent 字段。
<param name="debug" value="0"/>
debug 級別。
<!-- <param name="shutdown-on-fail" value="true"/> -->
由于各種原因(如端口被占用,IP地址錯誤等),都可能造成 UA 在初始化時失敗,該參數在失敗時會停止 FreeSWITCH。
<param name="sip-trace" value="no"/>
是否開啟 SIP 消息跟蹤。另外,也可以在控制臺上用以下命令開啟和關閉 sip-trace:
sofia profile internal siptrace on
sofia profile internal siptrace off
.
<param name="log-auth-failures" value="true"/>
是否將認證錯誤寫入日志。
<param name="context" value="public"/>
context 是 dialplan 中的環境。在此指定來話要落到 dialplan 的哪個 context 環境中。需要指出,如果用戶注冊到該 profile 上(或是經過認證的用戶,即本地用戶),則用戶目錄(directory)中設置的 contex 優先級要比這里高。
<param name="rfc2833-pt" value="101"/>
設置 SDP 中 RFC2833 的值。RFC2833 是傳遞 DTMF 的標準。
<param name="sip-port" value="$${internal_sip_port}"/>
監聽的 SIP 端口號,變量 internal_sip_port 在 vars.xml 中定義,默認是 5060。
<param name="dialplan" value="XML"/>
設置對應默認的 dialplan。我們后面會專門講 dialplan。
<param name="dtmf-duration" value="2000"/>
設置 DTMF 的時長。
<param name="inbound-codec-prefs" value="$${global_codec_prefs}"/>
支持的來話語音編碼,用于語音編碼協商。global_codec_prefs 是在 vars.xml中定義的。
<param name="outbound-codec-prefs" value="$${global_codec_prefs}"/>
支持的去話語音編碼。
<param name="rtp-timer-name" value="soft"/>