安卓(Android)开发百度语音唤醒(识别)


目录

  • 安卓(Android)开发百度语音唤醒(识别)
  • 一:准备
  • 1:获取自定义唤醒词
  • 2:SDK下载
  • 3:将bdasr_V3_xxx_xxx.jar引入到项目libs文件中
  • 4:将armeabi,armeabi-v7a,arm64-v8a,x86,x86_64引入到项目jniLibs目录下。
  • 5:将语音唤醒词放入到项目assets目录下。
  • 二:开始
  • 1:设置权限(application标签外)
  • 2:设置APP_ID,API_KEY,SECRET_KEY(请登录百度语音控制台获取)
  • 3:逻辑代码


一:准备

本项目仅仅使用在线语音唤醒(识别)

1:获取自定义唤醒词

2:SDK下载

3:将bdasr_V3_xxx_xxx.jar引入到项目libs文件中

bdasr_V3_xxx_xxx.jar 位于 所下载SDK的 core/libs 目录下。

Intent android 唤醒new android语音唤醒_json

4:将armeabi,armeabi-v7a,arm64-v8a,x86,x86_64引入到项目jniLibs目录下。

armeabi,armeabi-v7a,arm64-v8a,x86,x86_64 5个架构目录位于所下载SDK的 core/src/main/jniLibs 目录下

Intent android 唤醒new android语音唤醒_Android语音唤醒_02

项目层级关系请看图片

5:将语音唤醒词放入到项目assets目录下。

Intent android 唤醒new android语音唤醒_离线_03

二:开始

1:设置权限(application标签外)

<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" />

2:设置APP_ID,API_KEY,SECRET_KEY(请登录百度语音控制台获取)

application标签内

<meta-data android:name="com.baidu.speech.APP_ID"
          android:value="17885408" />
    <meta-data
         android:name="com.baidu.speech.API_KEY"
         android:value="lbKgiTxxxxxxxxxxxxxxxxx" />
     <meta-data
         android:name="com.baidu.speech.SECRET_KEY"
         android:value="1V0L5Fxxxxxxxxxxxxxxxxxx" />
     <service android:name="com.baidu.speech.VoiceRecognitionService" android:exported="false" />

3:逻辑代码

package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
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.speech.asr.SpeechConstant;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

public class MainActivity extends AppCompatActivity implements EventListener {

    protected TextView txtLog;
    protected TextView txtResult;
    protected Button btn;
    protected Button stopBtn;
    private MediaPlayer mp3;

//    private static String DESC_TEXT = "精简版识别,带有SDK唤醒运行的最少代码,仅仅展示如何调用,\n" +
//            "也可以用来反馈测试SDK输入参数及输出回调。\n" +
//            "本示例需要自行根据文档填写参数,可以使用之前识别示例中的日志中的参数。\n" +
//            "需要完整版请参见之前的识别示例。\n" +
//            "需要测试离线命令词识别功能可以将本类中的enableOffline改成true,首次测试离线命令词请联网使用。之后请说出“打电话给李四”";

    private static String DESC_TEXT = "请点击开始,然后说出语音。\n\n"+
            "需要连接网络才能执行";

    private EventManager asr;

    private boolean lock = true; //为false时不再启动语音唤醒

    private boolean logTime = true;

    protected boolean enableOffline = false; // 测试离线命令词,需要改成true

    /**
     * 基于SDK集成2.2 发送开始事件
     * 点击开始按钮
     * 测试参数填在这里
     */
    private void start() {

        if(lock==false){
            return;
        }

        txtLog.setText("");
        Map<String, Object> params = new LinkedHashMap<String, Object>();
        String event = null;
        event = SpeechConstant.ASR_START; // 替换成测试的event

        if (enableOffline) {
            params.put(SpeechConstant.DECODER, 2);
        }
        // 基于SDK集成2.1 设置识别参数
        params.put(SpeechConstant.ACCEPT_AUDIO_VOLUME, false);



        // params.put(SpeechConstant.NLU, "enable");
        // params.put(SpeechConstant.VAD_ENDPOINT_TIMEOUT, 0); // 长语音
        // params.put(SpeechConstant.IN_FILE, "res:///com/baidu/android/voicedemo/16k_test.pcm");
        // params.put(SpeechConstant.VAD, SpeechConstant.VAD_DNN);
        // params.put(SpeechConstant.PID, 1537); // 中文输入法模型,有逗号

        /* 语音自训练平台特有参数 */
        // params.put(SpeechConstant.PID, 8002);
        // 语音自训练平台特殊pid,8002:搜索模型类似开放平台 1537  具体是8001还是8002,看自训练平台页面上的显示
        // params.put(SpeechConstant.LMID,1068); // 语音自训练平台已上线的模型ID,https://ai.baidu.com/smartasr/model
        // 注意模型ID必须在你的appId所在的百度账号下
        /* 语音自训练平台特有参数 */

        // 请先使用如‘在线识别’界面测试和生成识别参数。 params同ActivityRecog类中myRecognizer.start(params);
        // 复制此段可以自动检测错误
//        (new AutoCheck(getApplicationContext(), new Handler() {
//            public void handleMessage(Message msg) {
//                if (msg.what == 100) {
//                    AutoCheck autoCheck = (AutoCheck) msg.obj;
//                    synchronized (autoCheck) {
//                        String message = autoCheck.obtainErrorMessage(); // autoCheck.obtainAllMessage();
//                        txtLog.append(message + "\n");
//                        ; // 可以用下面一行替代,在logcat中查看代码
//                        // Log.w("AutoCheckMessage", message);
//                    }
//                }
//            }
//        },enableOffline)).checkAsr(params);

        // 3) 通知唤醒管理器, 启动唤醒功能

        HashMap params2 = new HashMap();
        params2.put("kws-file","assets:///WakeUp.bin");

        // 3) 通知唤醒管理器, 启动唤醒功能

//        asr.send(event, json, null, 0, 0);

        String json = null; // 可以替换成自己的json
        json = new JSONObject(params).toString(); // 这里可以替换成你需要测试的json
        asr.send(event,json, null, 0, 0);
        printLog("输入参数:" +json);
    }

    /**
     * 点击停止按钮
     *  基于SDK集成4.1 发送停止事件
     */
    private void stop() {
        printLog("停止识别:ASR_STOP");
        lock = false; //不再识别
        asr.send(SpeechConstant.ASR_STOP, null, null, 0, 0); //
    }

    /**
     * enableOffline设为true时,在onCreate中调用
     * 基于SDK离线命令词1.4 加载离线资源(离线时使用)
     */
    private void loadOfflineEngine() {
        Map<String, Object> params = new LinkedHashMap<String, Object>();
        params.put(SpeechConstant.DECODER, 2);
        params.put(SpeechConstant.ASR_OFFLINE_ENGINE_GRAMMER_FILE_PATH, "assets://baidu_speech_grammar.bsg");
        asr.send(SpeechConstant.ASR_KWS_LOAD_ENGINE, new JSONObject(params).toString(), null, 0, 0);
    }

    /**
     * enableOffline为true时,在onDestory中调用,与loadOfflineEngine对应
     * 基于SDK集成5.1 卸载离线资源步骤(离线时使用)
     */
    private void unloadOfflineEngine() {
        asr.send(SpeechConstant.ASR_KWS_UNLOAD_ENGINE, null, null, 0, 0); //
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initPermission();
        // 基于sdk集成1.1 初始化EventManager对象
        asr = EventManagerFactory.create(this, "asr");
        // 基于sdk集成1.3 注册自己的输出事件类
        asr.registerListener(this); //  EventListener 中 onEvent方法
        btn.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                lock=true;
                start();
            }
        });
        stopBtn.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                stop();
            }
        });
        if (enableOffline) {
            loadOfflineEngine(); // 测试离线命令词请开启, 测试 ASR_OFFLINE_ENGINE_GRAMMER_FILE_PATH 参数时开启
        }

    }

    @Override
    protected void onPause(){
        super.onPause();
        asr.send(SpeechConstant.ASR_CANCEL, "{}", null, 0, 0);
        Log.i("ActivityMiniRecog","On pause");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 基于SDK集成4.2 发送取消事件
        asr.send(SpeechConstant.ASR_CANCEL, "{}", null, 0, 0);
        if (enableOffline) {
            unloadOfflineEngine(); // 测试离线命令词请开启, 测试 ASR_OFFLINE_ENGINE_GRAMMER_FILE_PATH 参数时开启
        }

        // 基于SDK集成5.2 退出事件管理器
        // 必须与registerListener成对出现,否则可能造成内存泄露
        asr.unregisterListener(this);
    }

    // 基于sdk集成1.2 自定义输出事件类 EventListener 回调方法
    // 基于SDK集成3.1 开始回调事件
    @Override
    public void onEvent(String name, String params, byte[] data, int offset, int length) {
        String logTxt = "name: " + name;

        if (params != null && !params.isEmpty()) {
            logTxt += " ;params :" + params;
        }

        if(params!=null){
            try {

                JSONObject json = new JSONObject(params);
                String word = json.getString("best_result");
                logTxt += " ;test+++++++++++ :" + word;

                if(word.equals("小白你好")){
                    Toast.makeText(MainActivity.this,"到这了+++++",Toast.LENGTH_SHORT).show();
                    setTitle("你好,我在,我是小白");

                    mp3 = new MediaPlayer();
                    mp3 = MediaPlayer.create(MainActivity.this,R.raw.test);
                    mp3.start();
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }


        if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_PARTIAL)) {
            if (params != null && params.contains("\"nlu_result\"")) {
                if (length > 0 && data.length > 0) {
                    logTxt += ", 语义解析结果:" + new String(data, offset, length);
                }
            }
        } else if (data != null) {
            logTxt += " ;data length=" + data.length;
        }

        if(name.equals("asr.exit")){
            start();
        }

        printLog(logTxt);
    }

    private void printLog(String text) {
        if (logTime) {
            text += "  ;time=" + System.currentTimeMillis();
        }
        text += "\n";
        Log.i(getClass().getName(), text);
        txtLog.append(text + "\n");
    }

    private void initView() {
        txtResult = (TextView) findViewById(R.id.txtResult);
        txtLog = (TextView) findViewById(R.id.txtLog);
        btn = (Button) findViewById(R.id.btn);
        stopBtn = (Button) findViewById(R.id.btn_stop);
        txtLog.setText(DESC_TEXT + "\n");
    }

    /**
     * android 6.0 以上需要动态申请权限
     */
    private void initPermission() {
        String permissions[] = {Manifest.permission.RECORD_AUDIO,
                Manifest.permission.ACCESS_NETWORK_STATE,
                Manifest.permission.INTERNET,
                Manifest.permission.READ_PHONE_STATE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE
        };

        ArrayList<String> toApplyList = new ArrayList<String>();

        for (String perm : permissions) {
            if (PackageManager.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(this, perm)) {
                toApplyList.add(perm);
                // 进入到这里代表没有权限.

            }
        }
        String tmpList[] = new String[toApplyList.size()];
        if (!toApplyList.isEmpty()) {
            ActivityCompat.requestPermissions(this, toApplyList.toArray(tmpList), 123);
        }

    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        // 此处为android 6.0以上动态授权的回调,用户自行实现。
    }

    public void setTitle(String msg){
        AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
        builder.setIcon(R.drawable.test);
        builder.setTitle("提示");
        builder.setCancelable(false);
        builder.setMessage(msg);
        builder.setPositiveButton("确认", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {

            }
        });
        builder.create();
        builder.show();
    }

}

仅仅支持在线识别,后续将更新添加离线识别,语音合成。