在与各类ASR等做对接时,总避免不了有些ASR没有一个更为标准的对接方式,有时就需要自己按mrcp协议去处理这些ASR识别引擎。
在这里我们采用unimrcp这个开源项目来作为识别中间件,对FreeSWITCH的语音部分通过unimrcp送给ASR识别引擎,然后识别引擎再把结果送到unimrcp后,由unimrcp再回送到FreeSWITCH结构大致如下:

在以上的开发流程中,我们结合了第三方语音机器人开发公司上海宁卫的检测模块的业务流程处理,结合unimrcp和第三方的MRCP服务器进行对接,ASR 服务器进行识别处理。
本之间我们先介绍下unimrcp这个开源项目。
这是一个基于RFC6787和RFC4463的跨平台mrcp的轻量实现,其跨平台是依赖apache apr库,而FreeSwitch的跨平台也是依赖于这一c实现库。在unimrcp中,还有以下一些第三方库:
- mpf - Media processing framework.
- mrcp - Implementation of MRCP basics (message, parser, resources).
- mrcpv2-transport - Implementation of the MRCPv2 transport layer.
- mrcp-signaling - Abstract MRCP signaling (session management) interface.
- mrcp-engine - Abstract resource engine interface.
- mrcp-client - Implementation of an MRCP client stack based on the abstract signaling interface.
- mrcp-server - Implementation of an MRCP server stack based on the abstract signaling and engine interfaces.
- uni-rtsp - Implementation of a minimal RTSP stack required for MRCPv1.
- Mrcp-sofia - Implementation of the abstract signaling interface using the SofiaSIP library.
以上的介绍都算是一些基本的知识要求,而在unimrcp如果要按我们的想法去实现相关的对接,则是去实现一个个的插件(plugin).在unimrcp中现在默认支持以下四种plugin:
- demo-synth - Implementation of a TTS plugin which simulates synthesis.
- demo-recog - Implementation of an ASR plugin which simulates recognition.
- demo-verif - Implementation of an SVI plugin which simulates speaker verification.
- mrcp-recorder - Implementation of a recorder plugin.
在我们现在的语音机器人开发中,我们仅使用了语音识别功能和语音合成功能。当然,语音合成或TTS也可以使用其他第三方的模块来进行处理。在这里recorder(录音)或verif(验证)对我们暂时不需要,因为我们供助FreeSwitch来实现recorder更容易,而verif对我们来说,基本没什么需求,都可以略过。那么我们讲讲如何实现和ASR进行编程进行对接。
在实现unimrcp的ASR插件时,要按它的标准去实现一些接口或方法。
定义的结构体
MRCP引擎维护的方法:
static const struct mrcp_engine_method_vtable_t engine_vtable = {
demo_recog_engine_destroy,
demo_recog_engine_open,
demo_recog_engine_close,
demo_recog_engine_channel_create
};
这里其实就是声明为函数的指针,其定义如下:
/** Table of MRCP engine virtual methods */
struct mrcp_engine_method_vtable_t {
apt_bool_t (*destroy)(mrcp_engine_t *engine);
apt_bool_t (*open)(mrcp_engine_t *engine);
apt_bool_t (*close)(mrcp_engine_t *engine);
mrcp_engine_channel_t* (*create_channel)(mrcp_engine_t *engine, apr_pool_t *pool);
};
按以上两个定义,我们可以看到,实际上就是针对mrcp的通道建立、数据传输、关闭、释放做对应的回调。
2. MRCP通道的维护方法:
static const struct mrcp_engine_channel_method_vtable_t channel_vtable = {
demo_recog_channel_destroy,
demo_recog_channel_open,
demo_recog_channel_close,
demo_recog_channel_request_process
};
同样需要考虑这个mrcp_engine_channel_method_vtable_t结构的具体实现,其定义如下:
/** Table of channel virtual methods */
struct mrcp_engine_channel_method_vtable_t {
apt_bool_t (*destroy)(mrcp_engine_channel_t *channel);
apt_bool_t (*open)(mrcp_engine_channel_t *channel);
apt_bool_t (*close)(mrcp_engine_channel_t *channel);
apt_bool_t (*process_request)(mrcp_engine_channel_t *channel, mrcp_message_t *request);
};
通过以上这个结构体实现的方法,来完成对于识别通道的维护。
3. 针对音频流的维护方法:
static const mpf_audio_stream_vtable_t audio_stream_vtable = {
demo_recog_stream_destroy,
NULL,
NULL,
NULL,
demo_recog_stream_open,
demo_recog_stream_close,
demo_recog_stream_write,
NULL
};
这是在mpf(media process framework)中定义的对于流媒体的处理接口要求,原结构:
/** Table of audio stream virtual methods */
struct mpf_audio_stream_vtable_t {
apt_bool_t (*destroy)(mpf_audio_stream_t *stream);
apt_bool_t (*open_rx)(mpf_audio_stream_t *stream, mpf_codec_t *codec);
apt_bool_t (*close_rx)(mpf_audio_stream_t *stream);
apt_bool_t (*read_frame)(mpf_audio_stream_t *stream, mpf_frame_t *frame);
apt_bool_t (*open_tx)(mpf_audio_stream_t *stream, mpf_codec_t *codec);
apt_bool_t (*close_tx)(mpf_audio_stream_t *stream);
apt_bool_t (*write_frame)(mpf_audio_stream_t *stream, const mpf_frame_t *frame);
void (*trace)(mpf_audio_stream_t *stream, mpf_stream_direction_e direction, apt_text_stream_t *output);
};
4. 接下来要实现一个引擎队列维护对象
struct demo_recog_engine_t {
apt_consumer_task_t *task;
};
5. 需要明确声明一个对通道进行识别的一个具体的对象
struct demo_recog_channel_t {
demo_recog_engine_t *demo_engine;
mrcp_engine_channel_t *channel;
mrcp_message_t *recog_request;
mrcp_message_t *stop_response;
apt_bool_t timers_started;
mpf_activity_detector_t *detector;
FILE *audio_out;
};
这里需要注意的是这里可以定义定时器timers_started,用来配合detector这个mpf的特性来完成语音的有效或者说活动性检测。
而audio_out可以完成录音性的东西。
需要完成的方法
- demo_recog_engine_channel_create 用来创建一个要进行识别的通道,基本以sip为主,通过信令来管理。
- demo_recog_stream_write 对于通过rtp送过来的数据,送给识别引擎进行处理,更为大量的工作是在这里进行处理。
- 通过业务逻辑对话术进行处理和逻辑判断。此部分的内容我们在后续的增加中会通过简单示例来演示如何使用MRCP协议实现外呼,通过语音识别结合语义匹配实现银行催收业务和教育培训业务的处理



unimrcp-MRCP协议学习分享,QQ群号:208136295
关注微信公众号:asterisk-cn,获得有价值的Asterisk行业分享
freepbx 技术论坛:www.ippbx.org.cn
Asterisk, freepbx技术文档: www.freepbx.org.cn
欧米(Omni)智能客服解决方案
融合通信商业解决方案,协同解决方案首选产品:www.hiastar.com
Asterisk/FreePBX唯一中国官方合作伙伴