在移动游戏开发中,语音控制为用户带来了全新的交互体验。通过语音指令,玩家可以更加直观地控制游戏角色,提升游戏的沉浸感。本文将详细介绍如何在 Android 平台上集成讯飞语音识别SDK,实现对推箱子游戏的语音控制。我们将涵盖 SDK 的基础知识、集成步骤、详细的代码解析,并在文章末尾附上核心代码,帮助开发者快速上手。
一、什么是讯飞语音识别SDK?
讯飞语音识别SDK是由科大讯飞提供的一套高效、稳定的语音识别解决方案。它支持多种语言和方言,具有实时性强、识别准确率高的特点。开发者可以通过集成该SDK,轻松实现语音输入、语音控制等功能,为应用增添智能交互能力。
1. 主要功能
- 实时语音识别:支持实时将语音转换为文本。
- 多语言支持:支持中文、英文等多种语言。
- 离线识别:在无网络环境下,仍可进行语音识别(需预先下载离线资源)。
- 自定义词库:通过自定义词库,提高特定领域的识别准确率。
2. 应用场景
- 智能助手:通过语音指令完成任务。
- 游戏控制:玩家通过语音控制游戏角色或进行操作。
- 语音输入:在应用中实现语音输入功能,提升用户体验。
二、项目准备与SDK集成
在开始集成讯飞语音识别SDK之前,需要进行以下准备工作:
1. 注册并获取应用ID
前往科大讯飞开放平台注册账号,并创建应用以获取 APPID
。APPID
是调用SDK时必需的认证信息。
2. 下载SDK
在科大讯飞开放平台下载最新版本的Android语音识别SDK,并按照官方文档进行集成。
3. 配置项目权限
为了正常使用语音识别功能,需要在 AndroidManifest.xml
中添加以下权限:
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
4. 集成SDK依赖
将下载的SDK库文件(通常为 .jar
或 .aar
文件)添加到项目的 libs
目录下,并在 build.gradle
中添加依赖:
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
// 其他依赖
}
三、实现语音控制的核心流程
要实现语音控制推箱子游戏,主要包括以下几个步骤:
- 初始化语音识别对象:创建
SpeechRecognizer
和RecognizerDialog
对象,并设置初始化监听器。 - 设置识别参数:配置语音识别的相关参数,如引擎类型、语言、结果格式等。
- 请求必要权限:动态申请语音识别所需的权限,如录音权限、网络权限等。
- 启动语音识别:通过用户交互(如按钮点击)启动语音识别对话框。
- 处理识别结果:解析识别结果,并根据识别到的指令控制游戏角色的移动。
- 错误处理与资源释放:处理识别过程中的错误,并在适当时机释放资源。
1. 初始化语音识别对象
在 onCreate
方法中,创建 SpeechRecognizer
和 RecognizerDialog
对象,并设置初始化监听器:
// 使用SpeechRecognizer对象,可根据回调消息自定义界面;
mIat = SpeechRecognizer.createRecognizer(MainActivity.this, mInitListener);
// 使用UI听写功能,请根据sdk文件目录下的notice.txt,放置布局文件和图片资源
mIatDialog = new RecognizerDialog(MainActivity.this, mInitListener);
2. 设置识别参数
通过 setParam()
方法,配置语音识别的相关参数:
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");
mIat.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
// 设置语言区域
mIat.setParameter(SpeechConstant.ACCENT, lag);
} else {
mIat.setParameter(SpeechConstant.LANGUAGE, language);
}
// 设置语音前端点:静音超时时间,即用户多长时间不说话则当做超时处理
mIat.setParameter(SpeechConstant.VAD_BOS, mSharedPreferences.getString("iat_vadbos_preference", "4000"));
// 设置语音后端点:后端点静音检测时间,即用户停止说话多长时间内即认为不再输入, 自动停止录音
mIat.setParameter(SpeechConstant.VAD_EOS, mSharedPreferences.getString("iat_vadeos_preference", "100"));
// 设置标点符号,设置为"0"返回结果无标点,设置为"1"返回结果有标点
mIat.setParameter(SpeechConstant.ASR_PTT, mSharedPreferences.getString("iat_punc_preference", "0"));
// 设置音频保存路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限
mIat.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");
mIat.setParameter(SpeechConstant.ASR_AUDIO_PATH, Environment.getExternalStorageDirectory() + "/msc/iat.wav");
}
3. 请求必要权限
由于语音识别需要录音和网络权限,需要在运行时动态申请这些权限:
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<>();
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);
}
}
4. 启动语音识别
通过用户点击按钮,启动语音识别对话框:
binding.btnStart.setOnClickListener(v -> {
if (null == mIat) {
showMsg("创建对象失败,请确认 libmsc.so 放置正确,且有调用 createUtility 进行初始化");
return;
}
mIatResults.clear(); // 清除数据
setParam(); // 设置参数
mIatDialog.setListener(mRecognizerDialogListener); // 设置监听
mIatDialog.show(); // 显示对话框
});
5. 处理识别结果
通过 RecognizerDialogListener
监听识别结果,并根据指令控制游戏角色:
private final RecognizerDialogListener mRecognizerDialogListener = new RecognizerDialogListener() {
public void onResult(RecognizerResult results, boolean isLast) {
printResult(results); // 结果数据解析
}
public void onError(SpeechError error) {
showMsg(error.getPlainDescription(true));
}
};
/**
* 数据解析
*
* @param results
*/
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));
}
String recognizedText = resultBuffer.toString();
binding.tvResult.setText(recognizedText); // 听写结果显示
// 处理语音指令
handleVoiceCommand(recognizedText);
}
/**
* 根据识别到的语音指令控制游戏
* @param command 识别到的文本
*/
private void handleVoiceCommand(String command) {
boolean recognized = false;
if (command.contains("上")) {
gameView.moveUp();
recognized = true;
} else if (command.contains("下")) {
gameView.moveDown();
recognized = true;
} else if (command.contains("左")) {
gameView.moveLeft();
recognized = true;
} else if (command.contains("右")) {
gameView.moveRight();
recognized = true;
}
if (recognized) {
gameView.invalidate(); // 刷新视图以显示移动
} else {
showMsg("未识别的指令: " + command);
}
}
6. 错误处理与资源释放
在 onDestroy
方法中,释放语音识别资源,避免内存泄漏:
@Override
protected void onDestroy() {
super.onDestroy();
if (null != mIat) {
// 退出时释放连接
mIat.cancel();
mIat.destroy();
}
}
四、核心代码分享
以下是实现语音控制推箱子游戏的核心代码,涵盖语音识别对象的初始化、参数设置、识别结果处理等部分。请参考并集成到您的项目中,以实现语音控制功能。
package com.llw.xfasrdemo;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;
import com.iflytek.cloud.ErrorCode;
import com.iflytek.cloud.InitListener;
import com.iflytek.cloud.RecognizerResult;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechRecognizer;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.ui.RecognizerDialog;
import com.iflytek.cloud.ui.RecognizerDialogListener;
import com.llw.xfasrdemo.databinding.ActivityMainBinding;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private ActivityMainBinding binding;
private SpeechRecognizer mIat; // 语音听写对象
private RecognizerDialog mIatDialog; // 语音听写UI
// 游戏视图引用
private GameView gameView;
// 用HashMap存储听写结果
private HashMap<String, String> mIatResults = new LinkedHashMap<>();
private SharedPreferences mSharedPreferences; // 缓存
private String mEngineType = SpeechConstant.TYPE_CLOUD; // 引擎类型
private String language = "zh_cn"; // 识别语言
private String resultType = "json"; // 结果内容数据格式
// 设定阈值
private static final float THRESHOLD = 5.0f;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
// 获取 GameView 引用
gameView = findViewById(R.id.game_view);
// 初始化语音识别对象
mIat = SpeechRecognizer.createRecognizer(MainActivity.this, mInitListener);
mIatDialog = new RecognizerDialog(MainActivity.this, mInitListener);
mSharedPreferences = getSharedPreferences("ASR", Activity.MODE_PRIVATE);
// 设置开始按钮点击事件
binding.btnStart.setOnClickListener(v -> {
if (null == mIat) {
showMsg("创建对象失败,请确认 libmsc.so 放置正确,且有调用 createUtility 进行初始化");
return;
}
mIatResults.clear(); // 清除数据
setParam(); // 设置参数
mIatDialog.setListener(mRecognizerDialogListener); // 设置监听
mIatDialog.show(); // 显示对话框
});
// 初始化权限
initPermission();
}
/**
* 初始化监听器。
*/
private final InitListener mInitListener = code -> {
Log.d(TAG, "SpeechRecognizer init() code = " + code);
if (code != ErrorCode.SUCCESS) {
showMsg("初始化失败,错误码:" + code + ",请点击网址https://www.xfyun.cn/document/error-code查询解决方案");
}
};
/**
* 听写UI监听器
*/
private final RecognizerDialogListener mRecognizerDialogListener = new RecognizerDialogListener() {
public void onResult(RecognizerResult results, boolean isLast) {
printResult(results); // 结果数据解析
}
public void onError(SpeechError error) {
showMsg(error.getPlainDescription(true));
}
};
/**
* 数据解析
*
* @param results
*/
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));
}
String recognizedText = resultBuffer.toString();
binding.tvResult.setText(recognizedText); // 听写结果显示
// 处理语音指令
handleVoiceCommand(recognizedText);
}
/**
* 参数设置
*/
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", "100"));
// 设置标点符号,设置为"0"返回结果无标点,设置为"1"返回结果有标点
mIat.setParameter(SpeechConstant.ASR_PTT, mSharedPreferences.getString("iat_punc_preference", "0"));
// 设置音频保存路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限
mIat.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");
mIat.setParameter(SpeechConstant.ASR_AUDIO_PATH, Environment.getExternalStorageDirectory() + "/msc/iat.wav");
}
/**
* 提示消息
*
* @param msg
*/
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();
}
}
/**
* android 6.0 以上需要动态申请权限
*/
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<>();
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);
}
}
/**
* 权限申请回调,可以作进一步处理
*
* @param requestCode
* @param permissions
* @param grantResults
*/
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
// 此处为android 6.0以上动态授权的回调,用户自行实现。
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
/**
* 根据识别到的语音指令控制游戏
*
* @param command 识别到的文本
*/
private void handleVoiceCommand(String command) {
boolean recognized = false;
if (command.contains("上")) {
gameView.moveUp();
recognized = true;
} else if (command.contains("下")) {
gameView.moveDown();
recognized = true;
} else if (command.contains("左")) {
gameView.moveLeft();
recognized = true;
} else if (command.contains("右")) {
gameView.moveRight();
recognized = true;
}
if (recognized) {
gameView.invalidate(); // 刷新视图以显示移动
} else {
showMsg("未识别的指令: " + command);
}
}
}
五、总结
通过集成讯飞语音识别SDK,开发者可以轻松为Android游戏添加语音控制功能,提升用户的互动体验。本文详细介绍了从SDK集成到实现语音控制的整个流程,并对关键代码进行了深入解析。希望能为广大开发者在语音识别应用领域提供有价值的参考。
在实际开发中,建议根据具体需求调整识别参数,优化用户体验。同时,关注讯飞开放平台的更新,获取最新的功能和优化建议。
如果你对本文内容有任何疑问或建议,欢迎在评论区留言讨论。希望这篇文章能帮助你在Android游戏开发中更好地应用语音识别技术,创造出更加出色的作品!
关注我
如果你觉得这篇文章对你有帮助,欢迎点赞、收藏和分享!也可以关注我的博客,获取更多技术干货。