目录直达
准备工作
-
注册讯飞账号,做相关的认证,只有认证通过才能下载部分免费的资源。官网地址:https://console.xfyun.cn/
-
创建我的应用后再在离线命令识别
- 操作前先查看一下这个官方文档Android 语音识别(Recognizer) | 讯飞开放平台文档中心 (xfyun.cn)
1、必要文件包复制到自己的项目目录中
1、在libs 目录下放置这些包
注意重新加载一些gradle
2、将assets 文件放置在 app 目录下
该文件下 iflytek/recognize.xml 文件是语音识别的ui文件,如果没有的话,点击语音识别app会直接闪退.
3、在build 目录下添加一下配置
sourceSets 这目录一定要添加,不然会报错 (创建对象失败,请确认 libmsc.so 放置正确,\n 且有调用 createUtility 进行初始化) 实质上是 包找不到 SpeechRecognizer 对象创建失败。(天坑 天坑 天坑 天坑 天坑)
android { sourceSets{ main{ jniLibs.srcDir(['libs']) } }}dependencies { implementation files('libs/Msc.jar') }
4、工具类拷贝到项目文件中
这里主要是一些讯飞提供的工具类,主要使用到的是json转换工具
setting 文件下的是语音命令识别和语音合成(暂时不使用)的设置
5、在AndroidManifest.xml 添加权限
<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.WRITE_EXTERNAL_STORAGE"/>
2、新建 IatActivity 声明必要的类成员
private static String TAG = "IatActivity";// 语音听写对象private SpeechRecognizer mIat;// 语音听写UIprivate RecognizerDialog mIatDialog;// 听写结果内容private EditText mResultText;// 用HashMap存储听写结果private HashMap<String, String> mIatResults = new LinkedHashMap<>();private SharedPreferences mSharedPreferences;private Toast mToast;private String mEngineType = "cloud";
3、初始化监听
private InitListener mInitListener = new InitListener() { @Override public void onInit(int code) { Log.d(TAG, "SpeechRecognizer init() code = " + code); if (code != ErrorCode.SUCCESS) { showTip("初始化失败,错误码:" + code + ",请点击网址https://www.xfyun.cn/document/error-code查询解决方案"); } } };
4、语音命令识别的周期监听
private RecognizerListener mRecognizerListener = new RecognizerListener() { @Override public void onBeginOfSpeech() { // 此回调表示:sdk内部录音机已经准备好了,用户可以开始语音输入 showTip("开始说话"); } @Override public void onError(SpeechError error) { // Tips: // 错误码:10118(您没有说话),可能是录音机权限被禁,需要提示用户打开应用的录音权限。 showTip(error.getPlainDescription(true)); } @Override public void onEndOfSpeech() { // 此回调表示:检测到了语音的尾端点,已经进入识别过程,不再接受语音输入 showTip("结束说话"); } @Override public void onResult(RecognizerResult results, boolean isLast) { String text = JsonParser.parseIatResult(results.getResultString()); mResultText.append(text); mResultText.setSelection(mResultText.length()); if (isLast) { //TODO 最后的结果 } } @Override public void onVolumeChanged(int volume, byte[] data) { showTip("当前正在说话,音量大小:" + volume); Log.d(TAG, "返回音频数据:" + data.length); } @Override public void onEvent(int eventType, int arg1, int arg2, Bundle obj) { // 以下代码用于获取与云端的会话id,当业务出错时将会话id提供给技术支持人员,可用于查询会话日志,定位出错原因 // 若使用本地能力,会话id为null if (SpeechEvent.EVENT_SESSION_ID == eventType) { String sid = obj.getString(SpeechEvent.KEY_EVENT_AUDIO_URL); Log.d(TAG, "session id =" + sid); } } };
5、离线命令UI监听
private RecognizerDialogListener mRecognizerDialogListener = new RecognizerDialogListener() { public void onResult(RecognizerResult results, boolean isLast) { Log.d(TAG, "recognizer result:" + results.getResultString()); String text = JsonParser.parseIatResult(results.getResultString()); System.out.println("语音听写结果为:" + text); if(!text.equals("")){ System.out.println("蓝牙发送了"); bluetoothUtils.write("1"); } mResultText.append(text); mResultText.setSelection(mResultText.length()); } public void onError(SpeechError error) { showTip(error.getPlainDescription(true)); } };
6、获取离线资源
在离线命令识别这里其实没有使用到的,因为.jet文件是语音发音包,就是官方提供的免费语音发音包
private String getResourcePath() { StringBuffer tempBuffer = new StringBuffer(); //识别通用资源 tempBuffer.append(ResourceUtil.generateResourcePath(this, ResourceUtil.RESOURCE_TYPE.assets, "iat/common.jet")); tempBuffer.append(";"); tempBuffer.append(ResourceUtil.generateResourcePath(this, ResourceUtil.RESOURCE_TYPE.assets, "iat/sms_16k.jet")); //识别8k资源-使用8k的时候请解开注释 return tempBuffer.toString();}
7、参数设置
参数设置这块,主要是为命令识别功能做配置,就像使用springboot 一样需要在yml里面配置,这里只是举个例子,在讯飞这里,命令识别有参数设置,语音合成也有参数设置,需要区分好。
public void setParam() { // 清空参数 mIat.setParameter(SpeechConstant.PARAMS, null); String lag = mSharedPreferences.getString("iat_language_preference", "mandarin"); // 设置引擎 mIat.setParameter(SpeechConstant.ENGINE_TYPE, mEngineType); // 设置返回结果格式 mIat.setParameter(SpeechConstant.RESULT_TYPE, "json"); //mIat.setParameter(MscKeys.REQUEST_AUDIO_URL,"true"); //this.mTranslateEnable = mSharedPreferences.getBoolean( this.getString(R.string.pref_key_translate), false ); if (mEngineType.equals(SpeechConstant.TYPE_LOCAL)) { // 设置本地识别资源 mIat.setParameter(ResourceUtil.ASR_RES_PATH, getResourcePath()); } // 在线听写支持多种小语种,若想了解请下载在线听写能力,参看其speechDemo if (lag.equals("en_us")) { // 设置语言 mIat.setParameter(SpeechConstant.LANGUAGE, "en_us"); mIat.setParameter(SpeechConstant.ACCENT, null); // 设置语言 mIat.setParameter(SpeechConstant.LANGUAGE, "zh_cn"); // 设置语言区域 mIat.setParameter(SpeechConstant.ACCENT, lag); } // 设置语音前端点:静音超时时间,即用户多长时间不说话则当做超时处理 mIat.setParameter(SpeechConstant.VAD_BOS, mSharedPreferences.getString("iat_vadbos_preference", "4000")); // 设置语音后端点:后端点静音检测时间,即用户停止说话多长时间内即认为不再输入, 自动停止录音 mIat.setParameter(SpeechConstant.VAD_EOS, mSharedPreferences.getString("iat_vadeos_preference", "1000")); // 设置标点符号,设置为"0"返回结果无标点,设置为"1"返回结果有标点 mIat.setParameter(SpeechConstant.ASR_PTT, mSharedPreferences.getString("iat_punc_preference", "1")); // 设置音频保存路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限 mIat.setParameter(SpeechConstant.AUDIO_FORMAT, "wav"); mIat.setParameter(SpeechConstant.ASR_AUDIO_PATH, getExternalFilesDir("msc").getAbsolutePath() + "/iat.wav"); }
8、弹窗提示
private void showTip(final String str) { if (mToast != null) { mToast.cancel(); } mToast = Toast.makeText(getApplicationContext(), str, Toast.LENGTH_SHORT); mToast.show();}
9、语音权限提示窗口
平常我们使用app 都会获取手机的权限,只有用户同意后才能使用app。这里就是这样的一个效果
private void showPrivacyDialog() { AppCompatTextView textView = new AppCompatTextView(this); textView.setPadding(100, 50, 100, 50); textView.setText( HtmlCompat.fromHtml("我们非常重视对您个人信息的保护,承诺严格按照讯飞开放平台《隐私政策》保护及处理您的信息,是否确定同意?", HtmlCompat.FROM_HTML_MODE_LEGACY)); textView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse("https://www.xfyun.cn/doc/policy/sdk_privacy.html")); startActivity(intent); } }); AlertDialog dialog = new AlertDialog.Builder(this) .setTitle("温馨提示") .setView(textView) .setPositiveButton("同意", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { mSharedPreferences.edit().putBoolean(SpeechApp.PRIVACY_KEY, true).apply(); dialog.dismiss(); } }) .setNegativeButton("不同意", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { mSharedPreferences.edit().putBoolean(SpeechApp.PRIVACY_KEY, false).apply(); finish(); System.exit(0); } }) .create(); dialog.setCanceledOnTouchOutside(false); dialog.show();}
10、动态申请权限
andriod 的高版本在AndroidManifest.xml 配置了权限还不够,还需要在 onCreate()中动态申请权限
注意 安装12以上(sdk 33 )需要这样写
String permissions[] = {android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.INTERNET, android.Manifest.permission.WRITE_EXTERNAL_STORAGE };
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); }}
11、在onCreate() 方法中初始
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_iat); // 初始化识别无UI识别对象 // 使用SpeechRecognizer对象,可根据回调消息自定义界面; mIat = SpeechRecognizer.createRecognizer(this, mInitListener); // 初始化听写Dialog,如果只使用有UI听写功能,无需创建SpeechRecognizer // 使用UI听写功能,请根据sdk文件目录下的notice.txt,放置布局文件和图片资源 mIatDialog = new RecognizerDialog(this, mInitListener); mSharedPreferences = getSharedPreferences(IatSettings.PREFER_NAME, Activity.MODE_PRIVATE); mResultText = findViewById(R.id.tv_result)); Button_Test(); }
12、按钮点击 处理识别命令测试
private void Button_Test(){ Button button = findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (null == mIat) { // 创建单例失败,与 21001 错误为同样原因,参考 http://bbs.xfyun.cn/forum.php?mod=viewthread&tid=9688 showTip("创建对象失败,请确认 libmsc.so 放置正确,\n 且有调用 createUtility 进行初始化"); return; } mResultText.setText(null);// 清空显示内容 mIatResults.clear(); // 设置参数 setParam(); boolean isShowDialog = mSharedPreferences.getBoolean(getString(R.string.pref_key_iat_show), true); if (isShowDialog) { try { // 显示听写对话框 mIatDialog.setListener(mRecognizerDialogListener); mIatDialog.show(); // todo 对话框显示不出来一直报错 showTip(getString(R.string.text_begin)); } catch (Exception e) { throw new RuntimeException(e); } } else { // 不显示听写对话框 ret = mIat.startListening(mRecognizerListener); if (ret != ErrorCode.SUCCESS) { showTip("听写失败,错误码:" + ret + ",请点击网址https://www.xfyun.cn/document/error-code查询解决方案"); } else { showTip(getString(R.string.text_begin)); } } } }); }
13、界面activity_iat.xml
<?xml version="1.0" encoding="utf-8"?><androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="93dp" android:layout_marginBottom="46dp" android:text="开始听写" app:layout_constraintBottom_toTopOf="@+id/tv_result" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.498" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <EditText android:id="@+id/tv_result" android:layout_width="0dp" android:layout_height="0dp" android:layout_marginBottom="493dp" android:layout_weight="1" android:gravity="center" android:text="语音识别到的内容" android:textColor="#000" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/button" /></androidx.constraintlayout.widget.ConstraintLayout>
14、strings.xml
该文件是讯飞官网下载后提供的,只要是一些公共的字符串,自己创建的项目大多数都没有用到,不过最好写上不然有的找不到报错(坑),可以将不要的删掉
<resources> <string name="app_name">讯飞蓝牙集成appstring> <string name="app_id">23810fb7string> <string name="example_explain">本示例为讯飞语音Android平台开发者提供语音听写、语法识别、语义理解和语音合成等代码样例,旨在让用户能够依据该示例快速开发出基于语音接口的应用程序。string> <string name="text_tts_source"> 科大讯飞作为智能语音技术提供商,在智能语音技术领域有着长期的研究积累,并在中文语音合成、语音识别、口语评测等多项技术上拥有技术成果。科大讯飞是我国以语音技术为产业化方向的“国家863计划产业化基地”..... string> <string name="text_tts_source_en">iFLYTEK is a national key software enterprise dedicated to the research of intelligent speech and language technologies, development of software and chip products, provision of speech information services, and integration of E-government systems. The intelligent speech technology of iFLYTEK, the core technology of the company, represents the top level in the world. string> <string name="text_isr_abnf_hint">\t上传内容为:\n\t#ABNF 1.0 gb2312;\n\tlanguage zh-CN;\n\tmode voice;\n\troot $main;\n\t$main = $place1 到$place2 ;\n\t$place1 = 北京 | 武汉 | 南京 | 天津 | 东京;\n\t$place2 = 上海 | 合肥;string> <string name="text_understand_hint">\t您可以说:\n\t今天的天气怎么样?\n\t北京到上海的火车?\n\t来首歌吧?\n\n\t更多语义请登录:\n\thttp://aiui.xfyun.cn/ \n\t配置您的专属语义吧!string> <string name="text_begin">请开始说话…string> <string name="text_begin_recognizer">开始音频流识别string> <string name="text_upload_contacts">上传联系人string> <string name="text_upload_userwords">上传用户词表string> <string name="text_upload_success">上传成功string> <string name="text_userword_empty">词表下载失败或内容为空string> <string name="text_download_success">下载成功string> <string name="pref_key_iat_show">iat_showstring> <string name="pref_title_iat_show">显示听写界面string> <string name="pref_key_translate">translatestring> <string name="pref_title_translate">翻译string> <string-array name="voicer_cloud_entries"> <item>小燕item> <item>小宇item> <item>凯瑟琳item> <item>亨利item> <item>玛丽item> <item>小研item> <item>小琪item> <item>小峰item> <item>小梅item> <item>小莉item> <item>小蓉item> <item>小芸item> <item>小坤item> <item>小强 item> <item>小莹item> <item>小新item> <item>楠楠item> <item>老孙item> string-array> <string-array name="voicer_cloud_values"> <item>xiaoyanitem> <item>xiaoyuitem> <item>catherineitem> <item>henryitem> <item>vimaryitem> <item>vixyitem> <item>xiaoqiitem> <item>vixfitem> <item>xiaomeiitem> <item>xiaolinitem> <item>xiaorongitem> <item>xiaoqianitem> <item>xiaokunitem> <item>xiaoqiangitem> <item>vixyingitem> <item>xiaoxinitem> <item>nannanitem> <item>vilsitem> string-array> <string-array name="voicer_xtts_entries"> <item>nannanitem> <item>小关item> <item>宜丰item> <item>小曦item> <item>小燕item> string-array> <string-array name="voicer_xtts_values"> <item>nannanitem> <item>xiaoguanitem> <item>yifengitem> <item>xiaoxiitem> <item>xiaoyanitem> string-array> <string-array name="voicer_local_entries"> <item>小燕item> <item>小峰item> string-array> <string-array name="voicer_local_values"> <item>xiaoyanitem> <item>xiaofengitem> string-array> <string-array name="stream_entries"> <item>通话item> <item>系统item> <item>铃声item> <item>音乐item> <item>闹铃item> <item>通知item> string-array> <string-array name="stream_values"> <item>0item> <item>1item> <item>2item> <item>3item> <item>4item> <item>5item> string-array> <string name="tts_toast_format" formatted="false">缓冲进度为%d%%,播放进度为%d%%string> <string-array name="language_entries"> <item>普通话item> <item>粤语item> <item>英语item> string-array> <string-array name="language_values"> <item>mandarinitem> <item>cantoneseitem> <item>en_usitem> string-array> <string-array name="punc_entries"> <item>有标点item> <item>无标点item> string-array> <string-array name="punc_values"> <item>1item> <item>0item> string-array> <string name="example_explain_wake">唤醒是指通过说出特定的唤醒词来唤醒处于休眠状态下的设备,又分为唤醒和唤醒+识别。string> <string name="wake_demo_hint">请点击“开始唤醒”后读出您在开放平台购买的唤醒词,当引擎计算得分大于您设置的门限值时,即可进行唤醒。string> <string name="oneshot_demo_hint">请点击“唤醒+识别”后读出您在开放平台购买的唤醒词+语法中指定的识别对象,当引擎计算得分大于您设置的门限值时,即可进行唤醒+识别。string> <string name="oneshot_resource_hint">本示例识别词语为“张三|李四|张海洋”,请开发者将语法文件中的唤醒词字段替换,本地语法定义详见demo工程的asset/wake.bnf文件。string>resources>
测试效果
博主打算将语音和蓝牙整合,通过语音命令发送蓝牙指令,如果想了解andriod蓝牙请参考以下线观文章
来源地址:https://blog.csdn.net/weixin_45833112/article/details/129885232