关于#语音识别#的问题:Freeswitch-mod_unimrcp音频打断问题

在Freeswitch中,播放录音使用的是playback,语音识别使用的是

play_and_detect_speech  detect:unimrcp {start-input-timers=false,no-input-timeout=80000,recognition-timeout=80000} hello

那么如何控制在语音识别结果出来的时候,停止音频播放;未识别出语音识别结果的时候,音频继续播放

这个要根据你识别出的结果进行判断吧,识别出是指定的文本了,进行控制
https://blog.csdn.net/jiajiren11/article/details/92795975

https://freeswitch.org/confluence/display/FREESWITCH/mod_dptools:+play_and_detect_speech

调用函数play_and_detect_speech后,判断语音识别是否出来了,然后分别进行不同的处理。

改动最小最简单的方法:
打开mod_unimrcp.c 找到这个函数,只需要添加一句代码,这是最简单的代码方式就能使这个app play_and_detect_speech 变得好用起来,你甚至不用去改fs的核心代码,也不用去重新编译fs,只需要重新编译mod_unimrcp.c就行

img

更简单更安全的方法:
不让unimrcpserver发送 start of input 事件,同样可以使这个app好用起来
这个只需要编译unimrcpserver里面的插件就行

img

因为这样做都是让fs可以忽略了 mrcp 的 start of input 事件,改为收到结果再打断。

FreeSwitch源码源码系列-play_and_detect_speech (FreeSWITCH语音打断的实现)__Coffee_的博客-CSDN博客_freeswitch play_and_detect_speech 其实在很久之前这个app函数我就已经用过,可是这个语音打断实在是不太敢用,实用性不高,打断其实不准确,但作为一个打断方案,还是可以学习一下,以及freeswitch是如何实现的,当你看到最后之后,你就知道为何这个app不好用了和之前一样,我们找到这个app的注册函数首先我们先看这个函数的整个逻辑吧这里其实也没做啥事,就是解析参数,做了错误判断其中这个app函数的错误响应有:“USAGE ERROR” (使用错误)“GRAMMAR ERROR” (语法错误)“ASR INIT ERROR” ( https://blog.csdn.net/qq1779062842/article/details/106471665

这个方案有试过吗?

你调用的这个接口可能是将播放和识别捆绑在一起的,要想单独控制的话,最好就播放和识别分开调用

FreeSwitch源码源码系列-play_and_detect_speech (FreeSWITCH语音打断的实现)__Coffee_的博客-CSDN博客_freeswitch play_and_detect_speech 可以看看这篇博客是否有用

加控制语句

playback_terminators=123456789*0# | any | none

你的你目的是:控制在语音识别结果出来的时候,停止音频播放;未识别出语音识别结果的时候,音频继续播放。
音频播放应该是一个函数,语音识别也应该是一个函数
(1)定义一个全局变量flag,在语音识别中,当识别出结果时,flag = true
(2)在音频播放中,不断检测 flag 是否为true,当检测到 true 时,停止音频播放;否则,继续播放

不知道具体你代码如何,只能说一下思路

可参考


if ret==语音识别结果出来的时候:
    停止音频播放;
if ret==未识别出语音识别结果的时候:
    音频继续播放。

if ret==语音识别结果出来的时候:
停止音频播放;
if ret==未识别出语音识别结果的时候:
音频继续播放。

找到这个app的注册函数

img


先看这个函数的整个逻辑

img


这里其实也没做啥事,就是解析参数,做了错误判断
其中这个app函数的错误响应有:
“USAGE ERROR” (使用错误)
“GRAMMAR ERROR” (语法错误)
“ASR INIT ERROR” (asr初始化失败)
“ERROR” (通用错误,通常指普通地调用app失败)
每一个错误码的提示都很清晰,进入到这个函数的定义后就可以看到:

img


首先是这个核心函数最先开启语音识别,调用函数:
switch_ivr_detect_speech
这个函数其实就是之前看过的detect_speech一样,其实也是调用了这个函数去开启ASR:

img


然后设置回调函数
play_and_detect_input_callback 这个就是打断函数,但是先不要管它
之后就是调用了放音函数
switch_ivr_play_file

img


在播放文件的时候,跳出这里有两种方式,
1:收码跳出 (收码打断)
2:收到mrcp start_input 事件跳出(语音打断)

img


一:首先调用这个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就行

img


二:
更简单更安全的方法:
不让unimrcpserver发送 start of input 事件,同样可以使这个app好用起来
这个只需要编译unimrcpserver里面的插件就行

img


这样做都是让fs可以忽略了 mrcp 的 start of input 事件,改为收到结果再打断,准确性可以大大提高 !!!

这个是什么

https://download.csdn.net/download/weixin_42122878/18684427?spm=1005.2026.3001.5635&utm_medium=distribute.pc_relevant_ask_down.none-task-download-2~default~OPENSEARCH~Rate-4-18684427-ask-7773341.pc_feed_download_top3ask&depth_1-utm_source=distribute.pc_relevant_ask_down.none-task-download-2~default~OPENSEARCH~Rate-4-18684427-ask-7773341.pc_feed_download_top3ask

         private void doVoice(ArrayList<RecognizerResult> results) {  
            Intent i = new Intent();  
            for(RecognizerResult result : results){  
                if(result.text.contains("天气")){  
                    i.setClass(Voice1Activity.this, Weather.class);  
                    startActivity(i);  
                }else if(result.text.contains("新闻")){  
                    i.setClass(Voice1Activity.this, News.class);  
                    startActivity(i);  
                }else if(result.text.contains("短信")){  
                    i.setAction(Intent.ACTION_VIEW);  
                    i.setType("vnd.android-dir/mms-sms");  
                    startActivity(i);  
                }else{  
                    Toast.makeText(Voice1Activity.this, "无法识别", Toast.LENGTH_SHORT).show();  
                }  
            }  
              
        }