【开发环境】android studio 3.4.2
先到百度语音官网上查看集成指南
百度AI开放平台-全球领先的人工智能服务平台-百度AI开放平台
然后再去下载语音识别 https://ai.baidu.com/sdk#asr
离在线融合SDK(audiobd_speech_sdk_asr_v3.0.12.3_20190515_c9eed5d.zip)
直接参考SDK中的ActivityMiniRecog类
【代码部分】
1、app\build.gradle
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
buildToolsVersion "29.0.1"
defaultConfig {
applicationId "com.unionman.speechdemo"
minSdkVersion 16
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation files('libs/bdasr_V3_20190515_c9eed5d.jar')
api fileTree(exclude: '*.bak', dir: 'libs')
api 'com.google.code.gson:gson:2.8.5'
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:support-v4:28.0.0'
}
2、AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.unionman.speechdemo">
<!-- begin: baidu speech sdk 权限 -->
<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" />
<!-- end: baidu speech sdk 权限 -->
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
android:name="com.baidu.speech.APP_ID"
android:value="替换成你申请的AppID"/>
android:name="com.baidu.speech.API_KEY"
android:value="替换成你申请的API_KEY" />
android:name="com.baidu.speech.SECRET_KEY"
android:value="替换成你申请的SECRET_KEY" />
android:name="com.baidu.speech.VoiceRecognitionService"
android:exported="false" />
<activity android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|screenLayout"
android:screenOrientation="portrait">
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</manifest>
**3、将SDK中的app/libs/bdasr_V3_20190515_c9eed5d.jar 复制到您的项目的同名目录中。 **记得之后add as library
**4、将SDK中的app/src/main/jniLibs 下armeabi等5个目录,复制到您的项目的同名目录中。 **
5、activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.unionman.speechdemo.MainActivity">
android:id="@+id/btnStartRecord"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/start_record"/>
android:id="@+id/btnStopRecord"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/stop_record"/>
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2"
android:orientation="vertical">
android:layout_width="match_parent"
android:layout_height="3dp"
android:background="#000"/>
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:id="@+id/tvResult"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/parse_process" />
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical">
android:layout_width="match_parent"
android:layout_height="3dp"
android:background="#000"/>
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:id="@+id/tvParseResult"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/parse_result" />
6、MainActivity.java
package com.***.***;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.Manifest;
import android.content.pm.PackageManager;
//import android.support.v4.app.ActivityCompat;
//import android.support.v4.content.ContextCompat;
//import android.support.v7.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.core.app.ActivityCompat;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.baidu.speech.EventListener;
import com.baidu.speech.EventManager;
import com.baidu.speech.EventManagerFactory;
import com.baidu.speech.asr.SpeechConstant;
import com.google.gson.Gson;
import com.unionman.speechdemo.asrfinishjson.AsrFinishJsonData;
import com.unionman.speechdemo.asrpartialjson.AsrPartialJsonData;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;
public class MainActivityextends AppCompatActivityimplements EventListener {
private static final StringTAG ="MainActivity";
private ButtonbtnStartRecord;
private ButtonbtnStopRecord;
private TextViewtvResult;
private TextViewtvParseResult;
private EventManagerasr;
private boolean logTime =true;
private Stringfinal_result;
@Override
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方法
btnStartRecord.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
start();
}
});
btnStopRecord.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
stop();
}
});
}
private void initView() {
tvResult = (TextView) findViewById(R.id.tvResult);
tvParseResult = (TextView) findViewById(R.id.tvParseResult);
btnStartRecord = (Button) findViewById(R.id.btnStartRecord);
btnStopRecord = (Button) findViewById(R.id.btnStopRecord);
btnStopRecord.setVisibility(View.GONE);
}
/**
* 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 toApplyList =new ArrayList();
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以上动态授权的回调,用户自行实现。
}
/*
* EventListener 回调方法 * name:回调事件 * params: JSON数据,其格式如下:*
* */
@Override
public void onEvent(String name, String params, byte[] data, int offset, int length) {
String result ="";
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:"+params);
parseAsrPartialJsonData(params);
}else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_FINISH)) {
// 识别结束, 最终识别结果或可能的错误
result +="识别结束";
btnStartRecord.setEnabled(true);
asr.send(SpeechConstant.ASR_STOP, null, null, 0, 0);
if (params !=null && !params.isEmpty()) {
result +="params :" + params +"\n";
}
Log.d(TAG, "Result Params:"+params);
parseAsrFinishJsonData(params);
}
printResult(result);
}
private void printResult(String text) {
tvResult.append(text +"\n");
}
private void start() {
tvResult.setText("");
btnStartRecord.setEnabled(false);
Map params =new LinkedHashMap();
String event =null;
event = SpeechConstant.ASR_START;
params.put(SpeechConstant.PID, 1737); // 默认1536
params.put(SpeechConstant.DECODER, 0); // 纯在线(默认)
params.put(SpeechConstant.VAD, SpeechConstant.VAD_DNN); // 语音活动检测
params.put(SpeechConstant.VAD_ENDPOINT_TIMEOUT, 2000); // 不开启长语音。开启VAD尾点检测,即静音判断的毫秒数。建议设置800ms-3000ms
params.put(SpeechConstant.ACCEPT_AUDIO_DATA, false);// 是否需要语音音频数据回调
params.put(SpeechConstant.ACCEPT_AUDIO_VOLUME, false);// 是否需要语音音量数据回调
String json =null; //可以替换成自己的json
json =new JSONObject(params).toString(); // 这里可以替换成你需要测试的json
asr.send(event, json, null, 0, 0);
printResult("输入参数:" + json);
}
private void stop() {
asr.send(SpeechConstant.ASR_STOP, null, null, 0, 0);
}
@Override
protected void onDestroy() {
super.onDestroy();
asr.send(SpeechConstant.ASR_CANCEL, "{}", null, 0, 0);
}
private void parseAsrPartialJsonData(String data) {
Log.d(TAG, "parseAsrPartialJsonData data:"+data);
Gson gson =new Gson();
AsrPartialJsonData jsonData = gson.fromJson(data, AsrPartialJsonData.class);
String resultType = jsonData.getResult_type();
Log.d(TAG, "resultType:"+resultType);
if(resultType !=null && resultType.equals("final_result")){
final_result = jsonData.getBest_result();
// tvParseResult.setText("解析结果:" + final_result);
}
}
private void parseAsrFinishJsonData(String data) {
Log.d(TAG, "parseAsrFinishJsonData data:"+data);
Gson gson =new Gson();
AsrFinishJsonData jsonData = gson.fromJson(data, AsrFinishJsonData.class);
String desc = jsonData.getDesc();
if(desc !=null && desc.equals("Speech Recognize success.")){
tvParseResult.setText("解析结果:" +final_result);
}else{
String errorCode ="\n错误码:" + jsonData.getError();
String errorSubCode ="\n错误子码:"+ jsonData.getSub_error();
String errorResult = errorCode + errorSubCode;
tvParseResult.setText("解析错误,原因是:" + desc +"\n" + errorResult);
}
}
}
7、asrfinishjson/AsrFinishJsonData.java
package com.unionman.speechdemo.asrfinishjson;
public class AsrFinishJsonData {
private Stringerror;
private Stringsub_error;
private Stringdesc;
private OriginResultorigin_result;
public StringgetError() {
return error;
}
public StringgetSub_error() {
return sub_error;
}
public StringgetDesc() {
return desc;
}
public OriginResultgetOrigin_result() {
return origin_result;
}
}
8、asrfinishjson\OriginResult.java
package com.unionman.speechdemo.asrfinishjson;
public class OriginResult {
private Stringerror;
private Stringsub_error;
private Stringsn;
private Stringdesc;
public StringgetSn() {
return sn;
}
public StringgetDesc() {
return desc;
}
public StringgetError() {
return error;
}
public StringgetSub_error() {
return sub_error;
}
}
9、asrpartialjson\AsrPartialJsonData.java
package com.unionman.speechdemo.asrpartialjson;
import java.util.ArrayList;
public class AsrPartialJsonData {
private ArrayListresults_recognition;
private OriginResultorigin_result;
private Stringerror;
private Stringbest_result;
private Stringresult_type;
public ArrayListgetResults_recognition() {
return results_recognition;
}
public OriginResultgetOrigin_result() {
return origin_result;
}
public StringgetBest_result() {
return best_result;
}
public StringgetError() {
return error;
}
public StringgetResult_type() {
return result_type;
}
}
10、asrpartialjson\OriginResult.java
package com.unionman.speechdemo.asrpartialjson;
public class OriginResult {
private Stringcorpus_no;
private Stringerr_no;
private Stringsn;
private Resultresult;
public ResultgetResult() {
return result;
}
public StringgetCorpus_no() {
return corpus_no;
}
public StringgetErr_no() {
return err_no;
}
public StringgetSn() {
return sn;
}
}
11、asrpartialjson\Result.java
package com.unionman.speechdemo.asrpartialjson;
import java.util.ArrayList;
import java.util.List;
public class Result {
private ArrayListuncertain_word;
private ArrayListword;
public ArrayListgetUncertain_word() {
return uncertain_word;
}
public ArrayListgetWord() {
return word;
}
}
工程文件如下:
最终demo如下图: