Android 基于百度语音的语音交互功能(推荐)

Android 基于百度语音的语音交互功能(推荐),第1张

概述项目里面用到了语音唤醒功能,前面一直在用讯飞的语音识别,本来打算也是直接用讯飞的语音唤醒,但是讯飞的语音唤醒要收费,试用版只有35天有效期。只好改用百度语音,百度语音所有功能免费,功能也比较简单实用,包

项目里面用到了语音唤醒功能,前面一直在用讯飞的语音识别,本来打算也是直接用讯飞的语音唤醒,但是讯飞的语音唤醒要收费,试用版只有35天有效期。只好改用百度语音,百度语音所有功能免费,功能也比较简单实用,包括语音识别,语音合成和语音唤醒,正好可以组成一套完整的语音交互功能。

效果图:

首先是语音唤醒功能,说出关键词即可叫语音识别,唤醒成功会有语音提示,这里采用了百度语音的合成功能。然后百度语音识别会根据wifi情况自动切换在线或者离线识别,但是离线识别只能识别已经导入的关键词,而且离线第一次识别需要联网,识别成功,同样会有语音提示。效果图gif没有声音,Toast显示的时候就是语音提示的内容。

这里说一点,百度语音的demo里给的语音唤醒是在onResume()开始唤醒监听,唤醒成功后在onPause()里就停止唤醒监听。而我现在要在唤醒成功后d出语音识别的UI界面,所以d出UI的同时就会停止唤醒监听。如果语音识别成功,UI界面消失,唤醒监听会重新开始,此时说出唤醒词即可重新唤醒。但是如果识别失败,封装好的UI界面会变成下图情况,这时候就要手动点击重试或者取消才可以,不符合全语音交互的理念。为了解决这个情况,要将停止唤醒监听写到onStop()里,这样即使语音识别失败,也可以重新唤醒。

具体的集成步骤官方文档里都有,也可以参考下面的文章

https://www.oudahe.com/p/27434/

注:我这里语音识别和语音合成都用到了,所以官网下的两个sdk都要导入到工程里,这里还有个小问题,正常来说,jar包导入到工程之后,还要将assert和jnilibs文件夹放到工程里,我这里只放了语音识别的assert文件夹,jnilibs文件夹我都没放入工程里,这样可以使用。如果我将语音识别和语音合成的assert和jnilibs都放到工程里,反而会报下面的错误,不知道为什么。

java.lang.UnsatisfIEdlinkError: Native method not found: com.baIDu.speech.easr.easrNativeJni.WakeUpFree:()I

MainActivity:

package com.example.administrator.baIDuvoicetest;import androID.content.Intent;import androID.os.Bundle;import androID.os.Environment;import androID.support.v7.app.AppCompatActivity;import androID.text.TextUtils;import androID.util.AndroIDRuntimeException;import androID.util.Log;import androID.vIEw.VIEw;import androID.Widget.EditText;import androID.Widget.TextVIEw;import androID.Widget.Toast;import com.baIDu.speech.EventListener;import com.baIDu.speech.EventManager;import com.baIDu.speech.EventManagerFactory;import com.baIDu.tts.auth.AuthInfo;import com.baIDu.tts.clIEnt.SpeechError;import com.baIDu.tts.clIEnt.SpeechSynthesizer;import com.baIDu.tts.clIEnt.SpeechSynthesizerListener;import com.baIDu.tts.clIEnt.TtsMode;import org.Json.JsONException;import org.Json.JsONObject;import java.io.file;import java.io.fileNotFoundException;import java.io.fileOutputStream;import java.io.IOException;import java.io.inputStream;import java.util.ArrayList;import java.util.HashMap;public class MainActivity extends AppCompatActivity {private TextVIEw txtResult;private EditText minput;private EventManager mWpEventManager;private SpeechSynthesizer mSpeechSynthesizer;private String mSampleDirPath;private static final String SAMPLE_DIR_name = "baIDuTTS";private static final String SPEECH_FEMALE_MODEL_name = "bd_etts_speech_female.dat";private static final String SPEECH_MALE_MODEL_name = "bd_etts_speech_male.dat";private static final String TEXT_MODEL_name = "bd_etts_text.dat";private static final String liCENSE_file_name = "temp_license";private static final String ENGliSH_SPEECH_FEMALE_MODEL_name = "bd_etts_speech_female_en.dat";private static final String ENGliSH_SPEECH_MALE_MODEL_name = "bd_etts_speech_male_en.dat";private static final String ENGliSH_TEXT_MODEL_name = "bd_etts_text_en.dat";private static final String TAG = "MainActivity";@OverrIDeprotected voID onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentVIEw(R.layout.activity_main);txtResult = (TextVIEw) findVIEwByID(R.ID.txtResult);txtResult.setText("请说唤醒词: 小度你好或者百度一下\n\n"+"离在线语法识别(首次使用需要联网授权)\n"+"语音识别开始后你可以说(可以根据语法自行定义离线说法):\n" +" 1. 打电话给张三(离线)\n" +" 2. 打电话给李四(离线)\n" +" 3. 打开计算器(离线)\n" +" 4. 明天天气怎么样(需要联网)\n" +" ..." +"\n");minput= (EditText) findVIEwByID(R.ID.input);minput.setVisibility(VIEw.GONE);initialEnv();initialTts();}@OverrIDeprotected voID onResume() {super.onResume();// 唤醒功能打开步骤// 1) 创建唤醒事件管理器mWpEventManager = EventManagerFactory.create(MainActivity.this,"wp");// 2) 注册唤醒事件监听器mWpEventManager.registerListener(new EventListener() {@OverrIDepublic voID onEvent(String name,String params,byte[] data,int offset,int length) {Log.d(TAG,String.format("event: name=%s,params=%s",name,params));try {JsONObject Json = new JsONObject(params);if ("wp.data".equals(name)) { // 每次唤醒成功,将会回调name=wp.data的时间,被激活的唤醒词在params的word字段String word = Json.getString("word");txtResult.append("唤醒成功,唤醒词: " + word + "\r\n");minput.setText("唤醒成功,请说出指令");//minput.setText("succeed");Toast.makeText(MainActivity.this,minput.getText(),Toast.LENGTH_LONG).show();speak();//延时3秒,防止语音合成的内容又被语音识别try {Thread.sleep(3000);} catch (InterruptedException e) {e.printstacktrace();}Intent intent = new Intent("com.baIDu.action.RECOGNIZE_SPEECH");intent.putExtra("grammar","asset:///baIDu_speech_grammardemo.bsg"); // 设置离线的授权文件(离线模块需要授权),该语法可以用自定义语义工具生成,链接http://yuyin.baIDu.com/asr#m5//intent.putExtra("slot-data",your slots); // 设置grammar中需要覆盖的词条,如联系人名startActivityForResult(intent,1);} else if ("wp.exit".equals(name)) {txtResult.append("唤醒已经停止: " + params + "\r\n");}} catch (JsONException e) {throw new AndroIDRuntimeException(e);}}});// 3) 通知唤醒管理器,启动唤醒功能HashMap params = new HashMap();params.put("kws-file","assets:///WakeUpDemo.bin"); // 设置唤醒资源,唤醒资源请到 http://yuyin.baIDu.com/wake#m4 来评估和导出mWpEventManager.send("wp.start",new JsONObject(params).toString(),null,0);}@OverrIDeprotected voID onActivityResult(int requestCode,int resultCode,Intent data) {super.onActivityResult(requestCode,resultCode,data);if (resultCode == RESulT_OK) {Bundle results = data.getExtras();ArrayList<String> results_recognition = results.getStringArrayList("results_recognition");//txtResult.append("识别结果(数组形式): " + results_recognition + "\n");//将数组形式的识别结果变为正常的String类型,例:[给张三打电话]变成给张三打电话String str=results_recognition+"";String res=str.substring(str.indexOf("[")+1,str.indexOf("]"));txtResult.append(res+"\n");minput.setText("好的,马上执行"+res);speak();Toast.makeText(MainActivity.this,Toast.LENGTH_LONG).show();}}private voID initialTts() {this.mSpeechSynthesizer = SpeechSynthesizer.getInstance();this.mSpeechSynthesizer.setContext(this);this.mSpeechSynthesizer.setSpeechSynthesizerListener(new SpeechSynthesizerListener() {@OverrIDepublic voID onSynthesizeStart(String s) {}@OverrIDepublic voID onSynthesizeDataArrived(String s,byte[] bytes,int i) {}@OverrIDepublic voID onSynthesizefinish(String s) {}@OverrIDepublic voID onSpeechStart(String s) {}@OverrIDepublic voID onSpeechProgressChanged(String s,int i) {}@OverrIDepublic voID onSpeechFinish(String s) {}@OverrIDepublic voID onError(String s,SpeechError speechError) {}});// 文本模型文件路径 (离线引擎使用)this.mSpeechSynthesizer.setParam(SpeechSynthesizer.ParaM_TTS_TEXT_MODEL_file,mSampleDirPath + "/"+ TEXT_MODEL_name);// 声学模型文件路径 (离线引擎使用)this.mSpeechSynthesizer.setParam(SpeechSynthesizer.ParaM_TTS_SPEECH_MODEL_file,mSampleDirPath + "/"+ SPEECH_FEMALE_MODEL_name);// 本地授权文件路径,如未设置将使用默认路径.设置临时授权文件路径,liCENCE_file_name请替换成临时授权文件的实际路径,仅在使用临时license文件时需要进行设置,如果在[应用管理]中开通了正式离线授权,不需要设置该参数,建议将该行代码删除(离线引擎)// 如果合成结果出现临时授权文件将要到期的提示,说明使用了临时授权文件,请删除临时授权即可。this.mSpeechSynthesizer.setParam(SpeechSynthesizer.ParaM_TTS_liCENCE_file,mSampleDirPath + "/"+ liCENSE_file_name);// 请替换为语音开发者平台上注册应用得到的App ID (离线授权)this.mSpeechSynthesizer.setAppID("xxx"/*这里只是为了让Demo运行使用的APPID,请替换成自己的ID。*/);// 请替换为语音开发者平台注册应用得到的APIkey和secretkey (在线授权)this.mSpeechSynthesizer.setAPIKey("xxx","xxx"/*这里只是为了让Demo正常运行使用APIKey,请替换成自己的APIKey*/);// 发音人(在线引擎),可用参数为0,1,2,3。。。(服务器端会动态增加,各值含义参考文档,以文档说明为准。0--普通女声,1--普通男声,2--特别男声,3--情感男声。。。)this.mSpeechSynthesizer.setParam(SpeechSynthesizer.ParaM_SPEAKER,"0");// 设置Mix模式的合成策略this.mSpeechSynthesizer.setParam(SpeechSynthesizer.ParaM_MIX_MODE,SpeechSynthesizer.MIX_MODE_DEFAulT);// 授权检测接口(只是通过AuthInfo进行检验授权是否成功。)// AuthInfo接口用于测试开发者是否成功申请了在线或者离线授权,如果测试授权成功了,可以删除AuthInfo部分的代码(该接口首次验证时比较耗时),不会影响正常使用(合成使用时SDK内部会自动验证授权)AuthInfo authInfo = this.mSpeechSynthesizer.auth(TtsMode.MIX);if (authInfo.isSuccess()) {Toast.makeText(this,"auth success",Toast.LENGTH_LONG).show();} else {String errorMsg = authInfo.getTtsError().getDetailMessage();Toast.makeText(this,"auth Failed errorMsg=" + errorMsg,Toast.LENGTH_LONG).show();}// 初始化ttsmSpeechSynthesizer.initTts(TtsMode.MIX);// 加载离线英文资源(提供离线英文合成功能)int result =mSpeechSynthesizer.loadEnglishModel(mSampleDirPath + "/" + ENGliSH_TEXT_MODEL_name,mSampleDirPath+ "/" + ENGliSH_SPEECH_FEMALE_MODEL_name);//Toast.makeText(this,"loadEnglishModel result=" + result,Toast.LENGTH_LONG).show();//打印引擎信息和model基本信息//printEngineInfo();}private voID speak() {String text = this.minput.getText().toString();//需要合成的文本text的长度不能超过1024个GBK字节。if (TextUtils.isEmpty(minput.getText())) {text = "欢迎使用百度语音合成SDK,百度语音为你提供支持。";minput.setText(text);}int result = this.mSpeechSynthesizer.speak(text);if (result < 0) {Toast.makeText(this,"error,please look up error code in doc or URL:http://yuyin.baIDu.com/docs/tts/122 ",Toast.LENGTH_LONG).show();}}private voID initialEnv() {if (mSampleDirPath == null) {String sdcardpath = Environment.getExternalStorageDirectory().toString();mSampleDirPath = sdcardpath + "/" + SAMPLE_DIR_name;}makeDir(mSampleDirPath);copyFromAssetsToSdcard(false,SPEECH_FEMALE_MODEL_name,mSampleDirPath + "/" + SPEECH_FEMALE_MODEL_name);copyFromAssetsToSdcard(false,SPEECH_MALE_MODEL_name,mSampleDirPath + "/" + SPEECH_MALE_MODEL_name);copyFromAssetsToSdcard(false,TEXT_MODEL_name,mSampleDirPath + "/" + TEXT_MODEL_name);copyFromAssetsToSdcard(false,liCENSE_file_name,mSampleDirPath + "/" + liCENSE_file_name);copyFromAssetsToSdcard(false,"english/" + ENGliSH_SPEECH_FEMALE_MODEL_name,mSampleDirPath + "/"+ ENGliSH_SPEECH_FEMALE_MODEL_name);copyFromAssetsToSdcard(false,"english/" + ENGliSH_SPEECH_MALE_MODEL_name,mSampleDirPath + "/"+ ENGliSH_SPEECH_MALE_MODEL_name);copyFromAssetsToSdcard(false,"english/" + ENGliSH_TEXT_MODEL_name,mSampleDirPath + "/"+ ENGliSH_TEXT_MODEL_name);}private voID makeDir(String dirPath) {file file = new file(dirPath);if (!file.exists()) {file.mkdirs();}}/*** 将sample工程需要的资源文件拷贝到SD卡中使用(授权文件为临时授权文件,请注册正式授权)** @param isCover 是否覆盖已存在的目标文件* @param source* @param dest*/private voID copyFromAssetsToSdcard(boolean isCover,String source,String dest) {file file = new file(dest);if (isCover || (!isCover && !file.exists())) {inputStream is = null;fileOutputStream fos = null;try {is = getResources().getAssets().open(source);String path = dest;fos = new fileOutputStream(path);byte[] buffer = new byte[1024];int size = 0;while ((size = is.read(buffer,1024)) >= 0) {fos.write(buffer,size);}} catch (fileNotFoundException e) {e.printstacktrace();} catch (IOException e) {e.printstacktrace();} finally {if (fos != null) {try {fos.close();} catch (IOException e) {e.printstacktrace();}}try {if (is != null) {is.close();}} catch (IOException e) {e.printstacktrace();}}}}@OverrIDeprotected voID onStop() {super.onStop();// 停止唤醒监听mWpEventManager.send("wp.stop",0);}}

注:源码是将官网给的demo进行整合,并且删除了一些用不到的方法,简少了代码量。

activity_main:只有一个TextVIEw和一个EditVIEw,很简单。TextVIEw用于显示结果,EditVIEw用于语音合成的文字信息

<?xml version="1.0" enCoding="utf-8"?><linearLayout xmlns:androID="http://schemas.androID.com/apk/res/androID"xmlns:tools="http://schemas.androID.com/tools"androID:ID="@+ID/activity_main"androID:layout_wIDth="match_parent"androID:layout_height="match_parent"androID:orIEntation="vertical"tools:context="com.example.administrator.baIDuvoicetest.MainActivity"><TextVIEwandroID:layout_wIDth="match_parent"androID:layout_height="wrap_content"androID:textSize="18dp"androID:padding="8dp"androID:ID="@+ID/txtResult" /><EditTextandroID:ID="@+ID/input"androID:layout_wIDth="fill_parent"androID:layout_height="wrap_content"androID:hint="input" /></linearLayout>

AndroIDManifest:添加权限和一个作为语音识别的UI的活动

<?xml version="1.0" enCoding="utf-8"?><manifest xmlns:androID="http://schemas.androID.com/apk/res/androID"package="com.example.administrator.baIDuvoicetest"><uses-permission androID:name="androID.permission.RECORD_AUdio" /><uses-permission androID:name="androID.permission.ACCESS_NETWORK_STATE" /><uses-permission androID:name="androID.permission.INTERNET" /><uses-permission androID:name="androID.permission.READ_PHONE_STATE" /><uses-permission androID:name="androID.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission androID:name="androID.permission.ACCESS_WIFI_STATE" /><uses-permission androID:name="androID.permission.CHANGE_WIFI_STATE" /><uses-permission androID:name="androID.permission.MODIFY_AUdio_SETTINGS" /><uses-permission androID:name="androID.permission.WRITE_SETTINGS" /><applicationandroID:allowBackup="true"androID:icon="@mipmap/ic_launcher"androID:label="@string/app_name"androID:supportsRtl="true"androID:theme="@style/Apptheme"><!-- begin: baIDu speech sdk--><!--离线功能指南:1. 在百度语音开放平台注册应用,http://yuyin.baIDu.com/app2. 为您的应用的“申请离线授权页面”,填写程序包名3. 在当前应用的AndroIDManifest.xml中填写相应的APP_ID(或在代码中设置appID参数)4. 根据场景下载并集成相应的资源,见http://yuyin.baIDu.com/docs/asr/131和http://yuyin.baIDu.com/asr/download另外需要注意的是离线功能只是在线功能的“增强”,不能永久不联网使用(特别是首次使用)。--><!-- 请填写真实的APP_ID API_KEY SECRET_KEY --><Meta-data androID:name="com.baIDu.speech.APP_ID" androID:value="8888274"/><Meta-data androID:name="com.baIDu.speech.API_KEY" androID:value="FOFOGnjFERG3UTZC4FdDnXhM"/><Meta-data androID:name="com.baIDu.speech.SECRET_KEY" androID:value="63830985f5b05d2863f13ad07c7feaa3"/><service androID:name="com.baIDu.speech.VoiceRecognitionService" androID:exported="false" /><activityandroID:name="com.baIDu.voicerecognition.androID.ui.BaIDuASRDigitalDialog"androID:configChanges="orIEntation|keyboardHIDden|screenLayout"androID:theme="@androID:style/theme.Dialog"androID:exported="false"androID:screenorIEntation="portrait"><intent-filter><action androID:name="com.baIDu.action.RECOGNIZE_SPEECH" /><category androID:name="androID.intent.category.DEFAulT" /></intent-filter></activity><!-- end : baIDu speech sdk--><activity androID:name=".MainActivity"><intent-filter><action androID:name="androID.intent.action.MAIN" /><category androID:name="androID.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>

以上所述是小编给大家介绍的androID 基于百度语音的语音交互功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对编程小技巧网站的支持!

总结

以上是内存溢出为你收集整理的Android 基于百度语音的语音交互功能(推荐)全部内容,希望文章能够帮你解决Android 基于百度语音的语音交互功能(推荐)所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1147686.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存