上一篇我们封装了科大讯飞接口实现了 UniMRCP ASR Plugin,这篇文章我们再简单说一下 TTS 的实现。
MRCP plugin
以下内容请参考《基于 UniMRCP 实现讯飞 ASR MRCP Server》:
- UniMRCP 的编译、安装运行
- UniMRCP plugin 的加载、调用流程
- UniMRCP plugin 的新建
- 讯飞 SDK 的导入
调用讯飞 API 实现 plugin
引用头文件
1 2 3 4 5 6 7 8 9 |
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include "qtts.h" #include "msp_cmn.h" #include "msp_errors.h" #include "mpf_buffer.h" |
channel 新增变量
新增 buffer 用于存放 TTS 转化后的语音:
1 2 3 4 |
struct xfyun_synth_channel_t { ... mpf_buffer_t *audio_buffer; } |
讯飞 login
因为编写 ASR plugin 的时候我们已经调用过,这里可以省略。
语音合成
跟 ASR 不同,TTS 的请求一下子就发送过来,没有一个长时间处理语音流的过程。所以我们把 session 的创建销毁直接放在一个处理过程中即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
static apt_bool_t xfyun_synth_text_to_speech(const char* src_text, const char* params, mpf_buffer_t *buffer) { int ret = -1; const char* sessionID = NULL; int synth_status = MSP_TTS_FLAG_STILL_HAVE_DATA; unsigned int audio_len = 0; sessionID = QTTSSessionBegin(params, &ret); if (MSP_SUCCESS != ret) { apt_log(APT_LOG_MARK, APT_PRIO_WARNING,"[xfyun] QTTSSessionBegin failed, error code: %d.", ret); return FALSE; } ret = QTTSTextPut(sessionID, src_text, (unsigned int)strlen(src_text), NULL); if (MSP_SUCCESS != ret) { apt_log(APT_LOG_MARK, APT_PRIO_WARNING,"[xfyun] QTTSTextPut failed, error code: %d.",ret); QTTSSessionEnd(sessionID, "TextPutError"); return FALSE; } apt_log(APT_LOG_MARK, APT_PRIO_WARNING,"[xfyun] 正在合成 ..."); while (1) { /* 获取合成音频 */ const void* data = QTTSAudioGet(sessionID, &audio_len, &synth_status, &ret); if (MSP_SUCCESS != ret) break; if (NULL != data) { mpf_buffer_audio_write(buffer, data, audio_len); } if (MSP_TTS_FLAG_DATA_END == synth_status) break; usleep(150*1000); //防止频繁占用CPU } if (MSP_SUCCESS != ret) { apt_log(APT_LOG_MARK, APT_PRIO_WARNING,"[xfyun] QTTSAudioGet failed, error code: %d.",ret); QTTSSessionEnd(sessionID, "AudioGetError"); return FALSE; } /* 合成完毕 */ ret = QTTSSessionEnd(sessionID, "Normal"); if (MSP_SUCCESS != ret) { apt_log(APT_LOG_MARK, APT_PRIO_WARNING,"[xfyun] QTTSSessionEnd failed, error code: %d.",ret); return FALSE; } return TRUE; } |
xfyun_synth_channel_request_dispatch
处理 SYNTHESIZER_SPEAK 消息时调用转换接口。转换完成后,调用如下接口触发媒体流事件:
1 |
mpf_buffer_event_write(synth_channel->audio_buffer, MEDIA_FRAME_TYPE_EVENT); |
传递语音流
xfyun_synth_stream_read
中读取 audio_buffer 中的语音流发送给客户端:
1 2 3 4 5 6 |
static apt_bool_t xfyun_synth_stream_read(mpf_audio_stream_t *stream, mpf_frame_t *frame) { ... mpf_buffer_frame_read(synth_channel->audio_buffer,frame); ... } |
修改配置文件
重新编译安装后,我们还需要修改配置文件,使用我们自己的 engine。编辑conf/unimrcpserver.xml
文件,启用我们自己的 engine:
1 2 |
<engine id="Demo-Synth-1" name="demosynth" enable="false"/> <engine id="XFyun-Synth-1" name="xfyunsynth" enable="true"/> |
运行后就可以看到 xfyunsynth 被加载了。
源码
GitHub:MRCP-Plugin-Demo,该 Demo 只是实现基本流程,还有很多可以完善的地方,如处理 synth 请求的参数。