文章目錄
- mrcp-plugin-with-freeswitch
- 主要目的 和技術援助方式
- 第一步安裝freeswitch
- 1.下載下傳 FreeSWITCH源碼:
- 2.安裝依賴庫
- 3.編譯安裝
- 4編譯運作
- 第二步 配置編譯UniMRCP Server
- 1.下載下傳 [UniMRCP Server Plugin Demo 源碼](https://github.com/reSipWebRTC/UniMRCP-with-freeswitch)
- 2.編譯準備環境
- 編譯可能出現錯誤, 注釋掉:107 ~ 109, getopt的set,其中存在不識别的option
- 編譯生成apr, apr-util, target path: ./libs
- 3.編譯安裝unimrcp
- 如果不能自動檢測apr,apr-util,請在configure中增加 option:--with-apr=/path/apr --with-apr-util=/path/apr-util/
- apr, apr-util由./build-dep-libs.sh 生成
- 4.測試運作(這時候可能你會遇到一個[問題](javascript:void(0)))這個問題一定要看
- 第三步 內建訊飛開放平台SDK
- 1.訊飛開發平台SDK下載下傳
- 2.plugin編寫與編譯
- 注意:在這個地方下載下傳無論是給還是筆者的百度雲盤此位置可能需要修改
- 第四步 配置與驗證
- 1.配置unimrcp子產品并自動加載;
- 編輯/usr/local/freeswitch-1.6/modules.conf檔案,找到要安裝的子產品,去掉前面的注釋符号#cd /usr/local/src/freeswitch
- 在/usr/local/freeswitch-1.6目錄下執行make mod_xxx-install指令,這樣就編譯相應子產品,并把編譯後的動态庫安裝的/usr/local/freeswitch/mod目錄下
- 編輯/usr/local/freeswitch/conf/autoload_configs/modules.conf.xml,去掉注釋符号,如果沒有發現對應子產品,則添加
- 2.設定profile檔案與conf檔案;
- 3.配置IVR與腳本。
- 測試:撥打5001測試一下:成功
mrcp-plugin-with-freeswitch
特别感謝Cotin 網站《建構簡單的智能客服系統》(一)、(二)、(三)對于建構過程的幫助,您在閱讀本教程前,可以先行閱讀這本書三篇文章,本教程基于此調整了建構順序,給出了更多的操作細節,錯誤處理以及其他建構描述。
主要目的 和技術援助方式
使用FreeSWITCH接受使用者手機呼叫,通過UniMRCP Server內建訊飛開放平台(xfyun)插件将使用者語音進行語音識别(ASR),并根據自定義業務邏輯調用語音合成(TTS),建構簡單的端到端語音呼叫中心。

第一步安裝freeswitch
1.下載下傳 FreeSWITCH源碼:
cd /usr/local/
git clone -b v1.6 https://freeswitch.org/stash/scm/fs/freeswitch.git freeswitch
缺包可在git粘貼複制
2.安裝依賴庫
yum install -y git gcc-c++ wgetalsa-lib-devel autoconf automake bison broadvoice-devel bzip2 curl-develdb-devel e2fsprogs-devel flite-devel g722_1-devel gdbm-devel gnutls-develilbc-devel ldns-devel libcodec2-devel libcurl libcurl-devel libedit-devellibidn-devel libjpeg-devel libmemcached-devel libogg-devel libssl-devellibsilk-devel libsndfile-devel libtheora-devel libtool libvorbis-devellibxml2-devel lua lua-devel lzo-devel mongo-c-driver-devel ncurses-develnet-snmp-devel openssl-devel opus-develpcre pcre-devel perl perl-libs perl-ExtUtils-Embed libzrtpcpp-devellibtiff-devel libX11-devel expat-devel pkgconfig portaudio-develpostgresql-devel python26-devel python-devel soundtouch-devel speex speex-develsqlite-devel unbound-devel unixODBC-devel libuuid-devel which yasm zlib-devel libdb-develuuid-devel @development-tools
3.編譯安裝
cd freeswitch/
# 先執行 bootstrap.sh,生成configure檔案
./bootstrap.sh
./configure --prefix=/usr/local/freeswitch
make & make install
make cd-sounds-install
make cd-moh-install
4編譯運作
cd /usr/local/freeswitch/bin
./freeswitch
5其他問題
筆者在centos7的時候遇到很多問題,感謝下列作者的貢獻
git源代碼:https://github.com/signalwire/freeswitch
freeswitch 中文語音:http://www.bubuko.com/infodetail-2905851.html
第二步 配置編譯UniMRCP Server
本次示例的UniMRCP Server在CentOS 7中進行源碼編譯安裝,感謝由Github使用者cotinyang提供的已經寫好的內建訊飛SDK的UniMRCP Server源碼。
1.下載下傳 UniMRCP Server Plugin Demo 源碼
連結: https://pan.baidu.com/s/1cUUK4q0LqZ5PhXtMK15i3Q 提取碼: z8ic 複制這段内容後打開百度網盤手機App,操作更友善哦
2.編譯準備環境
cd MRCP-Plugin-Demo/unimrcp-deps-1.5.0
編譯可能出現錯誤, 注釋掉:107 ~ 109, getopt的set,其中存在不識别的option
編譯生成apr, apr-util, target path: ./libs
./build-dep-libs.sh
注:1.過程中需要輸入兩次y,并确認;
3.編譯安裝unimrcp
cd unimrcp-1.5.0
./bootstrap
如果不能自動檢測apr,apr-util,請在configure中增加 option:–with-apr=/path/apr --with-apr-util=/path/apr-util/
apr, apr-util由./build-dep-libs.sh 生成
./configure
make & make install
4.測試運作(這時候可能你會遇到一個問題)這個問題一定要看
cd /usr/local/unimrcp/bin
./unimrcpserver -o 3
服務端啟動
[root@name /usr/local/unimrcp/bin]# ./unimrcpserver -o 3
.......省略
2021-08-24 17:02:28:224085 [INFO] Start Task [RTSP-Agent-1]
2021-08-24 17:02:28:224142 [INFO] Start Task [MRCPv2-Agent-1]
2021-08-24 17:02:28:224223 [INFO] Start Task [Media-Engine-1]
sres: /etc/resolv.conf: unknown option
2021-08-24 17:02:28:225218 [NOTICE] MRCP Server Started
在開一個黑框,上一個黑框不要動,使用client進行驗證
cd /usr/local/unimrcp/bin
./unimrcpclient
>help
usage:
- run [app_name] [profile_name] (run demo application)
app_name is one of 'synth', 'recog', 'bypass', 'discover'
profile_name is one of 'uni2', 'uni1', ...
examples:
run synth
run recog
run synth uni1
run recog uni1
- loglevel [level] (set loglevel, one of 0,1...7)
- quit, exit
輸入help回車,給出了使用方法,輸入run recog運作語音識别測試,run synth進行語音合成測試。
第三步 內建訊飛開放平台SDK
1.訊飛開發平台SDK下載下傳
由于從訊飛開放平台下載下傳的SDK包和使用者以及使用者建立的應用相關聯,是以需要将third-party/xfyun中的檔案和檔案夾全部删除,重新下載下傳解壓屬于自己的SDK,目錄與源代碼基本一緻。
您需要注冊并登入 訊飛開放平台 ,進入控制台頁面,并建立應用;
在“我的應用”界面獲得你的APPID,并為該應用“添加新服務”,選擇需要的“語音聽寫”和”線上語音合成“服務(本示例需要);
點選右側“SDK下載下傳”,在跳轉頁面中确認“選擇應用”已經選中了您建立的應用,“選擇您需要的AI能力”選中上述兩項服務,并點選“SDK下載下傳”等待SDK生成與完成下載下傳。
将下載下傳的zip包,解壓并替換MRCP-Plugin-Demo/unimrcp-1.5.0/plugins/third-party/xfyun/下的所有檔案及檔案夾。
注:建立應用頁面中的應用平台選擇“Linux”。
2.plugin編寫與編譯
本步驟将告訴您如何編寫unimrcp的插件代碼,即現在MRCP-Plugin-Demo/unimrcp-1.5.0/plugins檔案夾下xfyun_recog、xfyun_xynth檔案夾下的檔案及其相關配置是如何得到的,如果您目前還不關注此細節,可以跳過本步驟至第四步。
實際上,上述MRCP-Plugin-Demo代碼是在 Unimrcp官網 下載下傳 Unimrcp 1.5.0 和 Unimrcp Deps 1.5.0 并在此基礎上添加的plugin代碼。
首先編輯configure.ac檔案,會在後面的Makefile中使用到的宏定義。XFyun recognizer plugin的添加如下:
dnl XFyun recognizer plugin.
UNI_PLUGIN_ENABLED(xfyunrecog)
AM_CONDITIONAL([XFYUNRECOG_PLUGIN],[test "${enable_xfyunrecog_plugin}" = "yes"])
...
plugins/xfyun-recog/Makefile
...
echo XFyun recognizer plugin....... : $enable_xfyunrecog_plugin
注:其中 ··· 是該檔案中的其它預設配置,請找到對應位置填寫。
對應地,XFyun synthesizer plugin的添加如下:
dnl XFyun synthesizer plugin.
UNI_PLUGIN_ENABLED(xfyunsynth)
AM_CONDITIONAL([XFYUNSYNTH_PLUGIN],[test "${enable_xfyunsynth_plugin}" = "yes"])
···
plugins/xfyun-synth/Makefile
···
echo XFyun synthesizer plugin...... : $enable_xfyunsynth_plugin
新增源碼與目錄
在 plugins 目錄下,建立 xfyun-recog 目錄,并在該目錄下建立 src 目錄,可以将 demo_recog_engine.c 拷貝到該目錄下改名為 xfyun_recog_engine.c,将xfyun_recog_engine.c檔案進行修改(已知一個修改的部分:将appid修改成你自己下載下傳sdk的appid,不然會報錯:QISRAudioWrite failed! error code:10407),xfyun-synth目錄下對應建立并修改。
static apt_bool_t xfyun_login()
{
int ret = MSP_SUCCESS;
const char* login_params = "appid = XXXXX, work_dir = ."; // 登入參數,appid與msc庫綁定,請勿随意改動
/* 使用者登入 */
ret = MSPLogin(NULL, NULL, login_params); //第一個參數是使用者名,第二個參數是密碼,均傳NULL即可,第三個參數是登入參數
if (MSP_SUCCESS != ret)
{
apt_log(RECOG_LOG_MARK,APT_PRIO_ERROR,"[xfyun] MSPLogin failed , Error code %d.", ret);
return FALSE; //登入失敗,登出
}
apt_log(RECOG_LOG_MARK,APT_PRIO_INFO,"[xfyun] MSPLogin success");
return TRUE;
}
在xfyun-recog檔案夾下建立Makefile.am檔案,内容如下:
AM_CPPFLAGS = $(UNIMRCP_PLUGIN_INCLUDES)
plugin_LTLIBRARIES = xfyunrecog.la
xfyunrecog_la_SOURCES = src/xfyun_recog_engine.c
xfyunrecog_la_LDFLAGS = $(UNIMRCP_PLUGIN_OPTS) \
-L$(top_srcdir)/plugins/third-party/xfyun/libs/x64 \
-lmsc -ldl -lpthread -lrt -lstdc++
xfyunrecog_ladir = $(libdir)
xfyunrecog_la_DATA = $(top_srcdir)/plugins/third-party/xfyun/libs/x64/libmsc.so
include $(top_srcdir)/build/rules/uniplugin.am
UNIMRCP_PLUGIN_INCLUDES += -I$(top_srcdir)/plugins/third-party/xfyun/include
對應地,在fyun-synth檔案夾下建立Makefile.am檔案夾,内容如下:
AM_CPPFLAGS = $(UNIMRCP_PLUGIN_INCLUDES)
plugin_LTLIBRARIES = xfyunsynth.la
xfyunsynth_la_SOURCES = src/xfyun_synth_engine.c
xfyunsynth_la_LDFLAGS = $(UNIMRCP_PLUGIN_OPTS) \
-L$(top_srcdir)/plugins/third-party/xfyun/libs/x64 \
-lmsc -ldl -lpthread -lrt
xfyunsynth_ladir = $(libdir)
include $(top_srcdir)/build/rules/uniplugin.am
UNIMRCP_PLUGIN_INCLUDES += -I$(top_srcdir)/plugins/third-party/xfyun/include
修改plugins檔案夾下Makefile.am檔案,xfyun-recog添加内容如下:
if XFYUNRECOG_PLUGIN
SUBDIRS += xfyun-recog
endif
對應地,xfyun-synth添加内容如下:
if XFYUNRECOG_PLUGIN
SUBDIRS += xfyun-synth
endif
修改conf/unimrcpserver.xml檔案,從預設啟用demo engine改為啟用我們的兩個engine。
xfyun-recog修改如下:
注意:在這個地方下載下傳無論是給還是筆者的百度雲盤此位置可能需要修改
<engine id="Demo-Recog-1" name="demorecog" enable="false"/>
<engine id="XFyun-Recog-1" name="xfyunrecog" enable="true"/>
對應地,xfyun-synth修改如下:
<engine id="Demo-Synth-1" name="demorecog" enable="false"/>
<engine id="XFyun-Synth-1" name="xfyunsynth" enable="true"/>
同時,如果您已經準備好将UniMRCP Server和FreeSWITCH對接,您應該在conf/unimrcpserver.xml中配置好server的ip位址,即目前unimrcp安裝的子網通路位址。
重新編譯安裝unimrcp(第二步 3)。
當你啟動時出現如下問題時:
Failed to Load DSO: /usr/local/unimrcp/lib/libmsc.so: undefined symbol: _ZTVN10__cxxabiv117__class_type_infoE
方法:-lstdc++
筆者親測遇到了一個libsofia-sip-ua.so.0 不存在的一個情況
./unimrcpserver: error while loading shared libraries: libsofia-sip-ua.so.0: cannot open shared object file: No such file or directory
方法
在etc/ld.so.conf 内容增加: /usr/local/lib
ldconfig 将ld.so.conf讀入cache
注:替換unimrcp的VAD子產品
unimrcp vad 子產品voice activity dector一直認為比較粗暴,而且unimrcp的社群也很久沒有更新了。使用原始unimrcp如果隻是用來做Demo示範,通過手動調整參數,還是可以的。但是距離生産環境,還是有很遠的一段路。故可以替換成webrtc的vad子產品。
參考下面連結,本項目已經替換成webrtc的vad子產品,無需再修改。
第四步 配置與驗證
配置
配置FreeSWITCH
我們需要将處理使用者語音呼入的FreeSWITCH與向xfyun engine發請求的unimrcp server兩者連接配接起來。
1.配置unimrcp子產品并自動加載;
編輯/usr/local/freeswitch-1.6/modules.conf檔案,找到要安裝的子產品,去掉前面的注釋符号#cd /usr/local/src/freeswitch
vim modules.conf
#asr_tts/mod_unimrcp
asr_tts/mod_unimrcp
在/usr/local/freeswitch-1.6目錄下執行make mod_xxx-install指令,這樣就編譯相應子產品,并把編譯後的動态庫安裝的/usr/local/freeswitch/mod目錄下
make mod_unimrcp-install
編輯/usr/local/freeswitch/conf/autoload_configs/modules.conf.xml,去掉注釋符号,如果沒有發現對應子產品,則添加
<load module="mod_unimrcp"/>
2.設定profile檔案與conf檔案;
在/usr/local/freeswitch/conf/mrcp_profiles目錄建立unimrcpserver-mrcp-v2.xml配置檔案:
這裡的ip如果你是centos等線上伺服器:ifconfig檢視 :筆者曾一度認為是我連接配接伺服器的ip位址,其實是不對的
<include>
<!-- UniMRCP Server MRCPv2 -->
<!-- 後面我們使用該配置檔案,均使用 name 作為唯一辨別,而不是檔案名 -->
<profile name="unimrcpserver-mrcp2" version="2">
<!-- MRCP 伺服器位址 -->
<param name="server-ip" value="XXX.XX.XX.XX"/>
<!-- MRCP SIP 端口号 -->
<param name="server-port" value="8060"/>
<param name="resource-location" value=""/>
<!-- FreeSWITCH IP、端口以及 SIP 傳輸方式 -->
<param name="client-ip" value="XXX.XX.XX.XX" />
<param name="client-port" value="5069"/>
<param name="sip-transport" value="udp"/>
<param name="speechsynth" value="speechsynthesizer"/>
<param name="speechrecog" value="speechrecognizer"/>
<!--param name="rtp-ext-ip" value="auto"/-->
<param name="rtp-ip" value="XXX.XX.XX.XX"/>
<param name="rtp-port-min" value="4000"/>
<param name="rtp-port-max" value="5000"/>
<param name="codecs" value="PCMU PCMA L16/96/8000"/>
<!-- Add any default MRCP params for SPEAK requests here -->
<synthparams>
</synthparams>
<!-- Add any default MRCP params for RECOGNIZE requests here -->
<recogparams>
<!--param name="start-input-timers" value="false"/-->
</recogparams>
</profile>
</include>
配置/usr/local/freeswitch/conf/autoload_configs/unimrcp.conf.xml檔案:
<configuration name="unimrcp.conf" description="UniMRCP Client">
<settings>
<!-- UniMRCP profile to use for TTS -->
<param name="default-tts-profile" value="unimrcpserver-mrcp2"/>
<!-- UniMRCP profile to use for ASR -->
<param name="default-asr-profile" value="unimrcpserver-mrcp2"/>
<!-- UniMRCP logging level to appear in freeswitch.log. Options are:
EMERGENCY|ALERT|CRITICAL|ERROR|WARNING|NOTICE|INFO|DEBUG -->
<param name="log-level" value="DEBUG"/>
<!-- Enable events for profile creation, open, and close -->
<param name="enable-profile-events" value="false"/>
<param name="max-connection-count" value="100"/>
<param name="offer-new-connection" value="1"/>
<param name="request-timeout" value="3000"/>
</settings>
<profiles>
<X-PRE-PROCESS cmd="include" data="../mrcp_profiles/*.xml"/>
</profiles>
</configuration>
注:1.unimrcpserver-mrcp-v2.xml中server-ip為unimrcpserver啟動的主機ip;2.client-ip和rtp-ip為FreeSWITCH啟動的主機,client-port仕FreeSWITCH作為用戶端通路unimrcpserver的端口,手機作為用戶端通路的FreeSWITCH端口預設為5060,兩者不同;3.unimrcpserver-mrcp-v2.xml中的profile name應和unimrcp.conf.xml中的default-tts-profile與default-ars-profile的value一緻(有些文檔的分析中稱mrcp_profiles中的xml檔案名也必須和這兩者一緻,實際上是非必須的)。
Attenion: unimrcpserver 和 freeswitch 部署在同一個網段很重要,最好部署測試的時候在同一台實體機器上進行
3.配置IVR與腳本。
在/usr/local/freeswitch/conf/dialplan/default.xml裡新增如下配置:
<extension name="unimrcp">
<condition field="destination_number" expression="^5001$">
<action application="answer"/>
<action application="lua" data="names.lua"/>
</condition>
</extension>
在/usr/local/freeswitch/scripts目錄下新增names.lua腳本:
session:answer()
--freeswitch.consoleLog("INFO", "Called extension is '".. argv[1]"'\n")
welcome = "ivr/ivr-welcome_to_freeswitch.wav"
menu = "ivr/ivr-this_ivr_will_let_you_test_features.wav"
--
grammar = "hello"
no_input_timeout = 80000
recognition_timeout = 80000
confidence_threshold = 0.2
--
session:streamFile(welcome)
--freeswitch.consoleLog("INFO", "Prompt file is \n")
tryagain = 1
while (tryagain == 1) do
--
session:execute("play_and_detect_speech",menu .. "detect:unimrcp {start-input-timers=false,no-input-timeout=" .. no_input_timeout .. ",recognition-timeout=" .. recognition_timeout .. "}" .. grammar)
xml = session:getVariable('detect_speech_result')
--
if (xml == nil) then
freeswitch.consoleLog("CRIT","Result is 'nil'\n")
tryagain = 0
else
freeswitch.consoleLog("CRIT","Result is '" .. xml .. "'\n")
tryagain = 0
end
end
--
-- put logic to forward call here
--
session:sleep(250)
session:set_tts_params("unimrcp", "xiaofang");
session:speak("今天天氣不錯啊");
session:hangup()
我們需要在/usr/local/freeswitch/grammar目錄新增hello.gram文法檔案,可以為空文法檔案須滿足語音識别文法規範1.0标準(簡稱 SRGS1.0),該文法檔案 ASR 引擎在進行識别時可以使用。
<?xml version="1.0" encoding="utf-8" ?>
<grammar version="1.0" xml:lang="zh-cn" root="Menu" tag-format="semantics/1.0"
xmlns=http://www.w3.org/2001/06/grammar
xmlns:sapi="http://schemas.microsoft.com/Speech/2002/06/SRGSExtensions"><!- 這些都是必不可少的-->
<rule id="city" scope="public">
<one-of> <!-- 比對其中一個短語-->
<item>北京</item>
<item>上海</item>
</one-of>
</rule>
<rule id="cross" scope="public">
<one-of>
<item>到</item>
<item>至</item>
<item>飛往</item>
</one-of>
</rule>
<rule id="Menu" scope="public">
<item>
<ruleref uri="#date"/> <!--指定關聯的其他規則的節點-->
<tag>out.date = reles.latest();</tag>
</item>
<item repeat="0-1">從</item> <!--顯示1次或0次-->
<item>
<ruleref uri="#city"/>
<tag>out.city = rulels.latest();</tag>
</item>
<item>
<ruleref uri="#cross"/>
<tag>out.cross = rulels.latest();</tag>
</item>
<item>
<ruleref uri="#city"/>
<tag>out.city = rulels.latest();</tag>
</item>
</rule>
</grammar>
注:lua腳本中,”play_and_detect_speech” 調用了 ASR 服務,”speak” 調用了 TTS 服務。配置啟動中遇到問題。
配置啟動中遇到問題:https://www.jianshu.com/p/6aa2140937b2
測試:撥打5001測試一下:成功
FreeSWITCH首頁:https://freeswitch.com/
Unimrcp首頁:http://www.unimrcp.org/
Apache APR:https://apr.apache.org/
訊飛SDK包導入方式:https://doc.xfyun.cn/msc_linux/SDK%E5%8C%85%E5%AF%BC%E5%85%A5.html