Linux下 python调用讯飞离线语音合成(tts)

Linux下,使用Python调用讯飞TTS离线SDK,源代码:

  • https://github.com/cch96/iflytek_tts
  • 具体使用方法参照readme

解决过程

Windows

Windows的SDK有编译好的可以直接被python用ctypes模块调用的动态链接库。可以直接根据科大讯飞的接口文档以及错误码进行开发调试。

  • bin文件夹下的dll
    在这里插入图片描述
  • 接口文档: http://mscdoc.xfyun.cn/windows/api/iFlytekMSCReferenceManual/files.html
  • 错误码: https://www.xfyun.cn/document/error-code

Linux

Linux版的SDK没有编译好的so,但是Linux的SDK中有一些函数库的动态链接库。

  • libs文件夹下的so
    Linux下 python调用讯飞离线语音合成(tts)_第1张图片
于是开始尝试使用这个库来调用接口,实现功能。在此期间出现了一些问题。

问题1:
在导入libmsc.so时出现异常

	OSError: libs/x64/libmsc.so: undefined symbol: _ZTVN10__cxxabiv117__class_type_infoE

该异常是由于讯飞的tts是由c++实现了,需要链接c++的一些基础依赖库。这里是少了lstdc++.so
解决1:
ctypes中有两种加载动态链接库的方式ctype.CDLL() 或者ctypes.cdll.load_libary(),
CDLL有一个mode的可选参数,mode=ctypes.RTLD_GLOBAL,可以全局引入动态链接,如果调用的动态库有其它依赖库时,提前加载的功能
把lstdc++.so提前导入即可ctypes.CDLL("lstdc++.so", mode=ctypes.RTLD_GLOBAL)

问题2:
解决了依赖库问题,在调用接口时出现异常

	segmentation fault

段错误,访问了不存在或者受限的内存,这个问题涉及到ctypes与c的交互的内部机制,不好解决,于是换了个思路
解决2:
放弃原来的思路,即用ctypes调用动态链接库中的接口,完成语言合成的逻辑。
改用,用c封装语音合成的逻辑,由它去调用动态链接库中的函数,而python只需要简单调用这些c封装好的接口。
其实官方的sdk中的c语言demo是可用的,把它稍加改造就可以满足我们的要求,就不用自己封装了。

最终解决

  1. 官方demo改成接口模块,并编译成so

    $gcc -c -fPIC -o mylib.o tts_offline_sample.c
    $gcc -shared -o libtts.so mylib.o

  2. 将libstdc++.so, libmsc.so, libtts.so都加载进来

    def __new__(cls, *args, **kwargs):
        # 加载库
        ctypes.CDLL("libstdc++.so.6", mode=ctypes.RTLD_GLOBAL)
        plat = platform.architecture()
        if plat[0] == '32bit':
            dll = CDLL(os.path.join(WORK_ROOT, 'libs/x86/libmsc.so'), mode=ctypes.RTLD_GLOBAL)
        else:
            dll = CDLL(os.path.join(WORK_ROOT, 'libs/x64/libmsc.so'), mode=ctypes.RTLD_GLOBAL)
        cls.dll = cdll.LoadLibrary(os.path.join(WORK_ROOT, "libtts.so"))
        cls.lock = threading.RLock()
        return super(IflytekTTS, cls).__new__(cls)
    
    
  3. python去调用libtts.so中的接口

    def text2wav(self, text, filename):
    	"""文字合成语音"""
        # 底层的c是不支持多线程的,所以这里限制一下
        with self.lock:
            ret = self.dll.msp_login(None, None, self.login_params)
            if (self.MSP_SUCCESS != ret):
                # 如果登陆验证失败
                print("MSPLogin failed, error code: %d.\n", ret)
                return
            #  登陆成功
            # print("开始合成 ...\n")
            ret = self.dll.text_to_speech(text, filename, self.session_begin_params)
            # print("合成完毕\n")
            # 退出登录
            self.dll.msp_logout()
    
第一次写博客,若有哪里不对请大家斧正

参考

https://blog.csdn.net/weizehua/article/details/88305752
https://blog.csdn.net/u013783095/article/details/79639754
https://www.cnblogs.com/hello–the-world/archive/2012/05/31/2528326.html
https://www.landui.com/help/show-7989

你可能感兴趣的:(语音合成,python,tts,linux)