语音驱动(tspeech_slot)

代码参考:小程序Basic(aplt.leagor.basic)有一个语音驱动实例tleagor_speech。

视频1 语音驱动

视频1演示了新建小程序、让小程序符合语音驱动规范、使用poedit、小程序上传到商店、从商店下载内测版,这整个过程。

图1 语音驱动模块
  1. 机器人采集到用户说的声音后,判断出来可能是段有效语音,就进行语音识别,得到一段文字。
  2. 解析文字,这段文字至少可能有两种功能,一是用于控制机器人,二是聊天。
  3. 用于控制机器人的文字。举个例子,命令机器人去启动豆浆机。机器人收到命令后,将移动到豆浆机,同时为让用户知道收到这命令了,会发出声音:“好的,这就去启动豆浆机”。
  4. 用于聊天的文字。举个例子:叫机器人背《静夜思》。这时是作为一个问题提交给NLP模型,NLP模型返回以文字表示的回答。接下把文字表示的回答转为声音,再叫机器人播放出来。于是现实人和机器人聊天。

正如上图所述,语音识别,识别出文字后怎么解析,怎么由文字表示的问题得到答案,这些都是语音驱动小程序实现。语音识别用的是科大讯飞还是百度,NLP模型用的是哪家,全看你此刻使用的是哪个语音驱动小程序。

 

一、输出规范

1.1 settings.cfg

speech_driver = yes

根下需存在键“speech_driver”,值是bool类型的“yes”。

1.2 libroseaplt.so需输出函数:aplt_create_speech_slot

void* aplt_create_speech_slot();

返回值是个指向aplt::tspeech_slot对象的指针。

 

二、识别、解析语音

图2 识别、解析语音

语音驱动涉及三个线程:主线程,声音采集线程和语音识别线程。让根据图2,看一次语音处理过程。

  1. [采集线程]提取出一段认为是语音的声音片断,记为(data_, voice_len_)。
  2. [采集线程]将voice_event_设为有信号,唤醒识别线程。
  3. [识别线程]调用虚函数recognize()识别声音片断(data_, voice_len_),tleagor_speech用的是科大讯飞语音识别算法。识别出的文字放在函数内变量result。
  4. [识别线程]把result值安全地放在类内变量vocie_result_,让主线程可以访问。
  5. [主线程]在新近一次tleagor_speech::slice,发现voice_result_不是空,先安全地转放到函数内变量result。至此result存储着一段新近识别出的语音。根据文字内容可执行不同操作。

tspeech_slot::DoWork是声音识别线程默认执行的操作。如果不重载它,语音驱动须实现方法:has_voice、recognize。

在slice,安全得到一个非空的result后,便可根据不同内容执行不同操作。

2.1 控制机器人

执行一个aplt::treq_task封装的任务

type描述生成该任务的方法
type_moveto移动到某个位置set_moveto
type_moveto_recognition移动到某个位置,移动成功后开始识别物体set_moveto_recognition
type_recognition原地开启摄像头,识别物体set_recognition

得到任务treq_task后,以它为参数调用tros::request_task,便可让launcher去执行该任务。

 

要求机器人播放一段声音

aplt::tpinyin::speak,参数是utf-8格式的一个字符串。

 

三、接收临时任务执行过程中消息

语音驱动发现语音是要控制机器人,会调用aplt::tros::request_task向launcher发起控制请求。launcher在执行这个临时任务时,为让用户有个好的体验,需让知道现在执行到哪阶段了。于是到某个事件点,launcher会以消息码为参数,调用aplt::tmsg_subscriber的对应方法。

每个方法都有一个id参数。这个id来自request_task时的参数aplt::treq_task中的id字段。系统中可能同时存在多个treq_task,语音驱动在处理时首先要判断这id是不是自已的,是的才处理,否则要忽略。

virtual void did_task_pre_navigation(int id);

机器人要开始导航

virtual void did_task_navigation_stopped(int id, bool result);

机器人导航结束。result表示导航是成功还是失败。

virtual void did_task_object(int id, const std::string& object);

图像识别时识别出新物体。参数object指示物体名称(utf-8格式)。

virtual void did_task_msg(int id, msg_t msg);

这是一个可处理多种消息的函数,这些消息都没有关联参数。

  • msg_disallowed。现在不允许执行新任务。举个例子,正显示着“设置”、“地图”等这些窗口时,不允许执行临时任务。
  • msg_unrecognized。物体识别时,如果此次一直没有识别到物体,那识别15秒后就结束。结束时会发出这消息。如果此次有识别到物体,那结束时刻是在识别出那一刻再延时15秒,而且结束后不会发这个消息。
  • msg_more_precise。物体识别时,4秒内没识别到这物体,会发出这消息。一次识别过程只会发一次。

 

四、科大讯飞语音识别

tleagor_speech在实现语音识别时,调用科大讯飞语音识别SDK。SDK是动态库方式,即windows上的msc.dll,android上的libmsc.so。

launcher是以动态方式加载msc.dll/libmsc.so。在获取库中某个地址时,该函数必须有“MSPAPI/__stdcall”修饰符。否则变成__cdecl,那会导致程序崩溃。

为安全,android对允许动态方式加载的动态库文件名做了限制,只允许:libroseaplt.x、libroseaplt2.x、libroseaplt3.x、libroseaplt4.x。libroseaplt.x有专门用途,那只能在2/3/4中选一个。

tleagor_speech集成的科大讯飞语音识别算法是免费的,有每天识别次数限制。自写、还是用讯飞的话,去讯飞官网申请个账号。

全部评论: 0

    写评论: