FreeSwitch源码系列-detect_speech

这个是我观看fs 源码的时候,看到的fs对asr的控制,如果你在搞asr的话,这或许可以给你提供一些不错的信息

fs是如何进行asr调用的,在调用asr的时候,fs做了什么事,以及asr的调用逻辑,fs是怎样控制各个模块,在asr调用的过程,又需要注意什么事?
我们以 detect_speech 这个函数来深入了解freeswitch,通过源码来获取更多asr相关的事情。

打开fs的源码后,在mod_dptools.c 的模块里就可以看到这个api的注册函数
在这里插入图片描述
它是个app函数,由mod_dptools辅助控制用户的调用,然后从模块转到fs核心处理

打开该函数后可以看到这个函数的参数以及调用的方法处理
在这里插入图片描述
在这里插入图片描述
普通的调用一般都会进入最后的函数:
除非你有特殊的调用,例如:detect_speech pause 等等
这个函数有5个参数
在这里插入图片描述
可以如下这样调用:
detect_speech unimrcp:unimrcpserver-mrcp2-127 hello hello
ps:
hello 是一个语法文件名,如果存在fs的目录下,不用加绝对路径以及语法后缀名.gam

最后一个参数是asr的句柄,但现在还没获取到,稍后就可以看到fs是如何调用asr模块去进行语音识别调用的
在这里插入图片描述
当我们跳到这个函数时switch_ivr_detect_speech,就已经由mod模块的控制跳转到fs的核心控制,就类似linux的用户空间跳转到内核空间,可以这么理解吧
需要重点关注这些函数
在这里插入图片描述
官方也写了注释了,首次需要初始化
进入这个函数switch_ivr_detect_speech_init,这个函数定义在ivr异步.c
在这里插入图片描述
switch_core_asr_open 在这个核心处理函数里面就对了asr进行open
在这里插入图片描述
这个函数里面通过mod的name的字符串获取了asr的实例,这个实例是fs启动时加载mod的时候就已经初始化好了,里面保存的是一张asr的回调函数表
在这里插入图片描述
一些设置之后,就直接回调了asr实例的回调函数asr_open
在这里插入图片描述
这个时候就从fs的核心控制跳转到了mod_unimrcp
我们可以在mod_unimrcp 看到这个函数以及一些注释
在这里插入图片描述
Process asr_open request from FreeSWITCH.表明了这个函数时由核心控制调用,并返回结果给fs的核心逻辑处理
这个函数主要关注这些函数调用
在这里插入图片描述
它创建了一条asr的通道,用fs传过来的通道的uuid以及name 以及通道的实例做了绑定,方便下次能快速找到属于该通道的asr通道
在这个函数里面就创建了asr会话以及一个音频的termination
官方也写了一些注释,很明了
这就比较重要了
在这里插入图片描述
这不仅设置了创建的是哪种asr的资源,还等待了mrcp连接成功
这个函数只是将一个消息push队列,然后就进入了一个循环等待
在这里插入图片描述
它会一直等待直到该通道连接成功,并且asr通道的状态改变才会跳出,也就是说成功跳出,失败也会跳出,因为在另一个函数有对asr通道的状态改变和这里是一个超时等待
在这里插入图片描述
如图,这个里会超时等待
如果成功连接上,这个函数里面就会对通道的状态做改变,从而跳出等待,否则就超时跳出等待,一旦超时,即mrcp初始化失败
在这里插入图片描述

之后再做些状态的判断以及打印一些log这个函数就退出了,这状态的判断就是在判断通道是否成功连接上asr,还是连接失败
在这里插入图片描述
之后就有mod的控制再次回到fs的核心控制
接下来重点只有这两个函数了
在这里插入图片描述

switch_core_media_bug_add
这是个核心控制函数
这个函数上面都是做一些通道的状态检查,不细看了,可以自行去查看
我们只需要注意这个回调函数
在这里插入图片描述
这一部分是对视频的初始化操作,如果媒体资源是视频的话
在这里插入图片描述
会开启一条专门负责处理视频流的线程
在这里插入图片描述
但不管怎么样还是会开启一条专门来处理asr结果的线程,这个线程也非常重要,fs的语音打断就是在里面做主要打断处理的
在这里插入图片描述
回来看一下这个speech callback 函数的实现
在这里插入图片描述
刚才我们看到了这switch的类型是哪个,它就是回调了进入了这个函数又开启另一条线程去处理asr的结果
在这里插入图片描述
继续看speech_thread函数,这函数会进入一个循环,不断去检查asr的结果,以及不断地生成一个asr的事件 DETECTED_SPEECH
在这里插入图片描述

开启并且 定阅事件后,就可以不断地收到该事件,它会一直循环到asr通道退出,期间不断地调用mod_unimrcp的回调函数去检查
在这里插入图片描述
再来看看回调结果的其他处理,处理如下图
在这里插入图片描述
再次回到这个函数switch_core_media_bug_add,这个bug 非常重要,一旦一个会话开启asr调用,这个bug就一定会在,并且保存在session里面,它的存在保证了该会话可以正确的把rtp流传输出去
在这里插入图片描述
之后再次创建一个事件 MEDIA_BUG_START,注意这个事件只有asr启动(连接)成功后,才会有,否则在上面就已经结束了函数的调用,不会进来这个函数,这样我们就可以非常灵活地通过esl来控制mrcp连接不上的办法了,例如订阅MEDIA_BUG_START 事件,然后设置一个定时器超时连接,如果超过几秒就直接停用asr释放资源,如果收到事件MEDIA_BUG_START 即连接mrcp 成功就清理超时定时器
在这里插入图片描述
之后这个函数就完全调用完毕,
再设置下收码回调函数,这个函数就返回回去了switch_ivr_detect_speech_init 完全调用完毕
在这里插入图片描述
之后就是做了一些其他操作和设置一下通道的标志,
注意只有开启了 fire_asr_events 你才能收到asr的事件
在这里插入图片描述
到此为止,fs对asr的调用完全调用完毕,我们整理一下过程
首先调用这个app 函数:
1:
mod_dptools :
detect_speech
从mod_dptools 跳转到核心控制函数 —> switch_ivr_detect_speech
2:
fs core:
:switch_ivr_detect_speech
从核心控制再次跳转到 ---->mod_unimrcp:asr_open
3:
mod_unimrcp
创建asr通道,并且等待asr通道连接成功,或超时
4:
fs core
再次回来创建等待asr结果线程,不断地去循环检查asr的结果,和生成事件
switch_core_media_bug_add
speech_callback
speech_thread

switch_core_event_hook_add_recv_dtmf 添加dtmf收码回调函数

asr开启结束(其实我是想画流程图的,但嫌累,还是不画了,可以脑补一下流程图)

最后完了吗?还没有,asr的rtp流是怎样传输过去的?
上面说bug很重要,流的传输就是靠这个传输过去的,看一下

看这里,会话保存了这个bug
rtp流不在asr开启流程这里传输的,它是可以在任何地方传输的
例如:当通道sleep的时候
在这里插入图片描述
如下图,这sleep函数里面是一个循环,在里面不断地调用核心函数:
switch_core_session_read_frame
从里面读取流传输给asr
在这里插入图片描述
如图:
在这里插入图片描述
在这里插入图片描述
看这个speech_callback函数 上面的 bp->callback = speech_callback 函数
在这里插入图片描述流在这里传输过去给asr的
在这里插入图片描述
如图:
在这里插入图片描述
如图:回调了进来mod_unimrcp,并且把rtp流写入asr通道创建的音频队列里面
在这里插入图片描述
也就是说,在通道的还存在fs里面,就可以从任何地方发送流给mod_unimrcp
可以搜一下个函数 switch_core_session_read_frame 在很多地方都有不停地调用

至此,fs对asr的调用以及控制基本算完了,当然还有通道挂机的对asr的控制,这里就不多写了,可以自行去探索,

下一次,我们来探讨freeswitch 是如何做语音打断的
就是这个函数:play_and_detect_speech

联系我:c_wujinbiao@163.com

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值