這幾天兩個舍友都買了iPhone 6S,玩起了「Hey, Siri」,我依舊對個人Nexus 5喊着「OK,Google」。但種種緣由,國內的「OK,Google」並不能展現出他的所有威力,因而上網搜索國內Android平臺的語音助手,我的以爲評價最好的是訊飛的——靈犀語音助手。其實訊飛語音雲平臺早就註冊過了,並下載了相應的SDK,只是沒仔細研究。今天忽然想好好學習一下,以方便之後集成到本身開發的APP中,也能夠方便你們參考。開發工具:Android Studio。
前端
好了,廢話就說這些。先來看效果圖:java
下面是具體的步驟。android
1,首先在訊飛開放平臺註冊開發者帳號,註冊流程很簡單,就不詳細介紹。網址:http://www.xfyun.cn/。而後就是像各大平臺同樣的步驟:新建Android應用獲取APPID—〉下載語音聽寫SDK。此處須要注意的是必定要新建本身的應用,別人的工程雖然能用,但不方便後續開發。json
2,解壓下載的SDK目錄,裏面有詳細的教程,可自行參考。而後新建工程,將MSC.jar(放入到libs文件夾下)和libmsc.so(放入到新建的jniLibs文件夾下)導入到本身的工程中(只有在線的全部功能,沒有提供離線服務。)另外,訊飛提供了兩種語音識別接口,一種是後臺進行語音檢測,沒有界面UI提示;另外一種是帶UI的接口,在錄音、播放音頻的時候,會有dialog彈出,並伴有相應的動畫,相對來講用戶交互體驗很不錯。若是使用帶UI接口時,請將assets下文件拷貝到項目中。這裏注意的是每一個SDK下載的assets可能不同(沒有親自測試過,由於recognize.xml打開亂碼),必定要將本身下載的SDK裏的assets目錄拷貝到XXX/src/main文件夾下。工程目錄以下:後端
3,在AndroidManifest.xml文件中添加權限:
數組
<!-- 在工程 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" /> <!-- 獲取當前wifi狀態 --> <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" />
4,佈局文件activity_main.xml網絡
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <EditText android:id="@+id/content_rec" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="識別內容" /> <Button android:id="@+id/bt_start" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:onClick="startRec" android:text="開始" /> <Button android:id="@+id/btn_read" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@+id/bt_start" android:layout_alignLeft="@+id/bt_start" android:layout_alignParentRight="true" android:onClick="read" android:text="朗讀" /> </RelativeLayout>
5,Java代碼:JsonParser.java 和 MainActivity.javaapp
(1),JsonParser.Java
ide
package com.xiaobailong24.xunfeiyun; import org.json.JSONArray; import org.json.JSONObject; import org.json.JSONTokener; /** * Json結果解析類 */ 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")); // 若是須要多候選結果,解析數組其餘字段 // for(int j = 0; j < items.length(); j++) // { // JSONObject obj = items.getJSONObject(j); // 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(); } }
(2),MainActivity.java函數
package com.xiaobailong24.xunfeiyun; import android.app.Activity; import android.os.Environment; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.EditText; import android.widget.Toast; import com.iflytek.cloud.ErrorCode; import com.iflytek.cloud.InitListener; 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.SpeechSynthesizer; import com.iflytek.cloud.SpeechUtility; import com.iflytek.cloud.SynthesizerListener; import com.iflytek.cloud.ui.RecognizerDialog; import com.iflytek.cloud.ui.RecognizerDialogListener; public class MainActivity extends Activity { private static String TAG = "MainActivity"; // 函數調用返回值 int ret = 0; // 語音聽寫對象 private SpeechRecognizer mIat; // 語音聽寫UI private RecognizerDialog iatDialog; // 聽寫結果內容 private EditText mResultText; // 語音合成對象 private SpeechSynthesizer mTts; // 默認發音人 private String voicer = "xiaoyan"; // 緩衝進度 private int mPercentForBuffering = 0; // 播放進度 private int mPercentForPlaying = 0; private Toast mToast; @Override public void onCreate(Bundle savedInstanceState) { Log.e(TAG, "onCreate"); super.onCreate(savedInstanceState); // this.requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); // 用於驗證應用的key,將XXXXXXXX改成你申請的APPID SpeechUtility.createUtility(MainActivity.this, SpeechConstant.APPID + "=XXXXXXXX"); // 建立語音聽寫對象 mIat = SpeechRecognizer.createRecognizer(this, mInitListener); // 初始化聽寫Dialog,若是隻使用有UI聽寫功能,無需建立SpeechRecognizer // 建立語音聽寫UI iatDialog = new RecognizerDialog(MainActivity.this, mInitListener); // 建立語音合成對象 mTts = SpeechSynthesizer.createSynthesizer(this, mInitListener); mToast = Toast.makeText(this, "", Toast.LENGTH_SHORT); content_rec)); } public void startRec(View view) { mResultText.setText(null); setParam(); boolean isShowDialog = true; if (isShowDialog) { // 顯示聽寫對話框 iatDialog.setListener(recognizerDialogListener); iatDialog.show(); // showTip("begin"); } else { // 不顯示聽寫對話框 ret = mIat.startListening(recognizerListener); if (ret != ErrorCode.SUCCESS) { // showTip("聽寫失敗,錯誤碼:" + ret); } else { // showTip("begin"); } } } public void read(View view) { String text = mResultText.getText().toString(); // 設置參數 setParam2(); //朗讀 int code = mTts.startSpeaking(text, mTtsListener); if (code != ErrorCode.SUCCESS) { if (code == ErrorCode.ERROR_COMPONENT_NOT_INSTALLED) { // 未安裝則跳轉到提示安裝頁面 } else { showTip("語音合成失敗,錯誤碼: " + code); } } } /** * 參數設置 * * @param * @return */ private void setParam2() { Log.e(TAG, "setParam2"); // 設置合成 mTts.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD); // 設置發音人 mTts.setParameter(SpeechConstant.VOICE_NAME, voicer); // 設置語速 mTts.setParameter(SpeechConstant.SPEED, "50"); // 設置音調 mTts.setParameter(SpeechConstant.PITCH, "50"); // 設置音量 mTts.setParameter(SpeechConstant.VOLUME, "50"); // 設置播放器音頻流類型 mTts.setParameter(SpeechConstant.STREAM_TYPE, "3"); } public void setParam() { Log.e(TAG, "setParam"); // 清空參數 mIat.setParameter(SpeechConstant.PARAMS, null); // 設置聽寫引擎 mIat.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD); // 設置語言 mIat.setParameter(SpeechConstant.LANGUAGE, "zh_cn"); // 設置語言區域 mIat.setParameter(SpeechConstant.ACCENT, "mandarin"); // 設置語音前端點 mIat.setParameter(SpeechConstant.VAD_BOS, "4000"); // 設置語音後端點 mIat.setParameter(SpeechConstant.VAD_EOS, "1000"); // 設置標點符號 1爲有標點 0爲沒標點 mIat.setParameter(SpeechConstant.ASR_PTT, "0"); // 設置音頻保存路徑 mIat.setParameter(SpeechConstant.ASR_AUDIO_PATH, Environment.getExternalStorageDirectory() + "/xiaobailong24/xunfeiyun"); } /** * 合成回調監聽。 */ private SynthesizerListener mTtsListener = new SynthesizerListener() { @Override public void onSpeakBegin() { Log.e(TAG, "mTtsListener-->onSpeakBegin"); showTip("開始播放"); } @Override public void onSpeakPaused() { Log.e(TAG, "mTtsListener-->onSpeakPaused"); showTip("暫停播放"); } @Override public void onSpeakResumed() { Log.e(TAG, "mTtsListener-->onSpeakResumed"); showTip("繼續播放"); } @Override public void onBufferProgress(int percent, int beginPos, int endPos, String info) { Log.e(TAG, "mTtsListener-->onBufferProgress"); mPercentForBuffering = percent; showTip(String.format(getString(R.string.tts_toast_format), mPercentForBuffering, mPercentForPlaying)); } @Override public void onSpeakProgress(int percent, int beginPos, int endPos) { Log.e(TAG, "mTtsListener-->onSpeakProgress"); mPercentForPlaying = percent; showTip(String.format(getString(R.string.tts_toast_format), mPercentForBuffering, mPercentForPlaying)); } @Override public void onCompleted(SpeechError error) { Log.e(TAG, "mTtsListener-->onCompleted"); if (error == null) { showTip("播放完成"); } else if (error != null) { showTip(error.getPlainDescription(true)); } } @Override public void onEvent(int eventType, int arg1, int arg2, Bundle obj) { Log.e(TAG, "mTtsListener-->onEvent"); } }; /** * 聽寫監聽器。 */ private RecognizerListener recognizerListener = new RecognizerListener() { @Override public void onVolumeChanged(int i, byte[] bytes) { Log.e(TAG, "recognizerListener-->onVolumeChanged"); showTip("當前正在說話,音量大小:" + i); } @Override public void onBeginOfSpeech() { Log.e(TAG, "recognizerListener-->onBeginOfSpeech"); showTip("開始說話"); } @Override public void onEndOfSpeech() { Log.e(TAG, "recognizerListener-->onEndOfSpeech"); showTip("結束說話"); } @Override public void onResult(RecognizerResult results, boolean isLast) { Log.e(TAG, "recognizerListener-->onResult"); String text = JsonParser.parseIatResult(results.getResultString()); mResultText.append(text); mResultText.setSelection(mResultText.length()); if (isLast) { // TODO 最後的結果 } } @Override public void onEvent(int eventType, int arg1, int arg2, Bundle obj) { Log.e(TAG, "recognizerListener-->onEvent"); } @Override public void onError(SpeechError arg0) { Log.e(TAG, "recognizerListener-->onError"); // TODO Auto-generated method stub } }; /** * 聽寫UI監聽器 */ private RecognizerDialogListener recognizerDialogListener = new RecognizerDialogListener() { public void onResult(RecognizerResult results, boolean isLast) { Log.e(TAG, "recognizerDialogListener-->onResult"); String text = JsonParser.parseIatResult(results.getResultString()); mResultText.append(text); mResultText.setSelection(mResultText.length()); } /** * 識別回調錯誤. */ public void onError(SpeechError error) { Log.e(TAG, "recognizerDialogListener-->onError"); showTip(error.getPlainDescription(true)); } }; private InitListener mInitListener = new InitListener() { @Override public void onInit(int code) { Log.e(TAG, "mInitListener-->onInit"); Log.d(TAG, "SpeechRecognizer init() code = " + code); if (code != ErrorCode.SUCCESS) { showTip("初始化失敗,錯誤碼:" + code); } } }; private void showTip(final String str) { Log.e(TAG, "showTip-->" + str); mToast.setText(str); mToast.show(); } @Override protected void onDestroy() { Log.e(TAG, "onDestroy"); super.onDestroy(); // 退出時釋放鏈接 mIat.cancel(); mIat.destroy(); } @Override protected void onResume() { Log.e(TAG, "onResume"); super.onResume(); } @Override protected void onPause() { Log.e(TAG, "onPause"); super.onPause(); } }