Unity3D接入百度语音识别实时识别带唤醒SDK(安卓版)

tech2023-02-01  108

一、首先下载官方Demo

https://ai.baidu.com/sdk#tts

二、版本介绍

本教程使用AndroidStudio3.6.3版本

由于是第三方插件,并且项目中已经有了一个第三方的插件,众所周知,Unity与安卓交互时,安卓端只能有一个Activity继承自UnityPlayerActivity,所以为了不与其他人的sdk冲突,我们便使用不继承UnityPlayerActivity的Java类

三、注册百度云账号

并且创建安卓版语音技术应用

四、导入官方demo中的sdk以及库文件

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; }

 

六、编写AndroidManifest.cml文件

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.xxx.xxx"> <!-- 填写自己的包名 --> <!-- 通用权限 --> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- 语音识别权限 --> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- 语音合成权限 --> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <uses-permission android:name="android.permission.WRITE_SETTINGS" tools:ignore="ProtectedPermissions" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <application android:allowBackup="true"> <activity android:name=".Wakeup.WakeUpResult"></activity> <activity android:name=".Wakeup.WakeupHandler" /> <activity android:name=".CientBaiDuVoiceMainActivity" android:launchMode="singleTask" /> <!-- 请填写真实的APP_ID API_KEY SECRET_KEY --> <meta-data android:name="com.baidu.speech.APP_ID" android:value="xxxxx" /> <meta-data android:name="com.baidu.speech.API_KEY" android:value="xxxxx" /> <meta-data android:name="com.baidu.speech.SECRET_KEY" android:value="xxxxx" /> <service android:name="com.baidu.speech.VoiceRecognitionService" android:exported="false" /> </application> </manifest>

因为语音唤醒是离线的,需要从百度语音技术官网中导出.bin文件

网址

自定义唤醒词 在 http://ai.baidu.com/tech/speech/wake 

最后导出并下载.bin文件,将文件放到我们的项目下的assets目录下

如何创建assets目录?

七、设置签名

请查看我的另一篇博文中的设置签名

https://blog.csdn.net/weixin_43271060/article/details/90318254

八、导出arr包

在我们新建的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即可导出指定的并且已经存在的目录中

九、Unity中调用

void Start() { AndroidJavaClass _androidJC = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); if (_androidJC == null) { Debug.Log("JNI initialization failure."); return; } m_AndroidPluginObj = _androidJC.GetStatic<AndroidJavaObject>("currentActivity"); } public void InitAsr() { AndroidJavaClass jc = new AndroidJavaClass("com.xxx.xxx.CientBaiDuVoiceMainActivity");//包名加类名 AndroidJavaObject m_Android = jc.CallStatic<AndroidJavaObject>("getInstance"); if (m_Android != null) { m_Android.Call("InitRecogn", m_AndroidPluginObj); } else Debug.Log("AndroidPlugin is Null"); } public void StartRecogn() { AndroidJavaClass jc = new AndroidJavaClass("com.xxx.xxx.CientBaiDuVoiceMainActivity"); AndroidJavaObject m_Android = jc.CallStatic<AndroidJavaObject>("getInstance"); if (m_Android != null) { m_Android.Call("StartRecogn"); } else Debug.Log("AndroidPlugin is Null"); } public void StopRecogn() { AndroidJavaClass jc = new AndroidJavaClass("com.xxx.xxx.CientBaiDuVoiceMainActivity"); AndroidJavaObject m_Android = jc.CallStatic<AndroidJavaObject>("getInstance"); if (m_Android != null) { m_Android.Call("StopRecogn"); } else Debug.Log("AndroidPlugin is Null"); } public void InitWakeUp() { AndroidJavaClass jc = new AndroidJavaClass("com.xxx.xxx.CientBaiDuVoiceMainActivity"); AndroidJavaObject m_Android = jc.CallStatic<AndroidJavaObject>("getInstance"); if (m_Android != null) { m_Android.Call("InitWakeUp", m_AndroidPluginObj); } else Debug.Log("AndroidPlugin is Null"); } public void StartWakeUp() { AndroidJavaClass jc = new AndroidJavaClass("com.xxx.xxx.CientBaiDuVoiceMainActivity"); AndroidJavaObject m_Android = jc.CallStatic<AndroidJavaObject>("getInstance"); if (m_Android != null) { m_Android.Call("StartWakeUp"); } else Debug.Log("AndroidPlugin is Null"); } public void StopWakeUp() { AndroidJavaClass jc = new AndroidJavaClass("com.xxx.xxx.CientBaiDuVoiceMainActivity"); AndroidJavaObject m_Android = jc.CallStatic<AndroidJavaObject>("getInstance"); if (m_Android != null) { m_Android.Call("StopWakeUp"); } else Debug.Log("AndroidPlugin is Null"); } public Text mRecognRes; /// <summary> /// 百度语音唤醒结果反馈 /// </summary> /// <param name="res"></param> void WakeupResult(string res) { string[] ress = res.Split('&'); JsonData jsonData = JsonMapper.ToObject(ress[1]); if (ress[0] == "wp.data") { if (jsonData["errorCode"].ToString() == "0") { mRecognRes.text = "唤醒成功:" + jsonData["word"].ToString(); } } } /// <summary> /// 百度语音识别结果反馈 /// </summary> /// <param name="res"></param> void RecognResult(string res) { string[] ress = res.Split('&'); JsonData jsonData = JsonMapper.ToObject(ress[1]); string resStr = ""; if (jsonData["result_type"].ToString() == "partial_result") { resStr = "临时识别结果:"; } else { resStr = "最终识别结果:"; } resStr += jsonData["best_result"].ToString(); mRecognRes.text = resStr; }

十、发布arr包遇到的问题,请查看我的另一边博客

https://blog.csdn.net/weixin_43271060/article/details/108383451

最新回复(0)