freeswitch原生支持的tts功能中文一般是使用的ekho,但是那合成的效果简直惨不忍睹,于是我想自己做一个TTS服务器。
首先是找到比较满意的TTS引擎,科大讯飞的效果当然是没话说,但是价格不菲,其他商业的引擎中文合成也不是很流畅,偶然发现windows7自带的合成引擎还算过得去,windows10带的合成引擎就更好了(有兴趣的可以先测试一下,直接在windows控制面板中的语音设置里面有测试,但是测试的中英文混读很蛋疼)。
那么问题来了,怎么把这个引擎用到我的FS上边呢?
思路,debian上的freeswitch(后续简称de-FS)需要TTS的时候,通过桥接到另外一个windows版本的freeswitch(后续简称win-FS),在SIP消息X-header中附加上需要合成的文字,然后win-FS接收到文字后,通过lua脚本调用一个应用程序转换成语音文件,win-FS再播放出来,这样呼入原de-FS的主叫就听到了文本转换后的语音了。
折腾了一个星期,终于把这个TTS服务搭建好了,分享出来,顺便记一下,免得下次要用时找不到。
废话不多说了,直接上脚本(注:de-FS使用fusionpbx搭建的,数据源调用直接用了fusionpbx的方法,深究的可以搭一个fusionpbx查查里面的脚本)
1、de-FS端查数、外呼、转接脚本:
function createIconv(from,to,text) -- 本函数用于将utf8编码和gbk编码相互转换 -- apt-get install lua-iconv #需要先安装lua-iconv local iconv = require("iconv") local cd = iconv.new(to .. "//TRANSLIT", from) local ostr, err = cd:iconv(text) if err == iconv.ERROR_INCOMPLETE then return "ERROR: Incomplete input." elseif err == iconv.ERROR_INVALID then return "ERROR: Invalid input." elseif err == iconv.ERROR_NO_MEMORY then return "ERROR: Failed to allocate memory." elseif err == iconv.ERROR_UNKNOWN then return "ERROR: There was an unknown error." end return ostr end function inser_str_for(in_num) --本函数用在长串数字中插入空格 if in_num == nil then out_str = 'error in_num' else -- print("正在转换:" .. in_num .. "\n") in_num_len = string.len(in_num) tmp_str = string.sub(in_num,1,1) for start_len=2,in_num_len,1 do sub_str = string.sub(in_num,start_len,start_len) tmp_str = tmp_str .. " " .. sub_str end out_str = tmp_str end return out_str end -- require "resources.functions.config"; local Database = require "resources.functions.database"; dbh = Database.new('switch'); --调用freeswitch数据库 api = freeswitch.API(); session:answer(); if (session:ready() == true) then -- orderid = session:playAndGetDigits(8, 8, 3, 5000, '#', 'first sound:#', 'error_try sound', '\\d+|#'); orderid = session:playAndGetDigits(12, 12, 3, 8000, '#', 'misc/enter_carryid.wav', 'misc/erro_carryid.wav', '\\d+|#') end if (orderid== nil) then error_code = 0 else error_code = 1 end if (error_code == 1) then session:execute( "playback", "misc/carry_querying.wav" ) local params = {carry_id_in = orderid} local sql = "SELECT * from carry_staut t where t.carry_id= :carry_id_in;" dbh:query(sql, params, function(row) carry_staut = row.info; --返回字段映射 end); if carry_staut==nil then session:streamFile("misc/erro_carryid.wav") else -- out_orderid=inser_str_for(orderid) -- 当使用微软音库时需转换 out_orderid=orderid -- 当使用"VM Hui"音库时无需转换 tts_text = "您好,单号:" .. out_orderid ..",7月11日,您从广州寄往深圳的快件当前状态:".. carry_staut ..",签收人李先生,感谢使用顺丰!" tts_text = createIconv("utf-8","gbk",tts_text) --调用函数将字符集转换为gbk session:setVariable("sip_h_X-Text",tts_text) tts_session = freeswitch.Session("sofia/gateway/80fd35d7-d767-4fb3-907f-72daaa7896ea/1098", session) if (tts_session:ready() == true) then freeswitch.bridge(session,tts_session) tts_session:hangup() end end else session:streamFile("misc/erro_carryid.wav") end session:sleep(500) local digits = session:playAndGetDigits(1, 1, 3, 8000, '', 'misc/continue_carryid.wav', 'ivr/ivr-that_was_an_invalid_entry', '[\\d{1}|*]') if (digits == "1") then session:execute("transfer","6200"); else i