天天看点

Android--语音识别接口使用及调用流程

现在国内语音就讯飞和百度,百度免费的,果断采用。

一、首先去官网注册,申请KEY(http://ai.baidu.com/tech/speech/asr)。

二、下载SDK(DEMO里有SDK和jniLibs),开始集成

库文件路径:

jar :core/libs 目录下

so:core/src/main/jniLibs 目录

AndroidManifest.xml 文件

设置权限

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

设置APP_ID, APP_KEY, APP_SECRET

    <meta-data android:name="com.baidu.speech.APP_ID"

        android:value="9788136" />

    <meta-data

        android:name="com.baidu.speech.API_KEY"

        android:value="0GjQNO5H4pGPf9HyA3AmZEbz" />

    <meta-data

        android:name="com.baidu.speech.SECRET_KEY"

        android:value="db981ef3ec647ba8a09b599ad7447a24" />           

设置识别Service

<service android:name="com.baidu.speech.VoiceRecognitionService" android:exported="false" />           

android 6.0 以上版本权限申请

以下代码可以在demo中查找

/**

 * 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以上动态授权的回调,用户自行实现。           

bdasr_V3_xxxxxxxx_xxxx.jar 库

将app/libs/bdasr_V3_xxxxx_xxxxx.jar 复制到您的项目的同名目录中。

复制NDK 架构目录

  1. 将 app/src/main/jniLibs 下armeabi等5个目录,复制到您的项目的同名目录中。
  2. 如与第三方库集成,至少要保留armeabi目录。如第三方库有7个架构目录,比语音识别SDK多出2个目录 mips和mips64,请将mips和mips64目录删除,剩下5个同名目录合并。
  3. 如第三方库仅有armeabi这一个目录,请将语音识别SDK的额外4个目录如armeabi-v7a删除,合并armeabi目录下的so。 即目录取交集,so文件不可随意更改所属目录。
  4. 打包成apk文件,按照zip格式解压出libs目录可以验证。
  5. 运行时 getApplicationInfo().nativeLibraryDir 目录下查看是否有完整so文件。 特别是系统app需要手动push so文件到这个目录下。

build.gradle 文件及包名确认

  1. 根目录下build.gradle确认下gradle的版本。
  2. app/build.gradle 确认下 applicationId 包名是否与官网申请应用时相一致(离线功能需要)。 demo的包名是"com.baidu.speech.recognizerdemo"。
  3. 确认 compileSdkVersion buildToolsVersion 及 targetSdkVersion

proguard文件

-keep class com.baidu.speech.**{*;}

接口使用及调用流程

http://ai.baidu.com/docs#/ASR-Android-SDK/3844a54f

DEMO

package com.baidu.speech.recognizerdemo;

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

import org.json.JSONObject;

import android.Manifest;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.speech.RecognitionListener;
import android.speech.SpeechRecognizer;
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.VoiceRecognitionService;
import com.baidu.speech.asr.SpeechConstant;

public class MainActivity extends Activity implements EventListener {
	/*private SpeechRecognizer speechRecognizer;
	private Button btn;
	private TextView iat_text;

	public static final int STATUS_None = 0;
	public static final int STATUS_WaitingReady = 2;
	public static final int STATUS_Ready = 3;
	public static final int STATUS_Speaking = 4;
	public static final int STATUS_Recognition = 5;
	private static final int EVENT_ERROR = 11;

	private int status = STATUS_None;
*/
    protected TextView txtLog;
    protected TextView txtResult;
    protected Button btn;
    protected Button stopBtn;

    private EventManager asr;

    private boolean logTime = true;

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

	protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
		initView();
//        initPermission();
        asr = EventManagerFactory.create(this, "asr");
        asr.registerListener(this); //  EventListener 中 onEvent方法
        btn.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                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 onDestroy() {
	        super.onDestroy();
	        asr.send(SpeechConstant.ASR_CANCEL, "{}", null, 0, 0);
	        if (enableOffline) {
	            unloadOfflineEngine(); //测试离线命令词请开启, 测试 ASR_OFFLINE_ENGINE_GRAMMER_FILE_PATH 参数时开启
	        }
	    }

    /**
     * 测试参数填在这里
     */
    private void start() {
        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);
        }
        params.put(SpeechConstant.VAD_ENDPOINT_TIMEOUT,2000);
        params.put(SpeechConstant.ACCEPT_AUDIO_VOLUME, false);
        params.put(SpeechConstant.OUT_FILE, "/storage/emulated/0/baiduASR/outfile.pcm");
        params.put(SpeechConstant.ACCEPT_AUDIO_DATA, true);
        params.put(SpeechConstant.DISABLE_PUNCTUATION,false);
        //  params.put(SpeechConstant.NLU, "enable");
        // params.put(SpeechConstant.VAD_ENDPOINT_TIMEOUT, 800);
        // params.put(SpeechConstant.VAD, SpeechConstant.VAD_DNN);
        //  params.put(SpeechConstant.PROP ,20000);
        String json = null; //可以替换成自己的json
        json = new JSONObject(params).toString(); // 这里可以替换成你需要测试的json
        printLog("输入参数:" + json);
        asr.send(event, json, null, 0, 0);
    }

    private void stop() {
        asr.send(SpeechConstant.ASR_STOP, null, null, 0, 0); //
    }

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

    private void unloadOfflineEngine() {
        asr.send(SpeechConstant.ASR_KWS_UNLOAD_ENGINE, null, null, 0, 0); //
    }

    /*
     * EventListener  回调方法
     * name:回调事件
     * params: JSON数据,其格式如下:
     *
     * */
    @Override
    public void onEvent(String name, String params, byte[] data, int offset, int length) {
        String result = "name" + name;

        if (length > 0 && data.length > 0) {
            result += ", 语义解析结果:" + new String(data, offset, length);
        }

        if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_READY)) {
            // 引擎准备就绪,可以开始说话
            result += "引擎准备就绪,可以开始说话";

        } else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_BEGIN)) {
            // 检测到用户的已经开始说话
            result += "检测到用户的已经开始说话";

        } else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_END)) {
            // 检测到用户的已经停止说话
            result += "检测到用户的已经停止说话";
            if (params != null && !params.isEmpty()) {
                result += "params :" + params + "\n";
            }
        } else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_PARTIAL)) {
            // 临时识别结果, 长语音模式需要从此消息中取出结果
            result += "识别临时识别结果";
            if (params != null && !params.isEmpty()) {
                result += "params :" + params + "\n";
            }
            Log.d(TAG, "Temp Params:"+result);

        } else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_FINISH)) {
            // 识别结束, 最终识别结果或可能的错误
            result += "识别结束";
            asr.send(SpeechConstant.ASR_STOP, null, null, 0, 0);
            if (params != null && !params.isEmpty()) {
                result += "params :" + params + "\n";
            }
            Log.d(TAG, "Result Params:"+result);

        }

    }

    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以上动态授权的回调,用户自行实现。
    }*/
}           

附:讯飞语音识别

同百度语音一样,都是先官网申请key,然后将生成下载的Android_iat1136_*****.zip报解压,放入对应位置

Android--语音识别接口使用及调用流程
Android--语音识别接口使用及调用流程
Android--语音识别接口使用及调用流程

在onCreate方法中初始化

//配置语音
        SpeechUtility.createUtility(this, SpeechConstant.APPID + "=123456");           

其中123456换成自己申请的key

封装的方法

public void startVoice(){
        RecognizerDialog recognizerDialog = new RecognizerDialog(searchActivity.this, this);
        recognizerDialog.setParameter(SpeechConstant.LANGUAGE, "zh_cn");//语种,这里可以有zh_cn和en_us
        recognizerDialog.setParameter(SpeechConstant.ACCENT, "mandarin");//设置口音,这里设置的是汉语普通话
        recognizerDialog.setParameter(SpeechConstant.TEXT_ENCODING, "utf-8");//设置编码类型

        recognizerDialog.setListener(new RecognizerDialogListener() {
            @Override
            public void onResult(RecognizerResult recognizerResult, boolean b) {
                record = "";
                if (!b) {
                    Log.i("test_xunfei", recognizerResult.getResultString());
                    Gson gson = new Gson();
                    speech s = gson.fromJson(recognizerResult.getResultString(),speech.class);
                    List<speech.WsBean> ws = s.getWs();
                    for (int i = 0;i < ws.size();i++){
                        List<speech.WsBean.CwBean> cw = ws.get(i).getCw();
                        for (int j = 0;j < cw.size();j++){
                            record = record + cw.get(j).getW();
                        }
                    }
                    Log.i("xunfei",record);
                    Message msg = new Message();
                    msg.what = 1;
                    msg.obj = record;
                    mHandler.sendMessage(msg);
                }
            }

            @Override
            public void onError(SpeechError speechError) {//返回错误
                Log.e("xunfei", speechError.getErrorCode() + "");
            }

        });
        recognizerDialog.show();
    }

    @Override
    public void onInit(int code) {
        if (code != ErrorCode.SUCCESS) {
            Toast.makeText(searchActivity.this,"初始化失败,错误码:" + code,Toast.LENGTH_LONG).show();
        }
    }           

bean

package bean;

import java.util.List;

/**
 * Created by Administrator on 2019/5/15
 * <p>
 * desc:
 */
public class speech {

    /**
     * sn : 1
     * ls : false
     * bg : 0
     * ed : 0
     * ws : [{"bg":0,"cw":[{"sc":0,"w":"321"}]}]
     */

    private int sn;
    private boolean ls;
    private int bg;
    private int ed;
    private List<WsBean> ws;

    public int getSn() {
        return sn;
    }

    public void setSn(int sn) {
        this.sn = sn;
    }

    public boolean isLs() {
        return ls;
    }

    public void setLs(boolean ls) {
        this.ls = ls;
    }

    public int getBg() {
        return bg;
    }

    public void setBg(int bg) {
        this.bg = bg;
    }

    public int getEd() {
        return ed;
    }

    public void setEd(int ed) {
        this.ed = ed;
    }

    public List<WsBean> getWs() {
        return ws;
    }

    public void setWs(List<WsBean> ws) {
        this.ws = ws;
    }

    public static class WsBean {
        /**
         * bg : 0
         * cw : [{"sc":0,"w":"321"}]
         */

        private int bg;
        private List<CwBean> cw;

        public int getBg() {
            return bg;
        }

        public void setBg(int bg) {
            this.bg = bg;
        }

        public List<CwBean> getCw() {
            return cw;
        }

        public void setCw(List<CwBean> cw) {
            this.cw = cw;
        }

        public static class CwBean {
            /**
             * sc : 0.0
             * w : 321
             */

            private double sc;
            private String w;

            public double getSc() {
                return sc;
            }

            public void setSc(double sc) {
                this.sc = sc;
            }

            public String getW() {
                return w;
            }

            public void setW(String w) {
                this.w = w;
            }
        }
    }
}
           

继续阅读