一、首先下载官方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

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐