https://ai.baidu.com/sdk#tts
本教程使用AndroidStudio3.6.3版本
由于是第三方插件,并且项目中已经有了一个第三方的插件,众所周知,Unity与安卓交互时,安卓端只能有一个Activity继承自UnityPlayerActivity,所以为了不与其他人的sdk冲突,我们便使用不继承UnityPlayerActivity的Java类
并且创建安卓版语音技术应用
jar包位于core/libs/目录下
在我们创建好的项目中导入该sdk,
如何创建项目请参考我的另一篇博文
https://blog.csdn.net/weixin_43271060/article/details/90318254
导入步骤
选中jar包,然后按下Ctrl+C,在我们创建好的项目中选择Libs目录,然后按下Ctrl+V,这是导入,然后就是引用
1、选择File->Project Structure打开Project Structure窗口
2、选择Dependencies->我们自己创建的Module
选择我们导入的jar包
最后点击Apply
导入官方的库文件,位于core->src-main下方
jniLibs目录下就是我们所需的库文件,然后复制jniLibs文件夹,然后粘贴到我们的项目中的src->main目录下
1、创建百度语音主类,然后将它制成单利
public static CientBaiDuVoiceMainActivity _instance; public static CientBaiDuVoiceMainActivity getInstance() { if (_instance == null) { _instance = new CientBaiDuVoiceMainActivity(); } return _instance; }2、编写语音识别
选择包名,然后右键创建一个Package,名字为Recogn
3、创建语音识别监听识别后回调的类
package com.xxx.xxx.Recogn;//填写自己的包名 import com.baidu.speech.EventListener; import com.baidu.speech.asr.SpeechConstant; import com.unity3d.player.UnityPlayer; public class RecognListener implements EventListener { @Override public void onEvent(String name, String params, byte[] data, int i, int i1) { if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_PARTIAL)) { // 识别相关的结果都在这里 if (params == null || params.isEmpty()) { return; } if (params.contains("\"partial_result\"")) { UnityPlayer.UnitySendMessage("NetLogic", "RecognResult", name + "&" + params); // 一句话的临时识别结果 } else if (params.contains("\"final_result\"")) { UnityPlayer.UnitySendMessage("NetLogic", "RecognResult", name + "&" + params); // 一句话的最终识别结果 } else { // 一般这里不会运行 if (data != null) { } } } else { // 识别开始,结束,音量,音频数据回调 if (params != null && !params.isEmpty()) { } if (data != null) { } } } };4、编写语音识别处理类
package com.xxx.xxx.Recogn;//自己的包名 import android.Manifest; import android.content.Context; import android.content.pm.PackageManager; import android.os.Build; import com.baidu.speech.EventListener; import com.baidu.speech.EventManager; import com.baidu.speech.EventManagerFactory; import com.baidu.speech.asr.SpeechConstant; import org.json.JSONObject; import java.util.LinkedHashMap; import java.util.Map; import static com.xxx.xxx.Util.GetActivity.getActivityByContext; public class RecognHandler { private boolean mIsInit = false; private EventManager asr; private EventListener mEventLisener; public RecognHandler(Context context, EventListener listener) { if (mIsInit) { listener=null; return; } mIsInit = true; mEventLisener = listener; //动态申请权限 initPermission(context); asr = EventManagerFactory.create(context, "asr"); asr.registerListener(listener); } //开始识别 public void Start() { Map<String, Object> params = new LinkedHashMap<String, Object>(); // 基于SDK集成2.1 设置识别参数 params.put(SpeechConstant.ACCEPT_AUDIO_VOLUME, true); params.put(SpeechConstant.DISABLE_PUNCTUATION, false); params.put(SpeechConstant.ACCEPT_AUDIO_DATA, false); params.put(SpeechConstant.PID, 1537); // 中文输入法模型,有逗号 String json = null; // 可以替换成自己的json json = new JSONObject(params).toString(); // 这里可以替换成你需要测试的json asr.send(SpeechConstant.ASR_START, json, null, 0, 0); } //停止识别 public void Stop() { asr.send(SpeechConstant.ASR_STOP, null, null, 0, 0); } //释放实例 public void Release() { asr.unregisterListener(mEventLisener); mIsInit = false; asr=null; } /** * android 6.0 以上需要动态申请权限 */ private void initPermission(Context context) { String permissions[] = {Manifest.permission.RECORD_AUDIO, Manifest.permission.ACCESS_NETWORK_STATE, Manifest.permission.INTERNET, Manifest.permission.WRITE_EXTERNAL_STORAGE }; PackageManager pm = getActivityByContext(context).getPackageManager(); boolean permission_readStorage = (PackageManager.PERMISSION_GRANTED == pm.checkPermission("android.permission.RECORD_AUDIO", "com.cientx.tianguo")); boolean permission_network_state = (PackageManager.PERMISSION_GRANTED == pm.checkPermission("android.permission.ACCESS_NETWORK_STATE", "com.cientx.tianguo")); boolean permission_internet = (PackageManager.PERMISSION_GRANTED == pm.checkPermission("android.permission.INTERNET", "com.cientx.tianguo")); boolean permission_writeStorage = (PackageManager.PERMISSION_GRANTED == pm.checkPermission("android.permission.WRITE_EXTERNAL_STORAGE", "com.cientx.tianguo")); if (!(permission_readStorage && permission_writeStorage && permission_network_state && permission_internet)) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { getActivityByContext(context).requestPermissions(permissions, 0x01); } } } }5、创建一个工具Package名字叫Util
里面添加两个类,GetActivity用户根据Context获取Activity,LogPrint用于输出日志
package com.xxx.xxx.Util;//自己的包名 import android.app.Activity; import android.content.Context; import android.content.ContextWrapper; public class GetActivity { public static Activity getActivityByContext(Context context){ while(context instanceof ContextWrapper){ if(context instanceof Activity){ return (Activity) context; } context = ((ContextWrapper) context).getBaseContext(); } return null; } }package com.xxx.xxx.Util;//自己的包名 import com.tencent.mm.opensdk.utils.Log; public class LogPrint { public static void Log(String logStr){ Log.d("AndroidLog",logStr); } }
6、创建一个用于语音唤醒的Package名字叫Wakeup,并且创建三个类WakeupHandler(处理唤醒)、WakeupListener(监听唤醒结果)、WakeUpResult(唤醒结果解析获取)
package com.xxx.xxx.Wakeup;//自己的包名 import com.baidu.speech.EventListener; import com.baidu.speech.asr.SpeechConstant; import com.unity3d.player.UnityPlayer; public class WakeupListener implements EventListener { @Override public void onEvent(String name, String params, byte[] bytes, int i, int i1) { if (SpeechConstant.CALLBACK_EVENT_WAKEUP_SUCCESS.equals(name)) { // 识别唤醒词成功 WakeUpResult result = WakeUpResult.parseJson(name, params); int errorCode = result.getErrorCode(); if (result.hasError()) { // error不为0依旧有可能是异常情况 } else { String word = result.getWord(); //将结果发送给Unity UnityPlayer.UnitySendMessage("NetLogic", "WakeupResult", name+"&"+params); } } else if (SpeechConstant.CALLBACK_EVENT_WAKEUP_ERROR.equals(name)) { // 识别唤醒词报错 WakeUpResult result = WakeUpResult.parseJson(name, params); int errorCode = result.getErrorCode(); if (result.hasError()) { } } else if (SpeechConstant.CALLBACK_EVENT_WAKEUP_STOPED.equals(name)) { // 关闭唤醒词 } else if (SpeechConstant.CALLBACK_EVENT_WAKEUP_AUDIO.equals(name)) { // 音频回调 } } }package com.xxx.xxx.Wakeup; import com.baidu.speech.asr.SpeechConstant; import org.json.JSONException; import org.json.JSONObject; public class WakeUpResult { private String name; private String origalJson; private String word; private String desc; private int errorCode; private static int ERROR_NONE = 0; private static final String TAG = "WakeUpResult"; public boolean hasError() { return errorCode != ERROR_NONE; } public String getOrigalJson() { return origalJson; } public void setOrigalJson(String origalJson) { this.origalJson = origalJson; } public String getWord() { return word; } public void setWord(String word) { this.word = word; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } public int getErrorCode() { return errorCode; } public void setErrorCode(int errorCode) { this.errorCode = errorCode; } public String getName() { return name; } public void setName(String name) { this.name = name; } public static WakeUpResult parseJson(String name, String jsonStr) { WakeUpResult result = new WakeUpResult(); result.setOrigalJson(jsonStr); try { JSONObject json = new JSONObject(jsonStr); if (SpeechConstant.CALLBACK_EVENT_WAKEUP_SUCCESS.equals(name)) { int error = json.optInt("errorCode"); result.setErrorCode(error); result.setDesc(json.optString("errorDesc")); if (!result.hasError()) { result.setWord(json.optString("word")); } } else { int error = json.optInt("error"); result.setErrorCode(error); result.setDesc(json.optString("desc")); } } catch (JSONException e) { e.printStackTrace(); } return result; } }
package com.xxx.xxx.Wakeup;//自己的包名 import android.Manifest; import android.content.Context; import android.content.pm.PackageManager; import android.os.Build; import com.baidu.speech.EventListener; import com.baidu.speech.EventManager; import com.baidu.speech.EventManagerFactory; import com.baidu.speech.asr.SpeechConstant; import org.json.JSONObject; import java.util.HashMap; import java.util.Map; import static com.xxx.xxx.Util.GetActivity.getActivityByContext; public class WakeupHandler { private static boolean isInited = false; private EventManager wp; private EventListener eventListener; private static final String TAG = "MyWakeup"; public WakeupHandler(Context context, EventListener eventListener) { if (isInited) { eventListener = null; return; } isInited = true; this.eventListener = eventListener; //动态申请权限 initPermission(context); wp = EventManagerFactory.create(context, "wp"); wp.registerListener(eventListener); } //开始唤醒 public void Start() { Map<String, Object> params = new HashMap<String, Object>(); params.put(SpeechConstant.WP_WORDS_FILE, "assets:///WakeUp.bin"); params.put(SpeechConstant.APP_ID, "22328262"); params.put(SpeechConstant.APP_KEY, "At03gUWQMzSysSmWHixFZ098"); params.put(SpeechConstant.SECRET, "4z1Cuow14AF4jAQmmlS1P7BiZ5HA15Vb"); String json = new JSONObject(params).toString(); wp.send(SpeechConstant.WAKEUP_START, json, null, 0, 0); } // 停止唤醒 public void Stop() { wp.send(SpeechConstant.WAKEUP_STOP, null, null, 0, 0); } //释放实例 public void Release() { wp.unregisterListener(eventListener); wp = null; isInited = false; } //申请权限 private void initPermission(Context context) { String permissions[] = {Manifest.permission.RECORD_AUDIO, Manifest.permission.ACCESS_NETWORK_STATE, Manifest.permission.INTERNET, Manifest.permission.WRITE_EXTERNAL_STORAGE }; PackageManager pm = getActivityByContext(context).getPackageManager(); boolean permission_readStorage = (PackageManager.PERMISSION_GRANTED == pm.checkPermission("android.permission.RECORD_AUDIO", "com.cientx.tianguo")); boolean permission_network_state = (PackageManager.PERMISSION_GRANTED == pm.checkPermission("android.permission.ACCESS_NETWORK_STATE", "com.cientx.tianguo")); boolean permission_internet = (PackageManager.PERMISSION_GRANTED == pm.checkPermission("android.permission.INTERNET", "com.cientx.tianguo")); boolean permission_writeStorage = (PackageManager.PERMISSION_GRANTED == pm.checkPermission("android.permission.WRITE_EXTERNAL_STORAGE", "com.cientx.tianguo")); if (!(permission_readStorage && permission_writeStorage && permission_network_state && permission_internet)) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { getActivityByContext(context).requestPermissions(permissions, 0x01); } } } }
7、在语音技术主类CientBaiDuVoiceMainActivity中调用语音识别、语音唤醒接口
//语音识别 RecognHandler mRecognHandler; //语音唤醒 WakeupHandler mWakeup; //语音合成 SpeechSynthesizerHandler mSynthesizerHandler; //语音识别初始化 public void InitRecogn(Context context) { RecognListener listener=new RecognListener(); mRecognHandler=new RecognHandler(context,listener); } //开始语音识别 public void StartRecogn() { mRecognHandler.Start(); } //停止语音识别 public void StopRecogn() { mRecognHandler.Stop(); } //释放语音识别实例 public void ReleaseRecogn() { mRecognHandler.Release(); mRecognHandler=null; } //唤醒初始化 public void InitWakeUp(Context context){ WakeupListener listener=new WakeupListener(); mWakeup = new WakeupHandler(context,listener); } //开始唤醒 public void StartWakeUp(){ mWakeup.Start(); } //停止唤醒 public void StopWakeUp(){ mWakeup.Stop(); } //释放唤醒实例 public void ReleaseWakeUp(){ mWakeup.Release(); mWakeup=null; }
因为语音唤醒是离线的,需要从百度语音技术官网中导出.bin文件
网址
自定义唤醒词 在 http://ai.baidu.com/tech/speech/wake
最后导出并下载.bin文件,将文件放到我们的项目下的assets目录下
如何创建assets目录?
请查看我的另一篇博文中的设置签名
https://blog.csdn.net/weixin_43271060/article/details/90318254
在我们新建的Module中的build.gradle中设置
task copyPlugin(type: Copy) { dependsOn assemble from('build/outputs/aar') into('../../Assets/Plugins/Android') include(project.name + '-release.aar') }
然后在右上角的Gradle中的wxplugins->Task->other中选择copyPlugin即可导出指定的并且已经存在的目录中
https://blog.csdn.net/weixin_43271060/article/details/108383451