FreeSwitch源码源码系列-play_and_detect_speech (FreeSWITCH语音打断的实现)

这个app实用性不高,打断其实不准确,但作为一个打断方案,还是可以学习一下,以及freeswitch是如何实现的,当你看到最后之后,你就知道为何这个app不好用了
后面也有优化方法,用来提高这个app的实用性

和之前一样,我们找到这个app的注册函数FreeSwitch源码源码系列-play_and_detect_speech (FreeSWITCH语音打断的实现)_第1张图片
首先我们先看这个函数的整个逻辑吧
FreeSwitch源码源码系列-play_and_detect_speech (FreeSWITCH语音打断的实现)_第2张图片
这里其实也没做啥事,就是解析参数,做了错误判断
其中这个app函数的错误响应有:
“USAGE ERROR” (使用错误)
“GRAMMAR ERROR” (语法错误)
“ASR INIT ERROR” (asr初始化失败)
“ERROR” (通用错误,通常指普通地调用app失败)
每一个错误码的提示都很清晰

进入到这个函数的定义后就可以看到
FreeSwitch源码源码系列-play_and_detect_speech (FreeSWITCH语音打断的实现)_第3张图片
首先是这个核心函数最先开启语音识别,调用函数:
switch_ivr_detect_speech
这个函数其实就是之前看过的detect_speech一样,其实也是调用了这个函数去开启ASR,由于之前已经讲过这个函数,这里就不再重复
FreeSwitch源码源码系列-play_and_detect_speech (FreeSWITCH语音打断的实现)_第4张图片
然后设置回调函数
play_and_detect_input_callback 这个就是打断函数,但是先不要管它
之后就是调用了放音函数
switch_ivr_play_fileFreeSwitch源码源码系列-play_and_detect_speech (FreeSWITCH语音打断的实现)_第5张图片
重点:在回调函数play_and_detect_input_callback 和在switch_ivr_play_file
先看switch_ivr_play_file
里面的逻辑判断太多,不一一细看,只截取重要的地方说明
例如这里:解析参数,判断是文件播放还是使用asr的TTS合成
FreeSwitch源码源码系列-play_and_detect_speech (FreeSWITCH语音打断的实现)_第6张图片
如果是say:
则进行asr的TTS合成播放
FreeSwitch源码源码系列-play_and_detect_speech (FreeSWITCH语音打断的实现)_第7张图片
上面都不是的话,就组成文件名:
FreeSwitch源码源码系列-play_and_detect_speech (FreeSWITCH语音打断的实现)_第8张图片
之后如果是文件播放:
直接进入一个死循环,打开文件,加载音频文件的信息,设置一些参数
FreeSwitch源码源码系列-play_and_detect_speech (FreeSWITCH语音打断的实现)_第9张图片
重要地方,在这个循环内会开启一个线程来专门读取音频流
FreeSwitch源码源码系列-play_and_detect_speech (FreeSWITCH语音打断的实现)_第10张图片
进入这个函数后,就可以发现这个条线程会一直在读取音频或视频,asr为音频
FreeSwitch源码源码系列-play_and_detect_speech (FreeSWITCH语音打断的实现)_第11张图片
switch_core_session_read_frame 还记得这个函数吧,这里不再做说明这个函数
之后就是进入死循环真正播放放文件了
FreeSwitch源码源码系列-play_and_detect_speech (FreeSWITCH语音打断的实现)_第12张图片
重点来了,注意在播放文件的时候,跳出这里有两种方式,
1:收码跳出 (收码打断)
2:收到mrcp start_input 事件跳出(语音打断)
FreeSwitch源码源码系列-play_and_detect_speech (FreeSWITCH语音打断的实现)_第13张图片
在播放文件的同事会一直不断地检查事件
FreeSwitch源码源码系列-play_and_detect_speech (FreeSWITCH语音打断的实现)_第14张图片

接下来我们来看看是怎样打断的:
我们先回到这个函数switch_ivr_detect_speech
FreeSwitch源码源码系列-play_and_detect_speech (FreeSWITCH语音打断的实现)_第15张图片
一直追寻进入:
在这里插入图片描述
进入回调
FreeSwitch源码源码系列-play_and_detect_speech (FreeSWITCH语音打断的实现)_第16张图片
FreeSwitch源码源码系列-play_and_detect_speech (FreeSWITCH语音打断的实现)_第17张图片
由于之前已经讲过这个函数,这里就不再说明
如果你看过我的上一篇源码分析,就知道这里的逻辑,我们知道,在初始化asr的时候会单独通过回调函数:speech_callback 再去创建一条线程 speech_thread
这条speech_thread线程会一直在检查asr的结果,并且生成一个事件DETECTED_SPEECH 这个时候如果mrcpserver 发回了一个mrcp的事件start_input
FreeSwitch源码源码系列-play_and_detect_speech (FreeSWITCH语音打断的实现)_第18张图片
FreeSwitch源码源码系列-play_and_detect_speech (FreeSWITCH语音打断的实现)_第19张图片
FreeSwitch源码源码系列-play_and_detect_speech (FreeSWITCH语音打断的实现)_第20张图片
一旦有结果,或者受到start input 检查结果遍会返回成功
FreeSwitch源码源码系列-play_and_detect_speech (FreeSWITCH语音打断的实现)_第21张图片
由于在播放的同时会不断地检查通过回调去检查事件
FreeSwitch源码源码系列-play_and_detect_speech (FreeSWITCH语音打断的实现)_第22张图片
在进入回调后 play_and_detect_input_callback 检查由 speech_thread 产生的DETECTED_SPEECH 事件,然后就跳出
FreeSwitch源码源码系列-play_and_detect_speech (FreeSWITCH语音打断的实现)_第23张图片
最后这里由于收到了事件之后,返回的状态为SWITCH_STATUS_BREAK
FreeSwitch源码源码系列-play_and_detect_speech (FreeSWITCH语音打断的实现)_第24张图片

小结:

一:首先调用这个app函数时,是先开启语音识别
开启的时候初始化及创建asr通道
通过回调函数speech_callback 来创建一条循环检查ASR的结果,并且产生事件
产生事件,是在不断地调用mod_unimrcp 里面的一个回调函数:
recog_channel_check_results
产生事件的因素:必须有到结果或者收到unimrcpserver的start input 事件,才会
产生事件,Speech-Type:begin-speaking
之后就会一直产生的事件类型为:
Speech-Type:detected-speech
这样也是通过关注asr的事件,最后会一直产生这个类型的事件的原因

二:当进入switch_ivr_play_file,在一个死循环内就会不断地去调用回调函数play_and_detect_input_callback去检查asr生成的事件,如果事件的类型为:
SWITCH_EVENT_DETECTED_SPEECH 即收到了asr的事件,这个时候不论是收到事件类型的:begin-speaking 还是 detected-speech 都会导致跳出播放文件(打断)
但一开始应该收到的事件一般多为mrcp的start input ,除非unimrcpserver不发送start input 事件,最后也就是说,freeswitch 的语音打断是通过mrcp的start input 或者是收到asr的识别结果来做打断的。但其实这个是不好的

总结:
语音打断的方案其实有不少,fs的只是其中的一种,虽然不好用,但你也可以收动改源码使这个app好用
例如:
一:
改动最小最简单的方法:
打开mod_unimrcp.c 找到这个函数,只需要添加一句代码,这是最简单的代码方式就能使这个app play_and_detect_speech 变得好用起来,你甚至不用去改fs的核心代码,也不用去重新编译fs,只需要重新编译mod_unimrcp.c就行
FreeSwitch源码源码系列-play_and_detect_speech (FreeSWITCH语音打断的实现)_第25张图片
二:
更简单更安全的方法:
不让unimrcpserver发送 start of input 事件,同样可以使这个app好用起来
这个只需要编译unimrcpserver里面的插件就行
FreeSwitch源码源码系列-play_and_detect_speech (FreeSWITCH语音打断的实现)_第26张图片
因为这样做都是让fs可以忽略了 mrcp 的 start of input 事件,改为收到结果再打断,准确性可以大大提高 !!!

联系我:[email protected]

你可能感兴趣的:(Freeswitch,MRCP,unimrcpserver)