以下代码主要参考博客:
Android 科大讯飞语音识别Android蓝牙串口开发部分请参照博客:
Android蓝牙串口开发讯飞语音官方开发文档:
语音听写 Android SDK 文档
文章目录
- 前言
- 一、SDK的下载和导入
* - 1.SDK的下载
- 2.新建工程
- 3.配置项目
– - 二、工具类
* - 1.Json解析类
- 2.语音识别相关方法
– - 三、调用代码编写
* - 1.点击事件的监听
- 2.识别结果的显示
- 3.语音命令识别和发送
- 总结
前言
语音识别目前使用的比较频繁,项目需要使用语音识别用户指令,然后通过蓝牙通信传递指定,命令下位机做出反应。手机端主要负责命令的发送,选用讯飞语音SDK,学习官方文档和参考博客进行开发。写这篇博客记录一下。
一、SDK的下载和导入
这一部分可以可以参照讯飞语音官方文档来进行
官方文档:语音听写 Android SDK 文档
1.SDK的下载
首先,登录iFLYTEK开放平台。没有要注册的帐户。
[En]
First of all, log in on the iFLYTEK open platform. There is no account to register.
在控制台中,按照流程创建新的应用程序。
[En]
In the console, follow the process to create a new application.
在下方的SDK下载中,下载相应的SDK。
解压缩完成后,首先设置项目。
[En]
After the decompression is completed, set up the project first.
; 2.新建工程
打开Android Studio 开发平台,新建工程画好前端设计界面,建立工程这一部分就不在赘述。
3.配置项目
a.导包
将解压后的libs文件夹中的文件放入项目的libs文件夹中。
对Msc包右键,选择Add As Library导入,此时Msc包可展开。
然后再添加assets,将assets文件夹添加到工程main文件夹下面。
; b.权限
导包完成后,我们需要给App一些必要权限,来使用手机的硬件功能。
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_SETTINGS"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.CAMERA" />
c.修改buid.gradle
打开buid.gradle后,在文件中做以下修改。
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation files('libs/Msc.jar')
}
然后点击Sync Now。
二、工具类
1.Json解析类
识别语音时,需要用到Json格式,所以需要有一个解析Json格式的类。
在工程中,新建一个JsonParser 的类。
package com.example.speechrecognitionforbluetooth;
import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONTokener;
public class JsonParser {
public static String parseIatResult(String json) {
StringBuffer ret = new StringBuffer();
try {
JSONTokener tokener = new JSONTokener(json);
JSONObject joResult = new JSONObject(tokener);
JSONArray words = joResult.getJSONArray("ws");
for (int i = 0; i < words.length(); i++) {
JSONArray items = words.getJSONObject(i).getJSONArray("cw");
JSONObject obj = items.getJSONObject(0);
ret.append(obj.getString("w"));
}
} catch (Exception e) {
e.printStackTrace();
}
return ret.toString();
}
public static String parseGrammarResult(String json) {
StringBuffer ret = new StringBuffer();
try {
JSONTokener tokener = new JSONTokener(json);
JSONObject joResult = new JSONObject(tokener);
JSONArray words = joResult.getJSONArray("ws");
for (int i = 0; i < words.length(); i++) {
JSONArray items = words.getJSONObject(i).getJSONArray("cw");
for(int j = 0; j < items.length(); j++)
{
JSONObject obj = items.getJSONObject(j);
if(obj.getString("w").contains("nomatch"))
{
ret.append("没有匹配结果.");
return ret.toString();
}
ret.append("【结果】" + obj.getString("w"));
ret.append("【置信度】" + obj.getInt("sc"));
ret.append("\n");
}
}
} catch (Exception e) {
e.printStackTrace();
ret.append("没有匹配结果.");
}
return ret.toString();
}
public static String parseLocalGrammarResult(String json) {
StringBuffer ret = new StringBuffer();
try {
JSONTokener tokener = new JSONTokener(json);
JSONObject joResult = new JSONObject(tokener);
JSONArray words = joResult.getJSONArray("ws");
for (int i = 0; i < words.length(); i++) {
JSONArray items = words.getJSONObject(i).getJSONArray("cw");
for(int j = 0; j < items.length(); j++)
{
JSONObject obj = items.getJSONObject(j);
if(obj.getString("w").contains("nomatch"))
{
ret.append("没有匹配结果.");
return ret.toString();
}
ret.append("【结果】" + obj.getString("w"));
ret.append("\n");
}
}
ret.append("【置信度】" + joResult.optInt("sc"));
} catch (Exception e) {
e.printStackTrace();
ret.append("没有匹配结果.");
}
return ret.toString();
}
public static String parseTransResult(String json, String key) {
StringBuffer ret = new StringBuffer();
try {
JSONTokener tokener = new JSONTokener(json);
JSONObject joResult = new JSONObject(tokener);
String errorCode = joResult.optString("ret");
if(!errorCode.equals("0")) {
return joResult.optString("errmsg");
}
JSONObject transResult = joResult.optJSONObject("trans_result");
ret.append(transResult.optString(key));
} catch (Exception e) {
e.printStackTrace();
}
return ret.toString();
}
}
用于进行语音识别的方法调用。
[En]
A method call used to give speech recognition.
2.语音识别相关方法
现在需要实现语音识别的核心代码了,具体代码请参考官方文档Demo或访问参考博客学习,这里做一个展示。
a.变量声明
首先,比较要导入的包。
[En]
First, compare the package you want to import.
import com.iflytek.cloud.ErrorCode;
import com.iflytek.cloud.InitListener;
import com.iflytek.cloud.RecognizerResult;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.SpeechRecognizer;
import com.iflytek.cloud.ui.RecognizerDialog;
import com.iflytek.cloud.ui.RecognizerDialogListener;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import static android.widget.Toast.LENGTH_SHORT;
为语音识别部分声明必要的变量。
[En]
Declare the necessary variables for the speech recognition part.
private SpeechRecognizer mIat;
private RecognizerDialog mIatDialog;
private HashMap<String, String> mIatResults = new LinkedHashMap<String, String>();
private SharedPreferences mSharedPreferences;
private String mEngineType = SpeechConstant.TYPE_CLOUD;
private String language = "zh_cn";
private TextView tvResult;
private Button mBTN_SPEECH;
private String resultType = "json";
b.权限请求
在调用过程中,您需要动态获取权限。
[En]
During the call, you need to obtain permissions dynamically.
private void initPermission() {
String permissions[] = {Manifest.permission.RECORD_AUDIO,
Manifest.permission.ACCESS_NETWORK_STATE,
Manifest.permission.INTERNET,
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) {
}
c.语音监听
private InitListener mInitListener = new InitListener() {
@Override
public void onInit(int code) {
Log.d(TAG, "SpeechRecognizer init() code = " + code);
if (code != ErrorCode.SUCCESS) {
showMsg("初始化失败,错误码:" + code + ",请点击网址https://www.xfyun.cn/document/error-code查询解决方案");
}
}
};
private RecognizerDialogListener mRecognizerDialogListener = new RecognizerDialogListener() {
public void onResult(RecognizerResult results, boolean isLast) {
printResult(results);
}
public void onError(SpeechError error) {
showMsg(error.getPlainDescription(true));
}
};
private void showMsg(String msg) {
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (null != mIat) {
mIat.cancel();
mIat.destroy();
}
}
d.数据解析
分析得到的数据,利用Text将结果显示出来,然后分析结果,利用蓝牙将指令发送出去。
private void printResult(RecognizerResult results) {
String text = JsonParser.parseIatResult(results.getResultString());
String sn = null;
try {
JSONObject resultJson = new JSONObject(results.getResultString());
sn = resultJson.optString("sn");
} catch (JSONException e) {
e.printStackTrace();
}
mIatResults.put(sn, text);
StringBuffer resultBuffer = new StringBuffer();
for (String key : mIatResults.keySet()) {
resultBuffer.append(mIatResults.get(key));
}
mET_DATE.setText(resultBuffer.toString());
sendCMDByBluetooth(resultBuffer.toString());
}
c.参数配置
public void setParam() {
mIat.setParameter(SpeechConstant.PARAMS, null);
mIat.setParameter(SpeechConstant.ENGINE_TYPE, mEngineType);
mIat.setParameter(SpeechConstant.RESULT_TYPE, resultType);
if (language.equals("zh_cn")) {
String lag = mSharedPreferences.getString("iat_language_preference",
"mandarin");
Log.e(TAG, "language:" + language);
mIat.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
mIat.setParameter(SpeechConstant.ACCENT, lag);
} else {
mIat.setParameter(SpeechConstant.LANGUAGE, language);
}
Log.e(TAG, "last language:" + mIat.getParameter(SpeechConstant.LANGUAGE));
mIat.setParameter(SpeechConstant.VAD_BOS, mSharedPreferences.getString("iat_vadbos_preference", "4000"));
mIat.setParameter(SpeechConstant.VAD_EOS, mSharedPreferences.getString("iat_vadeos_preference", "1000"));
mIat.setParameter(SpeechConstant.ASR_PTT, mSharedPreferences.getString("iat_punc_preference", "1"));
mIat.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");
mIat.setParameter(SpeechConstant.ASR_AUDIO_PATH, Environment.getExternalStorageDirectory() + "/msc/iat.wav");
}
三、调用代码编写
准备工作基本完成后,我们现在需要在主程序中调用该方法以逻辑地实现函数。
[En]
After the preparatory work has been basically completed, we now need to call the method to implement the function logically in the main program.
1.点击事件的监听
首先,实现了对屏幕点击事件的监控。
[En]
First of all, the screen to achieve a click event monitoring.
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private static final String TAG ="MainActivity" ;
@Override
public void onClick(View v) {
if( null == mIat ){
showMsg( "创建对象失败,请确认 libmsc.so 放置正确,且有调用 createUtility 进行初始化" );
return;
}
mIatResults.clear();
setParam();
mIatDialog.setListener(mRecognizerDialogListener);
mIatDialog.show();
}
}
2.识别结果的显示
结果的显示包含在用于数据分析的部分代码中
[En]
The display of the results is contained in part of the code for data analysis
mET_DATE.setText(resultBuffer.toString());
sendCMDByBluetooth(resultBuffer.toString());
3.语音命令识别和发送
在检测到语音输入后,生成识别结果,并显示后,根据您需要的判断逻辑对识别结果进行分析,并发出指令。
[En]
After the speech input is detected, a recognition result is generated, and after it is displayed, the recognition result is analyzed according to the judgment logic you need, and an instruction is issued.
public void sendCMDByBluetooth(String Speech){
String CMD = Speech.substring(0,Speech.indexOf("。"));
if (CONNECT_STATUS) {
switch (CMD){
case "打开灯光":{
write("A");
Toast.makeText(MainActivity.this, "指令:打开灯光 CMD:A", LENGTH_SHORT).show();
break;
}
case "关闭灯光":{
write("B");
Toast.makeText(MainActivity.this, "指令:关闭灯光 CMD:B", LENGTH_SHORT).show();
break;
}
case "打开风扇":{
write("C");
Toast.makeText(MainActivity.this, "指令:打开风扇 CMD:C", LENGTH_SHORT).show();
break;
}
case "关闭风扇":{
write("D");
Toast.makeText(MainActivity.this, "指令:关闭风扇 CMD:D", LENGTH_SHORT).show();
break;
}
}
} else {
Toast.makeText(getApplicationContext(), "请先连接蓝牙", Toast.LENGTH_SHORT).show();
}
}
总结
对我来说,该项目主要的难点在于对SDK的使用,以及类的调用。更灵活的使用还需要加深理解。
关于Android经典蓝牙串口开发在我的另一篇博客有记录。
Android蓝牙串口开发Original: https://blog.csdn.net/u011604460/article/details/124294562
Author: CallMeMinxJ
Title: Android 讯飞语音识别功能开发
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/527221/
转载文章受原作者版权保护。转载请注明原作者出处!