什么是嵌入式腳本?
其實(shí)前面我們學(xué)到的 XML dialplan 已經(jīng)體現(xiàn)了其非凡的配置能力,它配合 FreeSWITCH 提供的各種 App 也可以認(rèn)為是一種腳本。當(dāng)然,畢竟 XML 是一種描述語言,功能還有限。FreeSWITCH 通過嵌入其它語言的解析器支持很多流行的編程語言。
一般來說,編程語言分為兩種:編譯型語言(如C)和解釋型語言(如 javascript,perl 等)。使用解釋型語言編寫出來的腳本不需要編譯,因而非常靈活方便。典型地,F(xiàn)reeSWITCH 支持的語言有:
- Lua
- Javascript
- Python
- Perl
- Java
其它腳本語言如 Php, Ruby 以前是支持的,由于它們有內(nèi)存及性能問題,且沒有志愿者維護(hù),現(xiàn)在已經(jīng)被列為 Unsupported 了。
應(yīng)用場景
一般來說,這些嵌入式腳本主要用于寫 IVR,即主要用來控制一路通話的呼叫流程。雖然它們也可以控制多路通話(在后面我們也會講到這樣的例子,但這不是他們擅長的功能。
當(dāng)然,這里說的一路通話不是說它們只能控制唯一一路通話。以 Lua 為例,你可以把呼叫路由到一個(gè) lua 腳本,當(dāng)有電話進(jìn)來時(shí),F(xiàn)reeSWITCH 會為每一路通話啟動一個(gè)線程,控制每一路通話的 lua 腳本則在相應(yīng)的線程內(nèi)執(zhí)行,互不干擾。Java 語言需要 Java 的虛擬機(jī)環(huán)境,比這個(gè)要復(fù)雜些。
Lua
這是一門小眾語言,聽起來,它可能不像其它語言(如 Java)那樣“如雷貫耳”,但由于其優(yōu)雅的語法及小巧的身段受到很多開發(fā)者的青睞,尤其是在游戲領(lǐng)域(我相信有很多人知道它是緣于2010年一則新聞中說一個(gè)14歲的少年用它編出了 iPhone 上的名為 Bubble Ball 的游戲,該游戲下載量曾一度超過史上最流行的“憤怒的小鳥”)。
在 FreeSWITCH 中,Lua 模塊是默認(rèn)加載的。在所有嵌入式腳本語言中,它是最值得推薦的語言。首先它非常輕量級,mod_lua.so 經(jīng)過減肥(strip)后只有272K;另外,它的語法也是相的的簡單。有人做過對比說,在嵌入式的腳本語言里,如果 Python 得 2 分,Perl 拿 4,Javascript 得 5, 則 Lua 語言可得 10 分?梢娨话。
另外, Lua 模塊的文檔也是最全的。寫其它語言的程序好多時(shí)候都需要參照 Lua 模塊的文檔。
語法簡介
Lua 語言的注釋為 “--” 開頭(單行),或 “--[[ ]]”(多行)。
Lua 變量不需要類型聲明
Lua 支持類似面向?qū)ο蟮木幊,所有對象都是一個(gè) Table(Lua 中獨(dú)有的概念)。
Lua 支持尾遞歸、閉包。
詳細(xì)的資料請參閱有關(guān)資料,底線是 -- 如果你會其它編程語言,在 30 分鐘內(nèi)就能學(xué)會它。
將電話路由到 Lua 腳本
在 dialplan XML 中,使用
<action application="lua" data="test.lua"/>
便可將進(jìn)入 dialplan 的電話交給 lua 腳本接管。腳本的默認(rèn)路徑是安裝路徑的 scripts/ 目錄下,當(dāng)然你也可以指定絕對路徑,如 /tmp/test.lua。需要注意在 windows 下目錄分隔符是用 "\" ,所以有時(shí)候需要兩個(gè),如“c:\test\test.lua”。
Session 相關(guān)函數(shù)
FreeSWITCH 會自動生成一個(gè) session 對象(實(shí)際上是一個(gè) table),因而可以使用 Lua 面象對象的特性編程,如以下腳本放播放歡迎聲音(來自 Hello Lua) 。
-- answer the call
session:answer();
-- sleep a second
session:sleep(1000);
-- play a file
session:streamFile("/tmp/hello-lua.wav");
-- hangup
session:hangup();
大部分跟 session 有關(guān)的函數(shù)是跟 FreeSWITCH 中的 App 是一一對應(yīng)的,如上面的 answer()、hangup() 等,特別的, streamFile() 對應(yīng) playback() App 。如果沒有對應(yīng)的函數(shù),也可以通過 session:execute() 來執(zhí)行相關(guān)的 App,如 session:execute("playback", "/tmp/sound.wav") 等價(jià)于 session:streamFile("/tmp/sound.wav")。
需要注意,lua 腳本執(zhí)行完畢后默認(rèn)會掛斷電話,所以上面的 Hello Lua 例子中不需要明確的 session:hangup()。如果想在 lua 腳本執(zhí)行完畢后繼續(xù)執(zhí)行 dialplan 中的后續(xù)流程,則需要在腳本開始處執(zhí)行
session:setAutoHangup(false)
如下列場景,test.lua 執(zhí)行完畢后(假設(shè)沒有 session:hangup(),主叫也沒有掛機(jī)),如果沒有 setAutoHangup(false),則后續(xù)的 playback 動作得不到執(zhí)行。
<extension name="eavesdrop">
<condition field="destination_number" expression="^1234$">
<action application="answer"/>
<action application="lua" data="test.lua"/>
<action application="playback" data="lua-script-complete.wav"/>
</condition>
</extension>
更多的函數(shù)可以參考相關(guān)的 wiki 文檔:http://wiki.freeswitch.org/wiki/Mod_lua