科大訊飛離線語音命令詞識別的使用說明
最近因為專案的需求,需要在無網路的情況下實現語音識別的功能,因為之前線上識別一直用的科大的,所以經理就和我說,你花半天時間簡單熟悉一下,然後出一個Demo,下午有人過來看;因為之前科大線上SR也是別人做的,準確的說我只是瞭解過一點,也寫過相關的blog——百度語音識別結合雲知聲離線TTSDemo(AS),Android原生TTS的基本使用以及配合中文語音包實現中文TTS等,但是就半天不到的時間寫一個Demo還是很趕的,比較不熟悉。下面就來簡單的總結一下這半天的經歷。
第一階段 基礎準備
第一步:找到科大訊飛開發平臺官網,註冊賬戶
第二步:點選右上角“控制檯”進入個人控制檯
第三步:建立應用,根據選擇的服務生成SDK並下載
這裡我們新增離線命令詞識別服務,獲取了對應SDK之後,也就完成的最基本的準備工作了,生成的APPID很重要喲,這個不用說你也應該知道。我們的第一階段就算完成了
第二階段 Demo匯入
第四步:開啟AS,建立一個和上圖同名的應用
第五步:匯入SDK解壓資料夾下的sample目錄裡面的的mscV5PlusDemomodule
這裡面需要實現在AS專案中匯入module操作,如下圖所示:
選擇上面sample下面對應的mscV5PlusDemo即可,如果有需要調整sdk版本的就按照錯誤提示調整就好了,比較簡單;至此,我們就把SDK中的Demo(mscV5PlusDemo
第六步:這個時候選擇匯入的module,在arm機上執行,發現並不能正常執行,那麼你需要考慮以下幾個問題
(1)Demo中的離線命令詞識別的commen.jet檔案位置錯誤
在解壓資料夾的res目錄下找到asr資料夾,將其copy到Demo裡面的assets目錄下:
(2)一定要在arm機上測試,因為這個Demo裡面只有armeabi的so檔案。
(3)如果可以執行,進入如下介面,發現裡面不僅僅只有我們需要的離線命令詞識別,還有線上識別等等:
我們點選“立刻體驗語法識別”,關閉裝置網路,選擇下圖中的“本地”,然後點選“構建語法”
這個時候很有可能再報錯誤,檢視錯誤碼發現原來是沒有錄音許可權等許可權問題,這個時候你就納悶了,明明Demo程式碼中已經添加了許可權:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<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.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
為什麼還有問題,這個時候你再進入到Demo程式碼裡面檢視,裡面並沒有做6.0以及以上版本的動態許可權申請處理,所以怎麼辦了,要麼我們自己加上,要麼換一個低一點的機子測試一下。
// 開始識別,沒有許可權判斷
case R.id.isr_recognize:
((EditText)findViewById(R.id.isr_text)).setText(null);// 清空顯示內容
// 設定引數
if (!setParam()) {
showTip("請先構建語法。");
return;
};
ret = mAsr.startListening(mRecognizerListener);
if (ret != ErrorCode.SUCCESS) {
showTip("識別失敗,錯誤碼: " + ret);
}
break;
這裡我們就不深究了,因為後面還有好多內容了,假設這個時候你能夠正常運行了,也能在Demo中完成離線命令詞識別了。那麼下一階段就是瘦身處理了。
第三階段 功能瘦身
第七步:提取離線命令詞識別功能
不得不說,這個Demo對於我們只使用離線命令詞識別來說有一點冗餘,太多了;下面我們就來把離線命令詞功能抽取出來,如下圖:
實現離線命令詞識別的功能實現主要是上圖中紅色框中AsrDemo中的邏輯,其原始碼如下:
package com.iflytek.mscv5plusdemo;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.EditText;
import android.widget.RadioGroup;
import android.widget.RadioGroup.OnCheckedChangeListener;
import android.widget.Toast;
import com.iflytek.cloud.ErrorCode;
import com.iflytek.cloud.GrammarListener;
import com.iflytek.cloud.InitListener;
import com.iflytek.cloud.LexiconListener;
import com.iflytek.cloud.RecognizerListener;
import com.iflytek.cloud.RecognizerResult;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.SpeechRecognizer;
import com.iflytek.cloud.util.ContactManager;
import com.iflytek.cloud.util.ContactManager.ContactListener;
import com.iflytek.cloud.util.ResourceUtil;
import com.iflytek.cloud.util.ResourceUtil.RESOURCE_TYPE;
import com.iflytek.speech.util.FucUtil;
import com.iflytek.speech.util.JsonParser;
import com.iflytek.speech.util.XmlParser;
public class AsrDemo extends Activity implements OnClickListener{
private static String TAG = AsrDemo.class.getSimpleName();
// 語音識別物件
private SpeechRecognizer mAsr;
private Toast mToast;
// 快取
private SharedPreferences mSharedPreferences;
// 本地語法檔案
private String mLocalGrammar = null;
// 本地詞典
private String mLocalLexicon = null;
// 雲端語法檔案
private String mCloudGrammar = null;
// 本地語法構建路徑
private String grmPath = Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/msc/test";
// 返回結果格式,支援:xml,json
private String mResultType = "json";
private final String KEY_GRAMMAR_ABNF_ID = "grammar_abnf_id";
private final String GRAMMAR_TYPE_ABNF = "abnf";
private final String GRAMMAR_TYPE_BNF = "bnf";
private String mEngineType = "cloud";
@SuppressLint("ShowToast")
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.isrdemo);
initLayout();
// 初始化識別物件
mAsr = SpeechRecognizer.createRecognizer(this, mInitListener);
// 初始化語法、命令詞
mLocalLexicon = "張海羊\n劉婧\n王鋒\n";
mLocalGrammar = FucUtil.readFile(this,"call.bnf", "utf-8");
mCloudGrammar = FucUtil.readFile(this,"grammar_sample.abnf","utf-8");
// 獲取聯絡人,本地更新詞典時使用
ContactManager mgr = ContactManager.createManager(AsrDemo.this, mContactListener);
mgr.asyncQueryAllContactsName();
mSharedPreferences = getSharedPreferences(getPackageName(), MODE_PRIVATE);
mToast = Toast.makeText(this,"",Toast.LENGTH_SHORT);
}
/**
* 初始化Layout。
*/
private void initLayout(){
findViewById(R.id.isr_recognize).setOnClickListener(this);
findViewById(R.id.isr_grammar).setOnClickListener(this);
findViewById(R.id.isr_lexcion).setOnClickListener(this);
findViewById(R.id.isr_stop).setOnClickListener(this);
findViewById(R.id.isr_cancel).setOnClickListener(this);
//選擇雲端or本地
RadioGroup group = (RadioGroup)this.findViewById(R.id.radioGroup);
group.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
if(checkedId == R.id.radioCloud)
{
((EditText)findViewById(R.id.isr_text)).setText(mCloudGrammar);
findViewById(R.id.isr_lexcion).setEnabled(false);
mEngineType = SpeechConstant.TYPE_CLOUD;
}else if(checkedId == R.id.radioLocal)
{
((EditText)findViewById(R.id.isr_text)).setText(mLocalGrammar);
findViewById(R.id.isr_lexcion).setEnabled(true);
mEngineType = SpeechConstant.TYPE_LOCAL;
}
}
});
}
String mContent;// 語法、詞典臨時變數
int ret = 0;// 函式呼叫返回值
@Override
public void onClick(View view) {
if( null == mAsr ){
// 建立單例失敗,與 21001 錯誤為同樣原因,參考 http://bbs.xfyun.cn/forum.php?mod=viewthread&tid=9688
this.showTip( "建立物件失敗,請確認 libmsc.so 放置正確,\n 且有呼叫 createUtility 進行初始化" );
return;
}
if(null == mEngineType) {
showTip("請先選擇識別引擎型別");
return;
}
switch(view.getId())
{
case R.id.isr_grammar:
showTip("上傳預設關鍵詞/語法檔案");
// 本地-構建語法檔案,生成語法id
if (mEngineType.equals(SpeechConstant.TYPE_LOCAL)) {
((EditText)findViewById(R.id.isr_text)).setText(mLocalGrammar);
mContent = new String(mLocalGrammar);
mAsr.setParameter(SpeechConstant.PARAMS, null);
// 設定文字編碼格式
mAsr.setParameter(SpeechConstant.TEXT_ENCODING,"utf-8");
// 設定引擎型別
mAsr.setParameter(SpeechConstant.ENGINE_TYPE, mEngineType);
// 設定語法構建路徑
mAsr.setParameter(ResourceUtil.GRM_BUILD_PATH, grmPath);
//使用8k音訊的時候請解開註釋
// mAsr.setParameter(SpeechConstant.SAMPLE_RATE, "8000");
// 設定資源路徑
mAsr.setParameter(ResourceUtil.ASR_RES_PATH, getResourcePath());
ret = mAsr.buildGrammar(GRAMMAR_TYPE_BNF, mContent, grammarListener);
if(ret != ErrorCode.SUCCESS){
showTip("語法構建失敗,錯誤碼:" + ret);
}
}
// 線上-構建語法檔案,生成語法id
else {
((EditText)findViewById(R.id.isr_text)).setText(mCloudGrammar);
mContent = new String(mCloudGrammar);
// 指定引擎型別
mAsr.setParameter(SpeechConstant.ENGINE_TYPE, mEngineType);
// 設定文字編碼格式
mAsr.setParameter(SpeechConstant.TEXT_ENCODING,"utf-8");
ret = mAsr.buildGrammar(GRAMMAR_TYPE_ABNF, mContent, grammarListener);
if(ret != ErrorCode.SUCCESS)
showTip("語法構建失敗,錯誤碼:" + ret);
}
break;
// 本地-更新詞典
case R.id.isr_lexcion:
((EditText)findViewById(R.id.isr_text)).setText(mLocalLexicon);
mContent = new String(mLocalLexicon);
mAsr.setParameter(SpeechConstant.PARAMS, null);
// 設定引擎型別
mAsr.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_LOCAL);
// 設定資源路徑
mAsr.setParameter(ResourceUtil.ASR_RES_PATH, getResourcePath());
//使用8k音訊的時候請解開註釋
// mAsr.setParameter(SpeechConstant.SAMPLE_RATE, "8000");
// 設定語法構建路徑
mAsr.setParameter(ResourceUtil.GRM_BUILD_PATH, grmPath);
// 設定語法名稱
mAsr.setParameter(SpeechConstant.GRAMMAR_LIST, "call");
// 設定文字編碼格式
mAsr.setParameter(SpeechConstant.TEXT_ENCODING,"utf-8");
ret = mAsr.updateLexicon("contact", mContent, lexiconListener);
if(ret != ErrorCode.SUCCESS){
showTip("更新詞典失敗,錯誤碼:" + ret);
}
break;
// 開始識別
case R.id.isr_recognize:
((EditText)findViewById(R.id.isr_text)).setText(null);// 清空顯示內容
// 設定引數
if (!setParam()) {
showTip("請先構建語法。");
return;
};
ret = mAsr.startListening(mRecognizerListener);
if (ret != ErrorCode.SUCCESS) {
showTip("識別失敗,錯誤碼: " + ret);
}
break;
// 停止識別
case R.id.isr_stop:
mAsr.stopListening();
showTip("停止識別");
break;
// 取消識別
case R.id.isr_cancel:
mAsr.cancel();
showTip("取消識別");
break;
}
}
/**
* 初始化監聽器。
*/
private InitListener mInitListener = new InitListener() {
@Override
public void onInit(int code) {
Log.d(TAG, "SpeechRecognizer init() code = " + code);
if (code != ErrorCode.SUCCESS) {
showTip("初始化失敗,錯誤碼:"+code);
}
}
};
/**
* 更新詞典監聽器。
*/
private LexiconListener lexiconListener = new LexiconListener() {
@Override
public void onLexiconUpdated(String lexiconId, SpeechError error) {
if(error == null){
showTip("詞典更新成功");
}else{
showTip("詞典更新失敗,錯誤碼:"+error.getErrorCode());
}
}
};
/**
* 構建語法監聽器。
*/
private GrammarListener grammarListener = new GrammarListener() {
@Override
public void onBuildFinish(String grammarId, SpeechError error) {
if(error == null){
if (mEngineType.equals(SpeechConstant.TYPE_CLOUD)) {
Editor editor = mSharedPreferences.edit();
if(!TextUtils.isEmpty(grammarId))
editor.putString(KEY_GRAMMAR_ABNF_ID, grammarId);
editor.commit();
}
showTip("語法構建成功:" + grammarId);
}else{
showTip("語法構建失敗,錯誤碼:" + error.getErrorCode());
}
}
};
/**
* 獲取聯絡人監聽器。
*/
private ContactListener mContactListener = new ContactListener() {
@Override
public void onContactQueryFinish(String contactInfos, boolean changeFlag) {
//獲取聯絡人
mLocalLexicon = contactInfos;
}
};
/**
* 識別監聽器。
*/
private RecognizerListener mRecognizerListener = new RecognizerListener() {
@Override
public void onVolumeChanged(int volume, byte[] data) {
showTip("當前正在說話,音量大小:" + volume);
Log.d(TAG, "返回音訊資料:"+data.length);
}
@Override
public void onResult(final RecognizerResult result, boolean isLast) {
if (null != result && !TextUtils.isEmpty(result.getResultString())) {
Log.d(TAG, "recognizer result:" + result.getResultString());
String text = "";
if (mResultType.equals("json")) {
text = JsonParser.parseGrammarResult(result.getResultString(), mEngineType);
} else if (mResultType.equals("xml")) {
text = XmlParser.parseNluResult(result.getResultString());
}
// 顯示
((EditText) findViewById(R.id.isr_text)).setText(text);
} else {
Log.d(TAG, "recognizer result : null");
}
}
@Override
public void onEndOfSpeech() {
// 此回調錶示:檢測到了語音的尾端點,已經進入識別過程,不再接受語音輸入
showTip("結束說話");
}
@Override
public void onBeginOfSpeech() {
// 此回調錶示:sdk內部錄音機已經準備好了,使用者可以開始語音輸入
showTip("開始說話");
}
@Override
public void onError(SpeechError error) {
showTip("onError Code:" + error.getErrorCode());
}
@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_SESSION_ID);
// Log.d(TAG, "session id =" + sid);
// }
}
};
private void showTip(final String str) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mToast.setText(str);
mToast.show();
}
});
}
/**
* 引數設定
* @param
* @return
*/
public boolean setParam(){
boolean result = false;
// 清空引數
mAsr.setParameter(SpeechConstant.PARAMS, null);
// 設定識別引擎
mAsr.setParameter(SpeechConstant.ENGINE_TYPE, mEngineType);
if("cloud".equalsIgnoreCase(mEngineType))
{
String grammarId = mSharedPreferences.getString(KEY_GRAMMAR_ABNF_ID, null);
if(TextUtils.isEmpty(grammarId))
{
result = false;
}else {
// 設定返回結果格式
mAsr.setParameter(SpeechConstant.RESULT_TYPE, mResultType);
// 設定雲端識別使用的語法id
mAsr.setParameter(SpeechConstant.CLOUD_GRAMMAR, grammarId);
result = true;
}
}
else
{
// 設定本地識別資源
mAsr.setParameter(ResourceUtil.ASR_RES_PATH, getResourcePath());
// 設定語法構建路徑
mAsr.setParameter(ResourceUtil.GRM_BUILD_PATH, grmPath);
// 設定返回結果格式
mAsr.setParameter(SpeechConstant.RESULT_TYPE, mResultType);
// 設定本地識別使用語法id
mAsr.setParameter(SpeechConstant.LOCAL_GRAMMAR, "call");
// 設定識別的門限值
mAsr.setParameter(SpeechConstant.MIXED_THRESHOLD, "30");
// 使用8k音訊的時候請解開註釋
// mAsr.setParameter(SpeechConstant.SAMPLE_RATE, "8000");
result = true;
}
// 設定音訊儲存路徑,儲存音訊格式支援pcm、wav,設定路徑為sd卡請注意WRITE_EXTERNAL_STORAGE許可權
// 注:AUDIO_FORMAT引數語記需要更新版本才能生效
mAsr.setParameter(SpeechConstant.AUDIO_FORMAT,"wav");
mAsr.setParameter(SpeechConstant.ASR_AUDIO_PATH, Environment.getExternalStorageDirectory()+"/msc/asr.wav");
return result;
}
//獲取識別資源路徑
private String getResourcePath(){
StringBuffer tempBuffer = new StringBuffer();
//識別通用資源
tempBuffer.append(ResourceUtil.generateResourcePath(this, RESOURCE_TYPE.assets, "asr/common.jet"));
//識別8k資源-使用8k的時候請解開註釋
// tempBuffer.append(";");
// tempBuffer.append(ResourceUtil.generateResourcePath(this, RESOURCE_TYPE.assets, "asr/common_8k.jet"));
return tempBuffer.toString();
}
@Override
protected void onDestroy() {
super.onDestroy();
if( null != mAsr ){
// 退出時釋放連線
mAsr.cancel();
mAsr.destroy();
}
}
}
看著還是比較多的,我之所以說多而沒有說難就是因為它並不難;下面的介紹中我們會對其進行再次瘦身。
第八步:為自己的Demo做準備工作
(1)把assets目錄copy到我們的module中
(2)把jniLibs目錄copy到我們的module中
這裡是在Project檢視下完成的,這裡在Android檢視下展示效果更好一下
(3)開啟Project檢視,把libs目錄中的內容複製到我們的module中
(4)在build.gradle(Module:app)中的depandencies下新增依賴:
compile files('libs/Msc.jar')
(5)把Demo中的工具類copy到我們的module中
截止到現在,我們還在準備階段,下面就進入正題,來對我們的需要的功能的實現做一個簡要的梳理
第九步:提取離線命令詞識別功能到我們的專案
定義一個activity,CallStepActivity,把AsrDemo中的邏輯程式碼copy到CallStepActivty中,把對應的佈局檔案也對應copy進來
第十步:梳理邏輯,繼續瘦身
上面也說了,AsrDemo中的Demo還是有點冗餘,因為好多我們用不上或者暫時用不上,比如線上的命令詞識別等肯定用不上,比如詞典更新我們暫時用不上,下面就來分析一下單純使用離線命令詞識別的實現(下面是重點)
(1)根據應用ID初始化SpeechUtility,通常在程式入口Application中完成
package com.hfut.offlinerecongnizer.activity.util;
import android.app.Application;
import com.hfut.offlinerecongnizer.R;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechUtility;
/**
* author:why
* created on: 2018/8/27 11:10
* description:
*/
public class MyApplication extends Application {
@Override
public void onCreate() {
// 應用程式入口處呼叫,避免手機記憶體過小,殺死後臺程序後通過歷史intent進入Activity造成SpeechUtility物件為null
// 注意:此介面在非主程序呼叫會返回null物件,如需在非主程序使用語音功能,請增加引數:SpeechConstant.FORCE_LOGIN+"=true"
// 引數間使用“,”分隔。
// 設定你申請的應用appid
// 注意: appid 必須和下載的SDK保持一致,否則會出現10407錯誤
StringBuffer param = new StringBuffer();
param.append("appid=" + getString(R.string.app_id));
param.append(",");
// 設定使用v5+
param.append(SpeechConstant.ENGINE_MODE + "=" + SpeechConstant.MODE_MSC);
SpeechUtility.createUtility(MyApplication.this, param.toString());
super.onCreate();
}
}
(2)在Activity中初始化初始化監聽器,用於初始化語音識別引擎
/**
* 初始化監聽器。
*/
private InitListener mInitListener = new InitListener() {
@Override
public void onInit(int code) {
Log.d(TAG, "SpeechRecognizer init() code = " + code);
if (code != ErrorCode.SUCCESS) {
showTip("初始化失敗,錯誤碼:" + code);
}
}
};
(3)初始化語音識別監聽器
/**
* 識別監聽器。
*/
private RecognizerListener mRecognizerListener = new RecognizerListener() {
@Override
public void onVolumeChanged(int volume, byte[] data) {
showTip("當前正在說話,音量大小:" + volume);
Log.d(TAG, "返回音訊資料:" + data.length);
}
@Override
public void onResult(final RecognizerResult result, boolean isLast) {
if (null != result && !TextUtils.isEmpty(result.getResultString())) {
Log.d(TAG, "recognizer result:" + result.getResultString());
String text = "";
if (mResultType.equals("json")) {
text = JsonParser.parseGrammarResult(result.getResultString(), SpeechConstant.TYPE_LOCAL);
} else if (mResultType.equals("xml")) {
text = XmlParser.parseNluResult(result.getResultString());
}
// 顯示
((EditText) findViewById(R.id.isr_text)).setText(text);
} else {
Log.d(TAG, "recognizer result : null");
}
}
@Override
public void onEndOfSpeech() {
// 此回調錶示:檢測到了語音的尾端點,已經進入識別過程,不再接受語音輸入
showTip("結束說話");
}
@Override
public void onBeginOfSpeech() {
// 此回調錶示:sdk內部錄音機已經準備好了,使用者可以開始語音輸入
showTip("開始說話");
}
@Override
public void onError(SpeechError error) {
showTip("onError Code:" + error.getErrorCode());
}
@Override
public void onEvent(int i, int i1, int i2, Bundle bundle) {
}
};
(4)初始化語法檔案構建監聽器
/**
* 構建語法監聽器。
*/
private GrammarListener grammarListener = new GrammarListener() {
@Override
public void onBuildFinish(String grammarId, SpeechError error) {
if (error == null) {
showTip("語法構建成功:" + grammarId);
} else {
showTip("語法構建失敗,錯誤碼:" + error.getErrorCode());
}
}
};
(5)初始化語音識別引擎並完成引數設定
// 初始化識別引擎
mAsr = SpeechRecognizer.createRecognizer(this, mInitListener);
//設定識別引擎引數
setParam();
其中setPatam():
public void setParam() {
boolean result = true;
// 清空引數
mAsr.setParameter(SpeechConstant.PARAMS, null);
// 設定識別引擎
mAsr.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_LOCAL);
// 設定本地識別資源
mAsr.setParameter(ResourceUtil.ASR_RES_PATH, getResourcePath());
// 設定語法構建路徑
mAsr.setParameter(ResourceUtil.GRM_BUILD_PATH, grmPath);
// 設定返回結果格式
mAsr.setParameter(SpeechConstant.RESULT_TYPE, mResultType);
// 設定本地識別使用語法id
mAsr.setParameter(SpeechConstant.LOCAL_GRAMMAR, "call");
// 設定識別的門限值
mAsr.setParameter(SpeechConstant.MIXED_THRESHOLD, "30");
}
(6)完成語法構建
private void buildGrammer() {
mLocalGrammar = FucUtil.readFile(this, "call.bnf", "utf-8");
// 本地-構建語法檔案,生成語法id
((EditText) findViewById(R.id.isr_text)).setText(mLocalGrammar);
mContent = new String(mLocalGrammar);
mAsr.setParameter(SpeechConstant.PARAMS, null);
// 設定文字編碼格式
mAsr.setParameter(SpeechConstant.TEXT_ENCODING, "utf-8");
// 設定引擎型別
mAsr.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_LOCAL);
// 設定語法構建路徑
mAsr.setParameter(ResourceUtil.GRM_BUILD_PATH, grmPath);
// 設定資源路徑
mAsr.setParameter(ResourceUtil.ASR_RES_PATH, getResourcePath());
ret = mAsr.buildGrammar(GRAMMAR_TYPE_BNF, mContent, grammarListener);
if (ret != ErrorCode.SUCCESS) {
showTip("語法構建失敗,錯誤碼:" + ret);
} else {
showTip("語法構建成功");
}
}
(7)開啟識別,停止識別,取消識別分別是:
mAsr.startListening(mRecognizerListener);
mAsr.stopListening();
mAsr.cancel();
第十一步:最簡單的功能實現程式碼
所以最後組合起來,我們實現剝離了所有其他功能的只是實現離線命令詞識別的程式碼,CallStepActivity程式碼如下:
package com.hfut.offlinerecongnizer.activity.activity;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.SharedPreferences;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.hfut.offlinerecongnizer.R;
import com.hfut.offlinerecongnizer.activity.util.FucUtil;
import com.hfut.offlinerecongnizer.activity.util.JsonParser;
import com.hfut.offlinerecongnizer.activity.util.XmlParser;
import com.iflytek.cloud.ErrorCode;
import com.iflytek.cloud.GrammarListener;
import com.iflytek.cloud.InitListener;
import com.iflytek.cloud.LexiconListener;
import com.iflytek.cloud.RecognizerListener;
import com.iflytek.cloud.RecognizerResult;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.SpeechRecognizer;
import com.iflytek.cloud.util.ContactManager;
import com.iflytek.cloud.util.ResourceUtil;
/**
* @author why
* @date 2018-8-27 15:09:38
*/
public class CallStepActivity extends AppCompatActivity implements View.OnClickListener {
private static String TAG = OffLineTestActivity.class.getSimpleName();
// 語音識別物件
private SpeechRecognizer mAsr;
private Toast mToast;
// 本地語法檔案
private String mLocalGrammar = null;
// 本地語法構建路徑
private String grmPath = Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/msc/call";
// 返回結果格式,支援:xml,json
private String mResultType = "json";
private final String GRAMMAR_TYPE_BNF = "bnf";
@SuppressLint("ShowToast")
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_call_step);
initLayout();
mToast = Toast.makeText(this, "", Toast.LENGTH_SHORT);
// 初始化識別引擎
mAsr = SpeechRecognizer.createRecognizer(this, mInitListener);
//構建本地語法
buildGrammer();
}
/**
* 初始化Layout。
*/
private void initLayout() {
findViewById(R.id.isr_recognize).setOnClickListener(this);
findViewById(R.id.isr_stop).setOnClickListener(this);
findViewById(R.id.isr_cancel).setOnClickListener(this);
}
String mContent;// 語法、詞典臨時變數
int ret = 0;// 函式呼叫返回值
@Override
public void onClick(View view) {
if (null == mAsr) {
// 建立單例失敗,與 21001 錯誤為同樣原因,參考 http://bbs.xfyun.cn/forum.php?mod=viewthread&tid=9688
this.showTip("建立物件失敗,請確認 libmsc.so 放置正確,\n 且有呼叫 createUtility 進行初始化");
return;
}
switch (view.getId()) {
// 開始識別
case R.id.isr_recognize:
((EditText) findViewById(R.id.isr_text)).setText(null);// 清空顯示內容
//設定識別引擎引數
setParam();
ret = mAsr.startListening(mRecognizerListener);
if (ret != ErrorCode.SUCCESS) {
showTip("識別失敗,錯誤碼: " + ret);
}
break;
// 停止識別
case R.id.isr_stop:
mAsr.stopListening();
showTip("停止識別");
break;
// 取消識別
case R.id.isr_cancel:
mAsr.cancel();
showTip("取消識別");
break;
}
}
/**
* 初始化監聽器。
*/
private InitListener mInitListener = new InitListener() {
@Override
public void onInit(int code) {
Log.d(TAG, "SpeechRecognizer init() code = " + code);
if (code != ErrorCode.SUCCESS) {
showTip("初始化失敗,錯誤碼:" + code);
}
}
};
/**
* 構建語法監聽器。
*/
private GrammarListener grammarListener = new GrammarListener() {
@Override
public void onBuildFinish(String grammarId, SpeechError error) {
if (error == null) {
showTip("語法構建成功:" + grammarId);
} else {
showTip("語法構建失敗,錯誤碼:" + error.getErrorCode());
}
}
};
/**
* 識別監聽器。
*/
private RecognizerListener mRecognizerListener = new RecognizerListener() {
@Override
public void onVolumeChanged(int volume, byte[] data) {
showTip("當前正在說話,音量大小:" + volume);
Log.d(TAG, "返回音訊資料:" + data.length);
}
@Override
public void onResult(final RecognizerResult result, boolean isLast) {
if (null != result && !TextUtils.isEmpty(result.getResultString())) {
Log.d(TAG, "recognizer result:" + result.getResultString());
String text = "";
if (mResultType.equals("json")) {
text = JsonParser.parseGrammarResult(result.getResultString(), SpeechConstant.TYPE_LOCAL);
} else if (mResultType.equals("xml")) {
text = XmlParser.parseNluResult(result.getResultString());
}
// 顯示
((EditText) findViewById(R.id.isr_text)).setText(text);
} else {
Log.d(TAG, "recognizer result : null");
}
}
@Override
public void onEndOfSpeech() {
// 此回調錶示:檢測到了語音的尾端點,已經進入識別過程,不再接受語音輸入
showTip("結束說話");
}
@Override
public void onBeginOfSpeech() {
// 此回調錶示:sdk內部錄音機已經準備好了,使用者可以開始語音輸入
showTip("開始說話");
}
@Override
public void onError(SpeechError error) {
showTip("onError Code:" + error.getErrorCode());
}
@Override
public void onEvent(int i, int i1, int i2, Bundle bundle) {
}
};
private void showTip(final String str) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mToast.setText(str);
mToast.show();
}
});
}
/**
* 引數設定
*
* @param
* @return
*/
public void setParam() {
boolean result = true;
// 清空引數
mAsr.setParameter(SpeechConstant.PARAMS, null);
// 設定識別引擎
mAsr.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_LOCAL);
// 設定本地識別資源
mAsr.setParameter(ResourceUtil.ASR_RES_PATH, getResourcePath());
// 設定語法構建路徑
mAsr.setParameter(ResourceUtil.GRM_BUILD_PATH, grmPath);
// 設定返回結果格式
mAsr.setParameter(SpeechConstant.RESULT_TYPE, mResultType);
// 設定本地識別使用語法id
mAsr.setParameter(SpeechConstant.LOCAL_GRAMMAR, "call");
// 設定識別的門限值
mAsr.setParameter(SpeechConstant.MIXED_THRESHOLD, "30");
// 設定音訊儲存路徑,儲存音訊格式支援pcm、wav,設定路徑為sd卡請注意WRITE_EXTERNAL_STORAGE許可權
// 注:AUDIO_FORMAT引數語記需要更新版本才能生效
mAsr.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");
mAsr.setParameter(SpeechConstant.ASR_AUDIO_PATH, Environment.getExternalStorageDirectory() + "/msc/asr.wav");
}
//獲取識別資源路徑
private String getResourcePath() {
StringBuffer tempBuffer = new StringBuffer();
//識別通用資源
tempBuffer.append(ResourceUtil.generateResourcePath(this, ResourceUtil.RESOURCE_TYPE.assets, "asr/common.jet"));
return tempBuffer.toString();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (null != mAsr) {
// 退出時釋放連線
mAsr.cancel();
mAsr.destroy();
}
}
private void buildGrammer() {
mLocalGrammar = FucUtil.readFile(this, "call.bnf", "utf-8");
// 本地-構建語法檔案,生成語法id
((EditText) findViewById(R.id.isr_text)).setText(mLocalGrammar);
mContent = new String(mLocalGrammar);
mAsr.setParameter(SpeechConstant.PARAMS, null);
// 設定文字編碼格式
mAsr.setParameter(SpeechConstant.TEXT_ENCODING, "utf-8");
// 設定引擎型別
mAsr.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_LOCAL);
// 設定語法構建路徑
mAsr.setParameter(ResourceUtil.GRM_BUILD_PATH, grmPath);
//使用8k音訊的時候請解開註釋
// mAsr.setParameter(SpeechConstant.SAMPLE_RATE, "8000");
// 設定資源路徑
mAsr.setParameter(ResourceUtil.ASR_RES_PATH, getResourcePath());
ret = mAsr.buildGrammar(GRAMMAR_TYPE_BNF, mContent, grammarListener);
if (ret != ErrorCode.SUCCESS) {
showTip("語法構建失敗,錯誤碼:" + ret);
} else {
showTip("語法構建成功");
}
}
}
activity_call_step.xml檔案:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:focusable="true"
android:focusableInTouchMode="true"
android:gravity="center_horizontal"
android:orientation="vertical"
android:padding="10dip" >
<include layout="@layout/title" />
<EditText
android:id="@+id/isr_text"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:gravity="top|left"
android:textSize="20sp" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dip"
android:layout_marginBottom="2dip"
android:gravity="center_horizontal"
android:orientation="horizontal" >
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dip"
android:layout_marginBottom="2dip"
android:gravity="center_horizontal"
android:orientation="horizontal" >
<Button
android:id="@+id/isr_recognize"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="開始識別"
android:textSize="20sp" />
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="2dip"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:layout_marginTop="2dip"
android:gravity="center_horizontal"
android:orientation="horizontal" >
<Button
android:id="@+id/isr_stop"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="停止錄音"
android:textSize="20sp" />
<Button
android:id="@+id/isr_cancel"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="取消"
android:textSize="20sp" />
</LinearLayout>
</LinearLayout>
如果不出意外的話,執行應該沒有任何問題的。至此,最難的最複雜的第三階段已經結束了,下面就來看看第四階段的工作任務:
第四階段 提高
第十二步:豐富我們的功能
因為API裡面提供了更新詞典的功能(從這裡我們也可以推出來後面介紹的bnf檔案中詞槽的定義也可以通過程式碼來實現):
mAsr.updateLexicon(groupName, mLocalLexicon, lexiconListener);
所以我們就該利用起來,畢竟如果我想修改某一個詞槽的定義時,不能每次都是通過編輯bnf檔案,然後在執行程式來實現,太麻煩了。這裡我通過一個自定義的AlertDialog來實現對詞槽的重新賦值,並列的同義詞用“,”隔開即可,類似於bnf檔案中的 | 符號;下面直接給出OffLineTestActivity程式碼:
package com.hfut.offlinerecongnizer.activity.activity;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RadioGroup;
import android.widget.Toast;
import com.hfut.offlinerecongnizer.R;
import com.hfut.offlinerecongnizer.activity.util.FucUtil;
import com.hfut.offlinerecongnizer.activity.util.JsonParser;
import com.hfut.offlinerecongnizer.activity.util.XmlParser;
import com.iflytek.cloud.ErrorCode;
import com.iflytek.cloud.GrammarListener;
import com.iflytek.cloud.InitListener;
import com.iflytek.cloud.LexiconListener;
import com.iflytek.cloud.RecognizerListener;
import com.iflytek.cloud.RecognizerResult;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.SpeechRecognizer;
import com.iflytek.cloud.util.ContactManager;
import com.iflytek.cloud.util.ContactManager.ContactListener;
import com.iflytek.cloud.util.ResourceUtil;
import com.iflytek.cloud.util.ResourceUtil.RESOURCE_TYPE;
/**
* @author why
* @date 2018-8-27 13:20:58
*/
public class OffLineTestActivity extends AppCompatActivity implements View.OnClickListener {
private static String TAG = OffLineTestActivity.class.getSimpleName();
// 語音識別物件
private SpeechRecognizer mAsr;
private Toast mToast;
// 快取
//private SharedPreferences mSharedPreferences;
// 本地語法檔案
private String mLocalGrammar = null;
// 本地詞典
private String mLocalLexicon = null;
// 本地語法構建路徑
private String grmPath = Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/msc/call";
// 返回結果格式,支援:xml,json
private String mResultType = "json";
private final String GRAMMAR_TYPE_BNF = "bnf";
private String groupName;
private String groupInfo;
@SuppressLint("ShowToast")
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_off_line_test);
initLayout();
// 初始化識別引擎物件
mAsr = SpeechRecognizer.createRecognizer(this, mInitListener);
mToast = Toast.makeText(this, "", Toast.LENGTH_SHORT);
//構建本地語法
buildGrammer();
}
/**
* 初始化Layout
*/
private void initLayout() {
findViewById(R.id.isr_recognize).setOnClickListener(this);
findViewById(R.id.isr_lexcion).setOnClickListener(this);
findViewById(R.id.isr_stop).setOnClickListener(this);
findViewById(R.id.isr_cancel).setOnClickListener(this);
}
String mContent;// 語法、詞典臨時變數
int ret = 0;// 函式呼叫返回值
@Override
public void onClick(View view) {
if (null == mAsr) {
// 建立單例失敗,與 21001 錯誤為同樣原因,參考 http://bbs.xfyun.cn/forum.php?mod=viewthread&tid=9688
this.showTip("建立物件失敗,請確認 libmsc.so 放置正確,\n 且有呼叫 createUtility 進行初始化");
return;
}
switch (view.getId()) {
// 本地-更新詞典
case R.id.isr_lexcion:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
LayoutInflater inflater = LayoutInflater.from(this);
final View v = inflater.inflate(R.layout.user_info_editor, null);
final EditText wordGroupName = v.findViewById(R.id.enter_word_group_name);
final EditText wordGroupInfo = v.findViewById(R.id.enter_word_group_info);
Button cancleButton = v.findViewById(R.id.register_cancle);
Button confirmButton = v.findViewById(R.id.register_confirm);
final Dialog dialog = builder.create();
//點選EditText彈出軟鍵盤
cancleButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(OffLineTestActivity.this, "取消", Toast.LENGTH_SHORT).show();
dialog.cancel();
}
});
confirmButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!wordGroupName.getText().toString().equals("")) {
groupName= wordGroupName.getText().toString();
}
if (!wordGroupInfo.getText().toString().equals("")) {
groupInfo = wordGroupInfo.getText().toString();
}
mLocalLexicon=getUpdateInfo(groupInfo);
((EditText) findViewById(R.id.isr_text)).setText(mLocalLexicon);
mAsr.setParameter(SpeechConstant.PARAMS, null);
// 設定引擎型別
mAsr.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_LOCAL);
// 設定資源路徑
mAsr.setParameter(ResourceUtil.ASR_RES_PATH, getResourcePath());
// 設定語法構建路徑
mAsr.setParameter(ResourceUtil.GRM_BUILD_PATH, grmPath);
// 設定語法名稱
mAsr.setParameter(SpeechConstant.GRAMMAR_LIST, "call");
// 設定文字編碼格式
mAsr.setParameter(SpeechConstant.TEXT_ENCODING, "utf-8");
//執行更新操作
ret = mAsr.updateLexicon(groupName, mLocalLexicon, lexiconListener);
if (ret != ErrorCode.SUCCESS) {
showTip("更新詞典失敗,錯誤碼:" + ret);
}
else{
showTip("更新詞典成功" );
}
dialog.cancel();
}
});
dialog.show();
dialog.getWindow().setContentView(v);//自定義佈局應該在這裡新增,要在dialog.show()的後面
dialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
break;
// 開始識別
case R.id.isr_recognize:
//設定識別引擎引數
setParam();
((EditText) findViewById(R.id.isr_text)).setText(null);// 清空顯示內容
ret = mAsr.startListening(mRecognizerListener);
if (ret != ErrorCode.SUCCESS) {
showTip("識別失敗,錯誤碼: " + ret);
}
break;
// 停止識別
case R.id.isr_stop:
mAsr.stopListening();
showTip("停止識別");
break;
// 取消識別
case R.id.isr_cancel:
mAsr.cancel();
showTip("取消識別");
break;
}
}
private String getUpdateInfo(String groupInfo) {
String[] wordList=groupInfo.split(",");
StringBuilder builder=new StringBuilder();
for(int i=0;i<wordList.length;i++){
if(i==wordList.length-1) {
builder.append(wordList[i] );
Log.d(TAG, "getUpdateInfo: "+wordList[i]);
}else{
builder.append(wordList[i] + "\n");
}
}
return builder.toString();
}
/**
* 初始化監聽器。
*/
private InitListener mInitListener = new InitListener() {
@Override
public void onInit(int code) {
Log.d(TAG, "SpeechRecognizer init() code = " + code);
if (code != ErrorCode.SUCCESS) {
showTip("初始化失敗,錯誤碼:" + code);
}
}
};
/**
* 更新詞典監聽器。
*/
private LexiconListener lexiconListener = new LexiconListener() {
@Override
public void onLexiconUpdated(String lexiconId, SpeechError error) {
if (error == null) {
showTip("詞典更新成功");
} else {
showTip("詞典更新失敗,錯誤碼:" + error.getErrorCode());
}
}
};
/**
* 構建語法監聽器。
*/
private GrammarListener grammarListener = new GrammarListener() {
@Override
public void onBuildFinish(String grammarId, SpeechError error) {
if (error == null) {
showTip("語法構建成功:" + grammarId);
} else {
showTip("語法構建失敗,錯誤碼:" + error.getErrorCode());
}
}
};
/**
* 識別監聽器。
*/
private RecognizerListener mRecognizerListener = new RecognizerListener() {
@Override
public void onVolumeChanged(int volume, byte[] data) {
showTip("當前正在說話,音量大小:" + volume);
Log.d(TAG, "返回音訊資料:" + data.length);
}
@Override
public void onResult(final RecognizerResult result, boolean isLast) {
if (null != result && !TextUtils.isEmpty(result.getResultString())) {
Log.d(TAG, "recognizer result:" + result.getResultString());
String text = "";
if (mResultType.equals("json")) {
text = JsonParser.parseGrammarResult(result.getResultString(), SpeechConstant.TYPE_LOCAL);
} else if (mResultType.equals("xml")) {
text = XmlParser.parseNluResult(result.getResultString());
}
// 顯示
((EditText) findViewById(R.id.isr_text)).setText(text);
} else {
Log.d(TAG, "recognizer result : null");
}
}
@Override
public void onEndOfSpeech() {
// 此回調錶示:檢測到了語音的尾端點,已經進入識別過程,不再接受語音輸入
showTip("結束說話");
}
@Override
public void onBeginOfSpeech() {
// 此回調錶示:sdk內部錄音機已經準備好了,使用者可以開始語音輸入
showTip("開始說話");
}
@Override
public void onError(SpeechError error) {
showTip("onError Code:" + error.getErrorCode());
}
@Override
public void onEvent(int i, int i1, int i2, Bundle bundle) {
}
};
private void showTip(final String str) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mToast.setText(str);
mToast.show();
}
});
}
/**
* 引數設定
*
* @param
* @return
*/
public void setParam() {
// 清空引數
mAsr.setParameter(SpeechConstant.PARAMS, null);
// 設定識別引擎
mAsr.setParameter(SpeechConstant.ENGINE_TYPE,SpeechConstant.TYPE_LOCAL);
// 設定本地識別資源
mAsr.setParameter(ResourceUtil.ASR_RES_PATH, getResourcePath());
// 設定語法構建路徑
mAsr.setParameter(ResourceUtil.GRM_BUILD_PATH, grmPath);
// 設定返回結果格式
mAsr.setParameter(SpeechConstant.RESULT_TYPE, mResultType);
// 設定本地識別使用語法id
mAsr.setParameter(SpeechConstant.LOCAL_GRAMMAR, "call");
// 設定識別的門限值
mAsr.setParameter(SpeechConstant.MIXED_THRESHOLD, "30");
// 設定音訊儲存路徑,儲存音訊格式支援pcm、wav,設定路徑為sd卡請注意WRITE_EXTERNAL_STORAGE許可權
// 注:AUDIO_FORMAT引數語記需要更新版本才能生效
mAsr.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");
mAsr.setParameter(SpeechConstant.ASR_AUDIO_PATH, Environment.getExternalStorageDirectory() + "/msc/asr.wav");
}
//獲取識別資源路徑
private String getResourcePath() {
StringBuffer tempBuffer = new StringBuffer();
//識別通用資源
tempBuffer.append(ResourceUtil.generateResourcePath(this, RESOURCE_TYPE.assets, "asr/common.jet"));
return tempBuffer.toString();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (null != mAsr) {
// 退出時釋放連線
mAsr.cancel();
mAsr.destroy();
}
}
private boolean buildGrammer() {
mLocalGrammar = FucUtil.readFile(this, "call.bnf", "utf-8");
// 本地-構建語法檔案,生成語法id
((EditText) findViewById(R.id.isr_text)).setText(mLocalGrammar);
mContent = new String(mLocalGrammar);
mAsr.setParameter(SpeechConstant.PARAMS, null);
// 設定文字編碼格式
mAsr.setParameter(SpeechConstant.TEXT_ENCODING, "utf-8");
// 設定引擎型別
mAsr.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_LOCAL);
// 設定語法構建路徑
mAsr.setParameter(ResourceUtil.GRM_BUILD_PATH, grmPath);
//使用8k音訊的時候請解開註釋
// mAsr.setParameter(SpeechConstant.SAMPLE_RATE, "8000");
// 設定資源路徑
mAsr.setParameter(ResourceUtil.ASR_RES_PATH, getResourcePath());
ret = mAsr.buildGrammar(GRAMMAR_TYPE_BNF, mContent, grammarListener);
if (ret != ErrorCode.SUCCESS) {
showTip("語法構建失敗,錯誤碼:" + ret);
}
else{
showTip("語法構建成功");
}
return true;
}
}
activity_off_line_test.xml程式碼:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:focusable="true"
android:focusableInTouchMode="true"
android:gravity="center_horizontal"
android:orientation="vertical"
android:padding="10dip" >
<include layout="@layout/title" />
<EditText
android:id="@+id/isr_text"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:gravity="top|left"
android:textSize="20sp" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dip"
android:layout_marginBottom="2dip"
android:gravity="center_horizontal"
android:orientation="horizontal" >
<Button
android:id="@+id/isr_recognize"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="開始識別"
android:textSize="20sp" />
<Button
android:id="@+id/isr_lexcion"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="更新詞典"
android:textSize="20sp"
android:enabled="true" />
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="2dip"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:layout_marginTop="2dip"
android:gravity="center_horizontal"
android:orientation="horizontal" >
<Button
android:id="@+id/isr_stop"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="停止錄音"
android:textSize="20sp" />
<Button
android:id="@+id/isr_cancel"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="取消"
android:textSize="20sp" />
</LinearLayout>
</LinearLayout>
word_info_editor.xml程式碼:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#B0C4DE"
android:orientation="vertical">
<TextView
android:layout_marginLeft="20dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="請編輯更新資訊:"