logo资料库

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

第1页 / 共6页
第2页 / 共6页
第3页 / 共6页
第4页 / 共6页
第5页 / 共6页
第6页 / 共6页
资料共6页,全文预览结束
Android 基于百度语音的语音交互功能 基于百度语音的语音交互功能(推荐推荐) 项目里面用到了语音唤醒功能,前面一直在用讯飞的语音识别,本来打算也是直接用讯飞的语音唤醒,但是讯飞的语音唤醒要 收费,试用版只有35天有效期。只好改用百度语音,百度语音所有功能免费,功能也比较简单实用,包括语音识别,语音合 成和语音唤醒,正好可以组成一套完整的语音交互功能。 效果图: 首先是语音唤醒功能,说出关键词即可叫语音识别,唤醒成功会有语音提示,这里采用了百度语音的合成功能。然后百度语音 识别会根据wifi情况自动切换在线或者离线识别,但是离线识别只能识别已经导入的关键词,而且离线第一次识别需要联网, 识别成功,同样会有语音提示。效果图gif没有声音,Toast显示的时候就是语音提示的内容。 这里说一点,百度语音的demo里给的语音唤醒是在onResume()开始唤醒监听,唤醒成功后在onPause()里就停止唤醒 监听。而我现在要在唤醒成功后弹出语音识别的UI界面,所以弹出UI的同时就会停止唤醒监听。如果语音识别成功,UI界面消 失,唤醒监听会重新开始,此时说出唤醒词即可重新唤醒。但是如果识别失败,封装好的UI界面会变成下图情况,这时候就要 手动点击重试或者取消才可以,不符合全语音交互的理念。为了解决这个情况,要将停止唤醒监听写到onStop()里,这样 即使语音识别失败,也可以重新唤醒。 具体的集成步骤官方文档里都有,也可以参考下面的文章 //www.jb51.net/article/97329.htm 注:我这里语音识别和语音合成都用到了,所以官网下的两个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"; @Override protected 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(); } @Override protected void onResume() { super.onResume(); // 唤醒功能打开步骤 // 1) 创建唤醒事件管理器 mWpEventManager = EventManagerFactory.create(MainActivity.this, "wp"); // 2) 注册唤醒事件监听器 mWpEventManager.registerListener(new EventListener() { @Override public 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, 0); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { Bundle results = data.getExtras(); ArrayList 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,mInput.getText(),Toast.LENGTH_LONG).show(); } } private void initialTts() { this.mSpeechSynthesizer = SpeechSynthesizer.getInstance(); this.mSpeechSynthesizer.setContext(this); this.mSpeechSynthesizer.setSpeechSynthesizerListener(new SpeechSynthesizerListener() { @Override public void onSynthesizeStart(String s) { } @Override public void onSynthesizeDataArrived(String s, byte[] bytes, int i) { } @Override public void onSynthesizeFinish(String s) { } @Override public void onSpeechStart(String s) { } @Override public void onSpeechProgressChanged(String s, int i) { } @Override public void onSpeechFinish(String s) { } @Override public 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(); } // 初始化tts mSpeechSynthesizer.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, 0, 1024)) >= 0) { fos.write(buffer, 0, 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(); } } } } @Override protected void onStop() { super.onStop(); // 停止唤醒监听 mWpEventManager.send("wp.stop", null, null, 0, 0); } } 注:源码是将官网给的demo进行整合,并且删除了一些用不到的方法,简少了代码量。 activity_main:只有一个TextView和一个EditView,很简单。TextView用于显示结果,EditView用于语音合成的文字信息 AndroidManifest:添加权限和一个作为语音识别的UI的活动
android:supportsRtl="true" android:theme="@style/AppTheme"> 以上所述是小编给大家介绍的android 基于百度语音的语音交互功能,希望对大家有所帮助,如果大家有任何疑问请给我留 言,小编会及时回复大家的。在此也非常感谢大家对软件开发网网站的支持! 您可能感兴趣的文章:Android基于讯飞语音SDK实现语音识别Android仿微信语音聊天功能Android实现语音识别代码android预 您可能感兴趣的文章 置默认的语音信箱号码具体实现Android Studio应用开发集成百度语音合成使用方法实例讲解Android 轻松实现语音识别详解 及实例代码Android实现客户端语音动弹界面实例代码
分享到:
收藏