语音识别开发

2016-10-07 21:18:45 sac761 阅读数 22848

本项目做出的产品是一个Windows下的增强现实系统,系统很庞大,产品功能已经基本完善,考虑到给用户带来更好的体验,故综合评估后采用讯飞语音识别方案进行嫁接。

项目介绍:

1)打开系统时启动语音识别,检测到用户说出关键词(如:上一步,下一步,结束等)时,系统自动进行相应的操作;

2)不需要按任何按键进行连续的语音识别控制,延迟为2秒左右;

3)可以识别词语,句子,中文,英文数字字母通吃,不限语速。并且语句结束判断机制很智能;

3)离线!离线!现在做一个基于windows的离线的语音识别系统在网络上还真没谁,讯飞自己也还没有推出这款SDK,我是在讯飞的离线命令词识别SDK开发包上开发出的介于两者之间功能的系统。

为什么用讯飞:

之前使用过语音识别开发版,用驻极体采集声音,通过串口传输信号来进行识别,只能讲开发版只适合用来做个课程设计啥的玩玩,做产品还是太LOW,识别率地下并且识别范围窄,貌似只能识别数字字母;之后调查过汉语语音识别库如Sphinx,Julius,百度语音等。去网上问,很多人推荐这些方案的,我没试过,不过一个SDK也只有自己正真开发过才知道好不好用强不强大,说的再牛逼也是在别人手上玩的转,到你这就不一定了。我用讯飞就是看上它的鲁棒,免费,毕竟是久经考验的平台,讯飞有一个开发者论坛,开发别人的SDK有个社区很重要,不然有问题没地方问。


项目开发经验与源码如下:

一、跑通讯飞离线命令词识别SDK

首先去讯飞官网下载相应SDK,要注册登录,绑定产品才能下载,下载后跑一跑给的demo,跑不通的话去讯飞的论坛找答案。

我用的demo是asr_record_demo,这个demo可以实现的功能是按下R键从mic中录制缓冲音频并按下S键后进行识别。

稍微看一看这个demo中的东西吧,把该删的东西删了,该修整的修整,玩转了demo才能进一步做移植。

二、文件分析与移植

把SDK包中的需要的.lib  .h  .c和所需要的其余文件拷贝到项目相应的文件夹去,最好是分个类,看起来比较清楚。它比较重要的几个文件有以下几个:

msc.lib   讯飞语音离线命令词识别所依赖的库(X64版本为msc_x64.lib)才15KB就能有如此强大的功能。

call.bnf    采用巴科斯范式语法规则的自定义语法库(call是根据自己需要命名的),用来编写语音识别过程中的语法规则,这个语法写的好语音识别更智能。

speech_recognizer.c  基于录音接口和MSC接口封装一个MIC录音识别的模块,SDK的主要文件

winrec.c  封装windows录音,Windows平台下SDK的主要文件


好了,既然demo已经知道怎么用了,把demo所依赖的所有文件和库照搬进自己的项目去,就可以在自己的项目中调用讯飞的函数了(注意头文件和库文件的路径问题)。

三、使用讲解

先看看我的语法文件

call.bnf:


巴科斯范式语法语法文件怎么写在讯飞的论坛里有很多资源自己去看吧,我写的比较简单,写得好的语法可以更加智能。


大致讲讲源码:

为了看起来简洁,我在speech_recognizer.h中做了一个类SR,把主文件中的一些函数定义和一些宏搬进去。

speech_recognizer.h:

class SR {
public:

	const char * ASR_RES_PATH = "fo|res/asr/common.jet";  //离线语法识别资源路径
#ifdef _WIN64
	const char * GRM_BUILD_PATH = "res/asr/GrmBuilld_x64";  //构建离线语法识别网络生成数据保存路径
#else
	const char * GRM_BUILD_PATH = "res/asr/GrmBuilld";  //构建离线语法识别网络生成数据保存路径
#endif
	const char * GRM_FILE = "call.bnf"; //构建离线识别语法网络所用的语法文件

	int build_grammar(UserData *udata);//构建语法
	int run_asr(UserData *udata);//启动引擎

};
speech_recognizer.c:

#pragma comment(lib,"../../lib/msc_x64.lib") //x64
#else
#pragma comment(lib,"XXXXXX/lib/msc.lib") //x86
#endif
这里的库目录要注意,用相对路径可能找不到文件,可以使用绝对路径

#ifdef _WIN64
<pre name="code" class="cpp">static int update_format_from_sessionparam(const char * session_para, WAVEFORMATEX *wavefmt)
{
	char *s;
	/*if ((s = strstr(session_para, "sample_rate"))) {
		if (s = strstr(s, "=")) {
			s = skip_space(s);
			if (s && *s) {
				wavefmt->nSamplesPerSec = atoi(s);
				wavefmt->nAvgBytesPerSec = wavefmt->nBlockAlign * wavefmt->nSamplesPerSec;
			}
		}
		else
			return -1;
	}
	else {
		return -1;
	}*/

	return 0;
}


如果加到讯飞提供的demo使用的是VS2010如果放到VS2015中就会出一些语法上的错,自己看着改一改,比如上面这个函数,是更新用户词典用的,我不需要但是又存在语法错误,就把它的内容直接注释掉得了。

我的项目的主文件中:

首先定义几个宏:

UserData asr_data;//语音识别用户配置
speech_rec asr;//麦克风输入存储结构体
SR sr;//语音识别实体
string SPEAKER="";//用于缓存语音识别内容
在程序初始化处配置如下:

openVoiceRecognizer = true;//语音识别开关
	if (openVoiceRecognizer)
	{
		const char *login_config = "appid = XXXXX"; //登录参数
		int ret = 0;


		ret = MSPLogin(NULL, NULL, login_config); //第一个参数为用户名,第二个参数为密码,传NULL即可,第三个参数是登录参数
		if (MSP_SUCCESS != ret) {
			printf("登录失败:%d\n", ret);
			openVoiceRecognizer = false;
		}


		memset(&asr_data, 0, sizeof(UserData));
		printf("构建离线识别语法网络...\n");
		ret = sr.build_grammar(&asr_data);  //第一次使用某语法进行识别,需要先构建语法网络,获取语法ID,之后使用此语法进行识别,无需再次构建
		if (MSP_SUCCESS != ret) {
			printf("构建语法调用失败!\n");
			openVoiceRecognizer = false;
		}


		while (1 != asr_data.build_fini)
			_sleep(300);
		if (MSP_SUCCESS != asr_data.errcode)
			_sleep(300);
		printf("离线识别语法网络构建完成,开始识别...\n");
		ret = sr.run_asr(&asr_data);//预启动语音识别引擎
	}
在初始化这里我修改了 sr.run_asr(&asr_data);这个函数,我把它调用的sr_start_listening(&asr);函数抽离出来,不让它启动识别引擎而只让它预启动,把所有结构体,变量先初始化待命。

void recognize_mic(const char* session_begin_params)  //根据自己项目需要写的语音识别预热函数
{
	int errcode;
	HANDLE helper_thread = NULL;

	struct speech_rec_notifier recnotifier = {
		on_result,
		on_speech_begin,
		on_speech_end
	};
	errcode = sr_init(&asr, session_begin_params, SR_MIC, DEFAULT_INPUT_DEVID, &recnotifier);
	if (errcode) {
		printf("speech recognizer init failed\n");
		return;
	}

	/*	while (1) {
			errcode = sr_start_listening(&asr);//我把它调用的sr_start_listening(&asr);函数抽离出来,不让它启动识别引擎而只让它预启动,把所有结构体,变量先初始化待命。
		}

	exit:
		sr_uninit(&asr);*/
}

int SR::run_asr(UserData *udata)
{
	char asr_params[MAX_PARAMS_LEN] = { NULL };
	const char *rec_rslt = NULL;
	const char *session_id = NULL;
	const char *asr_audiof = NULL;
	FILE *f_pcm = NULL;
	char *pcm_data = NULL;
	long pcm_count = 0;
	long pcm_size = 0;
	int last_audio = 0;
	int aud_stat = MSP_AUDIO_SAMPLE_CONTINUE;
	int ep_status = MSP_EP_LOOKING_FOR_SPEECH;
	int rec_status = MSP_REC_STATUS_INCOMPLETE;
	int rss_status = MSP_REC_STATUS_INCOMPLETE;
	int errcode = -1;
	int aud_src = 0;

	//离线语法识别参数设置
	_snprintf(asr_params, MAX_PARAMS_LEN - 1,         //<span style="font-family: Arial, Helvetica, sans-serif;">离线语法识别参数根据自己的需要进行更改</span>

		"engine_type = local, \
		asr_res_path = %s, sample_rate = %d, \
		grm_build_path = %s, local_grammar = %s, ",
		sr.ASR_RES_PATH,
		SAMPLE_RATE_16K,
		sr.GRM_BUILD_PATH,
		udata->grammar_id
		);

	recognize_mic(asr_params);
	return 0;
}
而后是三个语音识别的中间过程和结果处理的函数:

void on_result(const char *result, char is_last)   //根据自己的需要写结果处理
{
	char *p = "上一步";
	char *pq = "下一步";
	char *q = "扫频仪操作演示";
	char *end1 = "结束";
	char *end2 = "退出";
	if (strstr(result, p)) {
		SPEAKER = "上一步";	
	}
	else if (strstr(result, pq)) {
		SPEAKER = "下一步";
	}
	else if (strstr(result, q)) {
		SPEAKER = "扫频仪操作演示";
	}
	else if (strstr(result,end1)|| strstr(result, end2)) {
		SPEAKER = "退出";
	}
	cout << SPEAKER << endl;
}
void on_speech_begin()
{
	if (g_result)
	{
		free(g_result);
	}
	g_result = (char*)malloc(BUFFER_SIZE);
	g_buffersize = BUFFER_SIZE;
	memset(g_result, 0, g_buffersize);

	printf("Start Listening...\n");
}
void on_speech_end(int reason)
{
	if (reason == END_REASON_VAD_DETECT)
		printf("\nSpeaking done \n");
	else
		printf("\nRecognizer error %d\n", reason);
}
最后就是在自己项目哪里需要语音识别就在哪里抛出缓冲线程启动识别引擎:

if (openVoiceRecognizer) {
		
		sr_start_listening(&asr);//抛出缓冲线程进行语音识别

		if (SPEAKER=="下一步") {
			keyPressed(' ');
		}
		else if (SPEAKER == "上一步") {
			keyPressed('b');
		}
		else if (SPEAKER == "扫频仪操作演示") {
			keyPressed('1');
		}
		else if (SPEAKER=="退出") {
			std::exit(0);
		}
		SPEAKER = "";
	}

上面代码中的关键就是sr_start_listening(&asr);这个函数,前面也说了这是从run_asr()调用的方法中抽离出来的,抽离出来后run_asr()就变成了预热函数,只需在程序初始化的时候调用它后面的语音识别就不要重复调用了,节省资源。

必须要说说这个关键函数sr_start_listening(&asr);

这是讯飞这款SDK中不需要动的最后一个封装好的函数,里面的东西不要动,前面的东西配置好一调用它就可以进行语音识别了,这个函数中的东西是这款SDK的精华,实现过程很复杂不需要管,但是要记住它的几个特性:

1)一调用它就相当于抛出了一个带缓冲的新线程,这个线程独立进行语音的识别可以不干扰项目的主循环的进行。

2)这个线程寿命是自动的,程序一开始启动到这里调用这个函数后启动线程,当程序的主循环又回来这里不会重复启动这个线程,而是该线程识别完用户的语音判断语句结束机制触发后才待命,等待下一次循环的启动。这句话有些费解,用我的项目解释下:我的项目在update()函数中调用sr_start_listening(&asr); 我的update()函数每100毫秒循环一次,第一次循环启动这个函数,抛出线程进行语音识别,语音识别用了10秒结束,在这10秒过程中update()循环了100次,但是只启动该函数一次,第101次循环的时候就可以第二次启动该函数了,同时在上面代码片中我用SPEAKER转存的字符串的判断条件已经成立,就可以进行相应的操作了,在这里我触发了不同的按键来代替各种操作。

3)举个栗子,我在update()中可以在每一次循环时画一帧图片的方式实现一个视频的播放,而在这里面调用语音引擎sr_start_listening(&asr);,在引擎识别的过程中会不会中断视频的播放或者视频出现卡帧或迟滞呢?答案是不会,上面也解释了,这个函数抛出一个独立的线程,不影响主函数的循环。所以可以用这种方法实现用语音控制视频的播放:快进、后退、暂停、截屏、全屏、音量加大、切换到高清......是不是很酷!

上面的几个源码文件我打了个包,下载看可能更清楚:

http://download.csdn.net/detail/sac761/9647029

四、总结

我用这个方案实现了离线的语音控制系统,语音识别率达到百分之九十以上,而且词语句子中英文通吃,实时性强,系统鲁棒。

畅想一下用这个方法加方案开发这几个产品:

语音控制的媒体播放器,功能在上面也讲了,很酷的!

语音控制的PPT遥控器

语音控制的AR/VR系统

语音交互智能眼镜

.............





2018-07-30 21:02:40 wenzhi20102321 阅读数 7418

讯飞语音识别和唤醒开发示例

最近需要用到讯飞的语音识别和语音唤醒的功能,就对这方面进行了一下简单研究。

本文帮助大家简单入门,并且提供几个代码示例给大家参考。

讯飞开发者网址:https://www.xfyun.cn/

讯飞的部分功能,如图:
1

本文只介绍一点语音相关的内容。如果需要可以看看。

一.创建自己的讯飞应用

这里需要先注册自己的讯飞账号。并且进行实名验证。

登陆后,看到右上角有个“控制台”的文本,点击进去,就可以创建我们的应用了。

输入应用的基本信息,如图:
2

创建自己的应用后,可以对自己的应用进行编辑,添加自己需要集成的功能,
如图:
3
创建的应用中有个属性APPID是在讯飞SDK初始化的时候需要用到的。下载的Demo中也有使用方法。

讯飞的功能是部分免费的,部分是体验的,有些是收费的。

比如,我这里添加了语言识别和语音唤醒功能,如图:
4

在后期是可以对自己的应用进行编辑,增加其他模块的功能的。

点击下载SDK,我们就可以进行讯飞的集成进行开发了。

二.讯飞集成开发

讯飞SDK下载后得到的文件,如图:
5

assets、res是一些资源文件
lib中是一些jar包和so库
sample是讯飞给我们提供的demo程序,这个很重要,如果是新手最好看看demo的代码参考开发
readme.txt是简单的注意事项
release.txt是一些版本的信息
wordlist.txt是自己设置的唤醒的关键字

我这里的SDK是集成了语音识别和唤醒功能的,但是我发现sample中有两个示例程序。

有一个demo是有唤醒功能代码的,另一个demo是没有唤醒功能代码的。

有唤醒功能代码的demo,资源文件缺少APPID.jet文件,这个文件在下载的SDK的res/ivw中,

需要复制到项目中的assets文件夹中,才能使用唤醒功能。

1.语音识别

主要控制的类

 // 语音听写对象
    private SpeechRecognizer mIat;

这个类实例化后,进行参数配置,就可以调用start,stop,cancel等方法进行识别控制

这里讯飞语音不是等你说完在进行识别的,而是一边说,它会一边帮你识别,
所以讯飞默认情况是会在你不说话的时候自动结束识别。

讯飞的语音识别也是有两种形式的,一种是有讯飞自定义的对话框显示的形式,另一种是没有对话框显示的形式。

具体的控制逻辑可以参考demo。

2.唤醒

唤醒记得要复制对的APPID.jet到正确的位置,才能进行有效唤醒。

但是我参考讯飞demo写的代码,只有WakeDemo这个类的唤醒有效,另一个类OneShotDemo的类唤醒无效!

三.这里我把几个项目的代码发给大家参考:

下载地址:https://download.csdn.net/download/wenzhi20102321/10573210

里面的文件说明:

1.my文件夹

这个是我从讯飞开发者中下载的完整的SDK代码,里面包括讯飞提供两个demo代码和一些资源文件

2.XunfeiDemo.rar

这个是我自己根据讯飞SDK中的Demo开发的简单例子,

这个例子里面只开发了语音识别和简单唤醒的功能。

唤醒的关键字是:美女你好

3.MySpeech.rar

这个也是别人根据其他讯飞SDK的Demo开发的例子

里面没有开发唤醒功能,但是有其他比较多的功能实现。

4.里面还提供了两个apk文件,可以安装看看效果

这两个apk如果使用adb install 可能安装失败,因为是调试版本
需要使用adb install -t 才能安装成功

共勉:智者的梦再美,也不如愚人实干的脚印。

2018-09-13 13:51:25 dyingstraw 阅读数 1853

由于业务需求,需要使用微信小程序语音识别的功能,查找了好多发难,也踩了好多坑,把过程记录一下,或许会帮助到需要的朋友。

业务需求:

在小程序中识别用户语音输入的命令

业务环境和关键技术:

1.小程序:

关键流程流程:

录音存储-->上传录音文件到服务器后台-->读取服务器返回结果

关键代码:

//按键按下事件
  startRec:function(res){
    var that=this
    wx.startRecord({
      success: function (res) {
        var tempFilePath = res.tempFilePath//获取录音文件路径
        console.log(tempFilePath)
        // 上传卢新文件到服务器
        wx.uploadFile({
          url: 'http://ipaddress:port/voice_detec',
          filePath: tempFilePath,
          name: 'voice',
          // 服务器返回识别结果
          success:function(res){
            console.log(res.data)
            var data = res.data
            var jd = JSON.parse(data)
            if (jd.err_no==0){
              var msg =jd.result[0];
            }
            else{
              var msg = '未识别,请重新尝试';
            }
            // 显示识别成功
            wx.showToast({
              title: msg,
            })

          },
          // 上传识别
          fail:function(){
            console.log('error upload!')
            wx.showToast({
              title: '与语音识别服务器断开连接',
            })
          }
        });
        // 播放录音
        wx.playVoice({
          filePath: tempFilePath,
          complete: function () {
          console.log("播放录音")
          }
        })
      },
      fail: function (res) {
        //录音失败
      }
    })
    setTimeout(function () {
      //结束录音  
      wx.stopRecord();
    }, 10000)
  },

2.服务器:

安装指南:

依赖组件:gcc、ffmpeg

git clone https://github.com/kn007/silk-v3-decoder.git
cd silk*/silk
make
#若果有waring不用担心,看看目录下有没有生成二级制文件decoder
# 使用上个目录的sh脚本,把1.silk转伟1.wav,这两个文件在同一个目录
cd ..

sh converter.sh 1.slk wav
# 看看有没有生成1.wav

由于百度api的语音识别的语音文件码率只能为8K或者16K,所以要对conveter.sh里面的几个参数进行修改,保证转化的采样率是16K,修改后的文件如下(把70行改成71行的内容),如果不修改,识别效果不是很好:

 62 $cur_dir/silk/decoder "$1" "$1.pcm" > /dev/null 2>&1
 63 if [ ! -f "$1.pcm" ]; then
 64         ffmpeg -y -i "$1" "${1%.*}.$2" > /dev/null 2>&1 &
 65         ffmpeg_pid=$!
 66         while kill -0 "$ffmpeg_pid"; do sleep 1; done > /dev/null 2>&1
 67         [ -f "${1%.*}.$2" ]&&echo -e "${GREEN}[OK]${RESET} Convert $1 to ${1%.*}.$2 success, ${YELLOW}but not a silk v3 encoded file.${RESET}"&    &exit
 68         echo -e "${YELLOW}[Warning]${RESET} Convert $1 false, maybe not a silk v3 encoded file."&&exit
 69 fi
 70 #ffmpeg -y -f s16le -ar 12000 -ac 2 -i "$1.pcm" "${1%.*}.$2" > /dev/null 2>&1
 71 ffmpeg -y -f s16le -ar 12000 -ac 2 -i "$1.pcm" -f wav -ar 16000 -ac 1 "${1%.*}.$2" > /dev/null 2>&1
 72 ffmpeg_pid=$!
 73 while kill -0 "$ffmpeg_pid"; do sleep 1; done > /dev/null 2>&1
 74 rm "$1.pcm"
 75 [ ! -f "${1%.*}.$2" ]&&echo -e "${YELLOW}[Warning]${RESET} Convert $1 false, maybe ffmpeg no format handler for $2."&&exit
 76 echo -e "${GREEN}[OK]${RESET} Convert $1 To ${1%.*}.$2 Finish."
 77 exit
  • python+flask+silk2wav+百度云resultApi

此步骤,通过flask搭建http服务器,接受小程序上传过来的silk语音文件,然后通过python调用shell脚本进行转码,再把转码后的wav语音文件调用百度api进行识别。

@app.route('/voice_detec', methods=['POST','GET'])  
def voice_detec():  
    if request.method == 'POST':  
        # print('POST:',request.form)
        # 接受小程序上传的文件
        voice_file = request.files['voice']
        if voice_file:
            # 存储到磁盘
            voice_file.save('2.silk')
            # 转码,这里需要注意文件放的位置,将在下面给出文件位置
            msg=os.system('sudo sh silk-v3-decoder/converter.sh ../2.silk wav')
            print(msg)
            f=open('2.wav','rb')
            # 调用api识别
            result=baidu_client.asr(f.read(),'wav',16000,{
                'dev_pid':1537,
            })
            f.close()
            print(result)
            # 返回识别结果
            return json.dumps(result)
        return '{'err_no':10010}'

 

整个服务器项目的目录结构:

webproject
    ├── 2.silk # 服务器上传的文件包存2.silk
    ├── 2.wav  #转码结果
    ├── http.py # 代码
    ├── silk-v3-decoder #github下载的源码+make后的文件
    │   ├── converter_beta.sh
    │   ├── converter.sh
    │   ├── conv.sh
    │   ├── LICENSE
    │   ├── README.md
    │   ├── silk
    │   └── windows

 

3.百度云:

语音识别api配置:这个直接看官方文档吧,很清楚。

4.爬坑指南

  1. 不要企图使用电脑客户端的缓存的.silk去转换,和真机环境不是一个类型
  2.  使用python2的朋友可能会面临字符串转码的问题,头痛
  3. silk-v3-decoder 编译过程报错或者警告问题

 

 

 

2018-03-23 11:19:47 qq_33945246 阅读数 16203

——利用讯飞开发平台作为第三方库

首先需要在讯飞开发平台下载SDK,网址为,讯飞开发平台,这些SDK 下载都是免费的,当然你需要先注册。在SDK 中不仅包含相应的jar包,还有一些相应的demo,可以供你参考学习

讯飞开发平台

在我们下载下来第一个SDK 之后就可以进行开发了,讯飞的SDK 给我们提供了详尽而强大的函数支持,下面我就从代码的角度来进行一些解释。

代码


package myVoice;

import java.awt.Button;

import java.awt.Font;

import java.awt.Frame;

import java.awt.GridLayout;

import java.awt.Panel;

import java.awt.TextArea;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import java.lang.reflect.Parameter;

import java.util.ArrayList;

import javax.swing.ImageIcon;

import javax.swing.JFrame;

import javax.swing.JLabel;

import com.iflytek.cloud.speech.RecognizerListener;

import com.iflytek.cloud.speech.RecognizerResult;

import com.iflytek.cloud.speech.SpeechError;

import com.iflytek.cloud.speech.SpeechRecognizer;

import com.iflytek.cloud.speech.SpeechUtility;

import com.iflytek.util.DebugLog;

import com.iflytek.util.JsonParser;

import com.iflytek.util.Version;

public class VoiceSpeech extends Frame implements ActionListener {

Button startBtn;

Button stopBtn;

TextArea textArea;

// 语音听写对象

SpeechRecognizer speechRecognize;

private static final String DEF_FONT_NAME = "宋体";

private static final int DEF_FONT_STYLE = Font.BOLD;

private static final int DEF_FONT_SIZE = 30;

private static final int TEXT_COUNT = 100;

public VoiceSpeech() {

// 初始化听写对象

speechRecognize = SpeechRecognizer.createRecognizer();

// 设置组件

startBtn = new Button("start");

stopBtn = new Button("stop");

textArea = new TextArea();

Panel btnPanel = new Panel();

Panel textPanel = new Panel();

// Button startBtn = new Button("开始");

//添加监听器

startBtn.addActionListener(this);

stopBtn.addActionListener(this);

btnPanel.add(startBtn);

btnPanel.add(stopBtn);

textPanel.add(textArea);

add(btnPanel);

add(textPanel);

// 设置窗体

setLayout(new GridLayout(2, 1));

setSize(400, 300);

setTitle("语音识别");

setLocation(200, 200);

setVisible(true);

}

public void actionPerformed(ActionEvent e) {

if (e.getSource() == startBtn) {

textArea.setText("*************你说的是:");

if (!speechRecognize.isListening())

speechRecognize.startListening(recognizerListener);

else

speechRecognize.stopListening();

} else if (e.getSource() == stopBtn) {

speechRecognize.stopListening();

}

}

/**

* 听写监听器

*/

private RecognizerListener recognizerListener = new RecognizerListener() {

public void onBeginOfSpeech() {

// DebugLog.Log( "onBeginOfSpeech enter" );

// ((JLabel) jbtnRecognizer.getComponent(0)).setText("听写中...");

// jbtnRecognizer.setEnabled(false);

}

public void onEndOfSpeech() {

DebugLog.Log("onEndOfSpeech enter");

}

/**

* 获取听写结果. 获取RecognizerResult类型的识别结果,并对结果进行累加,显示到Area里

*/

public void onResult(RecognizerResult results, boolean islast) {

DebugLog.Log("onResult enter");

// 如果要解析json结果,请考本项目示例的 com.iflytek.util.JsonParser类

String text =

JsonParser.parseIatResult(results.getResultString());

//  String text = results.getResultString();

//  JsonParser json = new JsonParser();

//      String newTest = json.parseIatResult(text);

//      textArea.setText(newTest);

textArea.append(text);

text = textArea.getText();

if (null != text) {

int n = text.length() / TEXT_COUNT + 1;

int fontSize = Math.max(10, DEF_FONT_SIZE - 2 * n);

DebugLog.Log("onResult new font size=" + fontSize);

int style = n > 1 ? Font.PLAIN : DEF_FONT_SIZE;

Font newFont = new Font(DEF_FONT_NAME, style, fontSize);

textArea.setFont(newFont);

}

if (islast) {

iatSpeechInitUI();

}

}

public void onVolumeChanged(int volume) {

DebugLog.Log("onVolumeChanged enter");

if (volume == 0)

volume = 1;

else if (volume >= 6)

volume = 6;

// labelWav.setIcon(new ImageIcon("res/mic_0" + volume + ".png"));

}

public void onError(SpeechError error) {

DebugLog.Log("onError enter");

if (null != error) {

DebugLog.Log("onError Code:" + error.getErrorCode());

textArea.setText(error.getErrorDescription(true));

iatSpeechInitUI();

}

}

public void onEvent(int eventType, int arg1, int agr2, String msg) {

DebugLog.Log("onEvent enter");

}

};

/**

* 听写结束,恢复初始状态

*/

public void iatSpeechInitUI() {

// labelWav.setIcon(new ImageIcon("res/mic_01.png"));

// jbtnRecognizer.setEnabled(true);

// ((JLabel) jbtnRecognizer.getComponent(0)).setText("开始听写");

}

public static void main(String[] args) {

// 初始化

StringBuffer param = new StringBuffer();

param.append( "appid=" + Version.getAppid() );

//  param.append( ","+SpeechConstant.LIB_NAME_32+"=myMscName" );

SpeechUtility.createUtility( param.toString() );

VoiceSpeech t = new VoiceSpeech();

}

}

代码解析

1.SpeechRecognizer类,语音识别类,语音识别,包括听写、语法识别功能。本类使用单例,调用者使用本类的对象,只需要通过createRecognizer()创建 一次对象后,便可一直使用该对象,直到通过调用destroy()进行单例对象销毁。调 用者可通过getRecognizer()获取当前已经创建的单例。我们在一开始导包,把相应的类导入,然后声明语音识别类,然后在VoiceSpeech类的构造器中初始化。

2.在SpeechRecognizer类中有很多有关语音识别的方法,

(1)startListening方法,开始进行语音识别,其方法的参数是一个回调函数,这个方法是另一个类RecognizerListener声明的实例,在其匿名内部类中重写关键的方法,借此到底我们想要的结果,我们在onResult方法中重写,把识别的结果通过json解析之后(识别的结果默认是json格式),把它依次添加到文本栏上面,之后我们对文本栏的内容进行文字字体大小等的设定

(2)stopListening方法,等录音结束之后,调用该方法,把录音结果通过网络传输给讯飞远程识别平台进行解析,解析完成之后,把解析结果传送过来

3.在main方法中先要进行SpeechUtility.createUtility,这是讯飞SDK的初始化,相当于远程连接讯飞识别平台,因为Java现在还不支持离线识别,所以在进行识别方法调用之前,必须连接讯飞开发平台,这个方法的作用正是如此,其参数就是不同的识别版本

4.因为很多方法都是讯飞提供的,所以我们需要导入相应的包

具体如下


import com.iflytek.cloud.speech.RecognizerListener;

import com.iflytek.cloud.speech.RecognizerResult;

import com.iflytek.cloud.speech.SpeechError;

import com.iflytek.cloud.speech.SpeechRecognizer;

import com.iflytek.cloud.speech.SpeechUtility;

import com.iflytek.util.DebugLog;

import com.iflytek.util.JsonParser;//json解析类

import com.iflytek.util.Version;//版本类

这些在SDK 中都有

最终的结果

ps:因为只是注重识别功能,所以界面很丑。。。

最终截图

2016-11-07 16:55:49 tiandijun 阅读数 11078

科大讯飞开放平台

http://www.xfyun.cn/

大致开发流程

想要使用科大的语音功能:

  1. 首先必须要注册一个开发者账号
  2. 然后新建一个应用
  3. 新建完成以后,需要开通你想要使用的功能,例如语音识别、语音合成、语义理解等等
  4. 下载sdk
  5. 集成开发

注意:

  • 创建完应用以后,会生成一个AppId,这个AppId是和SDK对应的,如果你在工程中用到的AppId和对应的库对应不上,在使用接口的时候会报错
  • 你要使用什么功能,必须要先开通服务以后才能使用。

 

 

创建应用以及开通服务

1)创建开发者帐号

右上角注册

2) 登录

右上角登录

3) 创建应用

 

4) 填写应用信息

5) 开通服务

填写完应用信息,提交以后,跳转到我的应用,新创建的应用是默认没有开通任何服务的,我们要使用哪些功能,需要开通对应的服务

点击立即开通

选择要开通的服务,点击确定

选择完要开通的服务以后会提示下载SDK

 

6)下载SDK

下载SDK,如果开通的是单个服务,就选择单个服务下载,多个服务就选择组合服务SDK下载,这就不用多说了。

应用审核

当应用开通完服务并且下载过SDK以后,应用后面会显示审核入口按钮,有的应用后面没有,是因为你还没有开通服务或者还没有下载过SDK,因为appid和SDK是对应的,如果你都还没下载过SDK,讯飞认为你肯定还没有把SDK集成到你自己的工程中,这种情况下是不允许审核的。

注意

下载的SDK里面除了Demo还会对应的给出so库、jar包、和一些资源文件,尤其要注意的是,so库和资源文件是和你的appid一一对应的,绝对不能和其他appid混用,否则会报错,导致程序无法正常运行

 

开始写一个集成的语音听写接口demo

 

(一)准备工作

  0、创建一个空的Android项目,比如项目名叫:SpeechRecognitionDemoJYJ。

  1、首先要在科大讯飞开放平台(http://www.xfyun.cn/)上注册

  2、点击网站首页右上角的“控制台”,进入控制台。

  3、按照说明创建一个应用,该应用名就叫SpeechRecognitionDemoJYJ,创建成功后会有一个AppID,记下来,编程的时候要用到。

  4、点击SpeechRecognitionDemoJYJ后面的“开通服务”按钮,开通服务—>语音听写,进入语音听写—>下载当前应用对应的SDK。

  5、下载Android版的SDK,将SDK包中libs目录下的Msc.jar和armeabi复制到Android工程的libs目录(如果工程无libs目录,请自行创建)中,并且因为还要用到语音听写Dialog,所以还要把SDK包中assets目录下的iflytek文件夹复制到工程的assets目录下,如下图所示。还要注意,每个不同的应用都要申请不同的AppID,并且要分别下载不同AppID对应的SDK,否则会出错。

 6、其他更详细的说明和资料可以参看讯飞开放平台的资料库(http://www.xfyun.cn/doccenter)。

 

  (二)开发

  Demo实现的功能很简单,就是点击一个按钮,弹出语音识别Dialog窗口,说话,说完了点击Dialog窗口后会把自动识别的文字结果显示在下方的EditText中。服务器返回的语音听写的结果是Json格式数据,最后还要对Json数据进行解析(具体解析方法参看我的这篇文章:用GSON解析Json格式数据),解析出语音字符串。

  

1、XML代码:

  界面中有一个按钮,一个TextView和一个EditText,EditText用于显示语音识别的结果。

1 
 5 
 6     


2、MainActivity


  1 import java.lang.reflect.Type;
  2 import java.util.List;
  3 
  4 import com.example.speechrecognition.DictationResult;
  5 import com.google.gson.Gson;
  6 import com.google.gson.reflect.TypeToken;
  7 import com.iflytek.cloud.RecognizerListener;
  8 import com.iflytek.cloud.RecognizerResult;
  9 import com.iflytek.cloud.SpeechConstant;
 10 import com.iflytek.cloud.SpeechError;
 11 import com.iflytek.cloud.SpeechRecognizer;
 12 import com.iflytek.cloud.SpeechUtility;
 13 import com.iflytek.cloud.ui.RecognizerDialog;
 14 import com.iflytek.cloud.ui.RecognizerDialogListener;
 15 
 16 import android.app.Activity;
 17 import android.content.Context;
 18 import android.os.Bundle;
 19 import android.os.Handler;
 20 import android.os.Message;
 21 import android.util.Log;
 22 import android.view.Menu;
 23 import android.view.MenuItem;
 24 import android.view.View;
 25 import android.view.View.OnClickListener;
 26 import android.view.inputmethod.InputMethodManager;
 27 import android.widget.Button;
 28 import android.widget.EditText;
 29 import android.widget.TextView;
 30 
 31 public class MainActivity extends Activity implements OnClickListener {
 32     private static String APPID = "569e39a1";
 33 
 34     private Button listenBtn;
 35     private EditText contentEt;
 36 
 37     // 听写结果字符串(多个Json的列表字符串)
 38     private String dictationResultStr = "[";
 39 
 40     @Override
 41     protected void onCreate(Bundle savedInstanceState) {
 42         super.onCreate(savedInstanceState);
 43         setContentView(R.layout.activity_main);
 44 
 45         listenBtn = (Button) findViewById(R.id.listen_btn);
 46         contentEt = (EditText) findViewById(R.id.content_et);
 47 
 48         listenBtn.setOnClickListener(this);
 49 
 50     }
 51 
 52     @Override
 53     public void onClick(View v) {
 54         switch (v.getId()) {
 55         case R.id.listen_btn:
 56 
 57             dictationResultStr = "[";
 58             // 语音配置对象初始化
 59             SpeechUtility.createUtility(MainActivity.this, SpeechConstant.APPID
 60                     + "=" + APPID);
 61 
 62             // 1.创建SpeechRecognizer对象,第2个参数:本地听写时传InitListener
 63             SpeechRecognizer mIat = SpeechRecognizer.createRecognizer(
 64                     MainActivity.this, null);
 65             // 交互动画
 66             RecognizerDialog iatDialog = new RecognizerDialog(
 67                     MainActivity.this, null);
 68             // 2.设置听写参数,详见《科大讯飞MSC API手册(Android)》SpeechConstant类
 69             mIat.setParameter(SpeechConstant.DOMAIN, "iat"); // domain:域名
 70             mIat.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
 71             mIat.setParameter(SpeechConstant.ACCENT, "mandarin"); // mandarin:普通话
 72             
 73             //3.开始听写
 74             iatDialog.setListener(new RecognizerDialogListener() {
 75 
 76                 @Override
 77                 public void onResult(RecognizerResult results, boolean isLast) {
 78                     // TODO 自动生成的方法存根
 79                     // Log.d("Result", results.getResultString());
 80                     // contentTv.setText(results.getResultString());
 81                     if (!isLast) {
 82                         dictationResultStr += results.getResultString() + ",";
 83                     } else {
 84                         dictationResultStr += results.getResultString() + "]";
 85                     }
 86                     if (isLast) {
 87                         // 解析Json列表字符串
 88                         Gson gson = new Gson();
 89                         List dictationResultList = gson
 90                                 .fromJson(dictationResultStr,
 91                                         new TypeToken>() {
 92                                         }.getType());
 93                         String finalResult = "";
 94                         for (int i = 0; i < dictationResultList.size() - 1; i++) {
 95                             finalResult += dictationResultList.get(i)
 96                                     .toString();
 97                         }
 98                         contentEt.setText(finalResult);
 99                         
100                         //获取焦点
101                         contentEt.requestFocus();
102                         
103                         //将光标定位到文字最后,以便修改
104                         contentEt.setSelection(finalResult.length());
105                         
106                         Log.d("From reall phone", finalResult);
107                     }
108                 }
109 
110                 @Override
111                 public void onError(SpeechError error) {
112                     // TODO 自动生成的方法存根
113                     error.getPlainDescription(true);
114                 }
115             });
116 
117             // 开始听写
118             iatDialog.show();
119 
120             break;
121         default:
122             break;
123         }
124     }
125 }
 

  

3、自定义的com.example.speechrecognition.DictationResult类的代码:


  1 import java.util.List;
  2 
  3 /**
  4  * 解析语音听写返回结果Json格式字符串的模板类(多重嵌套Json)
  5  * 
  6  * 语音识别结果Json数据格式(单条数据):
  7  * {"sn":1,"ls":true,"bg":0,"ed":0,"ws":[{"bg":0,"cw":[{"w":"今天","sc":0}]},
  8  * {"bg":0,"cw":{"w":"的","sc":0}]},{"bg":0,"cw":[{"w":"天气","sc":0}]},
  9  * {"bg":0,"cw":[{"w":"怎么样","sc":0}]},{"bg":0,"cw":[{"w":"。","sc":0}]}]}
 10  */
 11 public class DictationResult {
 12     private String sn;
 13     private String ls;
 14     private String bg;
 15     private String ed;
 16 
 17     private List ws;
 18 
 19     public static class Words {
 20         private String bg;
 21         private List cw;
 22 
 23         public static class Cw {
 24             private String w;
 25             private String sc;
 26 
 27             public String getW() {
 28                 return w;
 29             }
 30 
 31             public void setW(String w) {
 32                 this.w = w;
 33             }
 34 
 35             public String getSc() {
 36                 return sc;
 37             }
 38 
 39             public void setSc(String sc) {
 40                 this.sc = sc;
 41             }
 42 
 43             @Override
 44             public String toString() {
 45                 return w;
 46             }
 47         }
 48 
 49         public String getBg() {
 50             return bg;
 51         }
 52 
 53         public void setBg(String bg) {
 54             this.bg = bg;
 55         }
 56 
 57         public List getCw() {
 58             return cw;
 59         }
 60 
 61         public void setCw(List cw) {
 62             this.cw = cw;
 63         }
 64 
 65         @Override
 66         public String toString() {
 67             String result = "";
 68             for (Cw cwTmp : cw) {
 69                 result += cwTmp.toString();
 70             }
 71             return result;
 72         }
 73     }
 74 
 75     public String getSn() {
 76         return sn;
 77     }
 78 
 79     public void setSn(String sn) {
 80         this.sn = sn;
 81     }
 82 
 83     public String getLs() {
 84         return ls;
 85     }
 86 
 87     public void setLs(String ls) {
 88         this.ls = ls;
 89     }
 90 
 91     public String getBg() {
 92         return bg;
 93     }
 94 
 95     public void setBg(String bg) {
 96         this.bg = bg;
 97     }
 98 
 99     public String getEd() {
100         return ed;
101     }
102 
103     public void setEd(String ed) {
104         this.ed = ed;
105     }
106 
107     public List getWs() {
108         return ws;
109     }
110 
111     public void setWs(List ws) {
112         this.ws = ws;
113     }
114 
115     @Override
116     public String toString() {
117         String result = "";
118         for (Words wsTmp : ws) {
119             result += wsTmp.toString();
120         }
121         return result;
122     }
123 }

  

4、AndroidManifest.xml中申请权限:

 

 1   
 2     
 3     
 4      
 5       
 6       
 7       
 8       
 9     
10     
11       
12       
13       
14       

 

5、测试:模拟器无法打开录音机,是不能在上面测试的,要用真机测试。测试结果如下图:

 

 

更多可以参考:http://blog.csdn.net/q4878802/article/category/2858977